import 'package:flutter/material.dart';
import 'package:krow/core/presentation/styles/kw_text_styles.dart';
import 'package:krow/core/presentation/styles/theme.dart';

class KwTabBar extends StatefulWidget {
  final List<String> tabs;
  final void Function(int index) onTap;
  final List<int>? flexes;
  final bool forceScroll;

  const KwTabBar(
      {super.key,
        required this.tabs,
        required this.onTap,
        this.flexes,
        this.forceScroll = false});

  @override
  State<KwTabBar> createState() => _KwTabBarState();
}

class _KwTabBarState extends State<KwTabBar>
    with SingleTickerProviderStateMixin {
  var keyMaps = <int, GlobalKey>{};
  var tabPadding = 4.0;
  int _selectedIndex = 0;
  late AnimationController _controller;
  late Animation<double> _animation;
  late ScrollController _horScrollController;

  @override
  void initState() {
    super.initState();
    _horScrollController = ScrollController();
    _controller = AnimationController(
      duration: const Duration(milliseconds: 200),
      vsync: this,
    );
    _animation = Tween<double>(begin: 0, end: 0).animate(_controller);
  }

  @override
  dispose() {
    _controller.dispose();
    _horScrollController.dispose();
    _animation.removeListener(() {});
    super.dispose();
  }

  void _setSelectedIndex(int index) {
    if (_horScrollController.hasClients) {
      _scrollToSelected(index);
    }

    setState(() {
      _selectedIndex = index;
      _animation = Tween<double>(
        begin: _animation.value,
        end: index.toDouble(),
      ).animate(CurvedAnimation(
        parent: _controller,
        curve: Curves.easeInOut,
      ));
      _controller.forward(from: 0);
    });

    widget.onTap(index);
  }

  @override
  Widget build(BuildContext context) {
    return LayoutBuilder(
      builder: (context, constraints) {
        double totalWidth = widget.tabs
            .fold(0, (sum, tab) => sum + _calculateTabWidth(tab, 0, context));

        totalWidth += (widget.tabs.length) * tabPadding + 26; //who is 26?
        bool needScroll = widget.forceScroll ||
            widget.flexes == null ||
            totalWidth > constraints.maxWidth;
        return _buildTabsRow(context, needScroll, constraints.maxWidth);
      },
    );
  }

  Widget _buildTabsRow(BuildContext context, bool needScroll, maxWidth) {
    return SizedBox(
      width: maxWidth,
      child: needScroll
          ? SingleChildScrollView(
        physics: const BouncingScrollPhysics(),
        controller: _horScrollController,
        scrollDirection: Axis.horizontal,
        child: Stack(
          children: [
            _buildAnimatedUnderline(false),
            _buildRow(
              context,
            ),
          ],
        ),
      )
          : Stack(
        children: [
          _buildAnimatedUnderline(true),
          _buildRow(context, fixedWidth: true),
        ],
      ),
    );
  }

  Widget _buildRow(BuildContext context, {bool fixedWidth = false}) {
    return Padding(
      padding: const EdgeInsets.only(left: 16, right: 16),
      child: Row(
        mainAxisAlignment: MainAxisAlignment.spaceBetween,
        children: widget.tabs
            .asMap()
            .map((index, tab) => MapEntry(
          index,
          _buildSingleTab(index, tab, context, fixedWidth: fixedWidth),
        ))
            .values
            .toList(),
      ),
    );
  }

  Widget _buildSingleTab(int index, String tab, BuildContext context,
      {required bool fixedWidth}) {
    double? itemWidth;

    var d = (MediaQuery.of(context).size.width -
        (tabPadding * widget.tabs.length) -
        32);

    if (widget.flexes != null) {
      itemWidth = d *
          (widget.flexes?[index] ?? 1) /
          (widget.flexes?.reduce((a, b) => a + b) ?? 1);
    } else {
      itemWidth = (d / (widget.tabs.length));
    }
    if (keyMaps[index] == null) {
      keyMaps[index] = GlobalKey();
    }

    return GestureDetector(
      key: keyMaps[index],
      onTap: () {
        _setSelectedIndex(index);
      },
      child: AnimatedContainer(
        duration: const Duration(milliseconds: 200),
        decoration: BoxDecoration(
          borderRadius: BorderRadius.circular(23),
          color: Colors.transparent,
          border: Border.all(
            color: _selectedIndex != index
                ? AppColors.grayStroke
                : Colors.transparent,
            width: 1,
          ),
        ),
        padding: const EdgeInsets.symmetric(horizontal: 18),
        margin: EdgeInsets.only(right: tabPadding),
        height: 46,
        width: fixedWidth ? itemWidth : null,
        alignment: Alignment.center,
        child: AnimatedDefaultTextStyle(
          duration: const Duration(milliseconds: 200),
          style: _selectedIndex == index
              ? AppTextStyles.bodySmallReg.copyWith(color: AppColors.grayWhite)
              : AppTextStyles.bodySmallMed.copyWith(color: AppColors.blackGray),
          child: Text(tab),
        ),
      ),
    );
  }

  Widget _buildAnimatedUnderline(bool fixedWidth) {
    double? tabWidth;

    var d = (MediaQuery.of(context).size.width -
        (tabPadding * widget.tabs.length) -
        32);

    if (!fixedWidth) {
      tabWidth = null;
    } else if (widget.flexes != null) {
      tabWidth = d *
          (widget.flexes?[_selectedIndex] ?? 1) /
          (widget.flexes?.reduce((a, b) => a + b) ?? 1);
    } else {
      tabWidth = (d / (widget.tabs.length));
    }

    var content = AnimatedContainer(
      duration: const Duration(milliseconds: 200),
      width: tabWidth ??
          _calculateTabWidth(
              widget.tabs[_selectedIndex], _selectedIndex, context),
      height: 46,
      decoration: BoxDecoration(
        color: AppColors.bgColorDark,
        borderRadius: BorderRadius.circular(23),
      ),
    );

    return fixedWidth && widget.flexes == null
        ? AnimatedBuilder(
      animation: _animation,
      builder: (context, child) {
        return Padding(
          padding: const EdgeInsets.only(left: 16, right: 16),
          child: Align(
            alignment: Alignment(
              (_animation.value * 2 / (widget.tabs.length - 1)) - 1,
              1,
            ),
            child: content,
          ),
        );
      },
    )
        : animatedPadding(content);
  }

  AnimatedPadding animatedPadding(AnimatedContainer content) {
    return AnimatedPadding(
      curve: Curves.easeIn,
      padding: EdgeInsets.only(left: calcTabOffset(_selectedIndex)),
      duration: const Duration(milliseconds: 250),
      child: content,
    );
  }

  double _calculateTabWidth(String tab, int index, BuildContext context) {
    final textPainter = TextPainter(
      text: TextSpan(
        text: tab,
        style: _selectedIndex == index
            ? AppTextStyles.bodySmallReg
            : AppTextStyles.bodySmallMed,
      ),
      maxLines: 1,
      textDirection: TextDirection.ltr,
    )..layout();

    return textPainter.width + 36; // 36?
  }

  double calcTabOffset(index) {
    var scrollOffset =
    _horScrollController.hasClients ? _horScrollController.offset : 0.0;
    final keyContext = keyMaps[index]?.currentContext;
    if (keyContext != null) {
      final box = keyContext.findRenderObject() as RenderBox;
      return (box.localToGlobal(Offset.zero).dx + scrollOffset)
          .clamp(0, double.infinity);
    } else {
      return 0;
    }
  }

  void _scrollToSelected(int index) {
    print(index);
    double offset = 0;
    double tabWidth = _calculateTabWidth(widget.tabs[index], index, context);
    double screenWidth = MediaQuery.of(context).size.width;

    offset = calcTabOffset(index);

    double maxScrollExtent = _horScrollController.position.maxScrollExtent;
    double targetOffset = offset - (screenWidth - tabWidth) / 2;

    if (targetOffset < 0) {
      targetOffset = 0;
    } else if (targetOffset > maxScrollExtent) {
      targetOffset = maxScrollExtent;
    }

    _horScrollController.animateTo(
      targetOffset,
      duration: const Duration(milliseconds: 200),
      curve: Curves.easeInOut,
    );
  }
}
