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

class KwPopUpButton extends StatefulWidget {
  final double height;
  final bool disabled;
  final bool withBorder;
  final KwPopupButtonColorPallet colorPallet;
  final double popUpPadding;
  final String label;
  final List<KwPopUpButtonItem> items;

  KwPopUpButton(
      {super.key,
      required this.label,
      required this.items,
      colorPallet,
      this.height = 52,
      this.withBorder = false,
      this.disabled = false,
      required this.popUpPadding})
      : colorPallet = colorPallet ?? KwPopupButtonColorPallet.dark();

  @override
  State<KwPopUpButton> createState() => _KwPopUpButtonState();
}

class _KwPopUpButtonState extends State<KwPopUpButton> {
  final _layerLink = LayerLink();
  double opacity = 0.0;
  final _KwButtonListenableOverlayPortalController _controller =
      _KwButtonListenableOverlayPortalController();

  @override
  void initState() {
    super.initState();
    _controller.addListener(() {
      setState(() {});
    });

    _controller.addOnHideListener(_hide);
    _controller.addOnShowListener(_show);
  }

  @override
  Widget build(BuildContext context) {
    return _buildButton(context);
  }

  Widget _buildButton(BuildContext context) {
    return _KwButtonPopUpOverlayMenu(
      opacity: opacity,
      controller: _controller,
      layerLink: _layerLink,
      popUpPadding: widget.popUpPadding,
      items: widget.items,
      child: CompositedTransformTarget(
        link: _layerLink,
        child: AnimatedContainer(
          duration: const Duration(milliseconds: 150),
          height: widget.height,
          decoration: BoxDecoration(
            color: _getBgColor(),
            border: _getBorder(),
            borderRadius: BorderRadius.circular(widget.height / 2),
          ),
          child: Material(
            color: Colors.transparent,
            child: InkWell(
              onTapDown: widget.disabled ? null : _onTapDown,
              borderRadius: BorderRadius.circular(widget.height / 2),
              highlightColor: widget.colorPallet.pressedBdColor,
              splashColor: widget.colorPallet.pressedBdColor,
              child: _buildButtonContent(context),
            ),
          ),
        ),
      ),
    );
  }

  _buildButtonContent(BuildContext context) {
    return Center(
      child: Row(
        children: [
          const Gap(52),
          Expanded(
            child: Center(
              child: Text(
                widget.label,
                style:
                    AppTextStyles.bodyMediumMed.copyWith(color: _getTextColor()),
              ),
            ),
          ),
          AnimatedContainer(
            duration: const Duration(milliseconds: 150),
            height: 52,
            width: 52,
            decoration: BoxDecoration(
              color: _getDropDownBgColor(),
              borderRadius: BorderRadius.only(
                topRight: Radius.circular(widget.height / 2),
                bottomRight: Radius.circular(widget.height / 2),
              ),
            ),
            child: AnimatedRotation(
              turns: opacity * 0.5,
              duration: const Duration(milliseconds: 150),
              child: Icon(
                Icons.keyboard_arrow_down_rounded,
                color: _getIconColor(),
              ),
            ),
          )
        ],
      ),
    );
  }

  void _onTapDown(details) {
    if (_controller.isShowing) {
      _controller.hide();
    } else {
      _controller.show();
    }
  }

  Future<void> _hide() async {
    setState(() {
      opacity = 0.0;
    });
    await Future.delayed(const Duration(milliseconds: 150), () {});
  }

  Future<void> _show() async {
    WidgetsBinding.instance.addPostFrameCallback((call) {
      setState(() {
        opacity = 1.0;
      });
    });
  }

  Border? _getBorder() {
    return widget.withBorder
        ? Border.all(
            color: widget.disabled
                ? widget.colorPallet.dropDownDisabledBgColor
                : _controller.isShowing
                    ? widget.colorPallet.dropDownPressedBgColor
                    : widget.colorPallet.dropDownBgColor,
            width: 1)
        : null;
  }

  Color _getDropDownBgColor() {
    return widget.disabled
        ? widget.colorPallet.dropDownDisabledBgColor
        : _controller.isShowing
            ? widget.colorPallet.dropDownPressedBgColor
            : widget.colorPallet.dropDownBgColor;
  }

  Color _getBgColor() {
    return widget.disabled
        ? widget.colorPallet.disabledBdColor
        : widget.colorPallet.bgColor;
  }

  Color _getTextColor() {
    return (_controller.isShowing
        ? widget.colorPallet.textPressedColor
        : widget.disabled
            ? widget.colorPallet.textDisabledColor
            : widget.colorPallet.textColor);
  }

  Color _getIconColor() {
    return (_controller.isShowing
        ? widget.colorPallet.iconPressedColor
        : widget.disabled
            ? widget.colorPallet.iconDisabledColor
            : widget.colorPallet.iconColor);
  }
}

class KwPopUpButtonItem {
  final String title;
  final VoidCallback onTap;
  final Color color;

  KwPopUpButtonItem(
      {required this.title,
      required this.onTap,
      this.color = AppColors.blackBlack});
}

class KwPopupButtonColorPallet {
  final Color textColor;
  final Color textPressedColor;
  final Color textDisabledColor;
  final Color bgColor;
  final Color pressedBdColor;
  final Color disabledBdColor;
  final Color iconColor;
  final Color iconPressedColor;
  final Color iconDisabledColor;
  final Color dropDownBgColor;
  final Color dropDownPressedBgColor;
  final Color dropDownDisabledBgColor;

  const KwPopupButtonColorPallet._(
      {required this.textColor,
      required this.textPressedColor,
      required this.textDisabledColor,
      required this.bgColor,
      required this.pressedBdColor,
      required this.disabledBdColor,
      required this.iconColor,
      required this.iconPressedColor,
      required this.iconDisabledColor,
      required this.dropDownBgColor,
      required this.dropDownPressedBgColor,
      required this.dropDownDisabledBgColor});

  factory KwPopupButtonColorPallet.dark() {
    return const KwPopupButtonColorPallet._(
      textColor: AppColors.grayWhite,
      textPressedColor: AppColors.grayWhite,
      textDisabledColor: AppColors.grayWhite,
      bgColor: AppColors.bgColorDark,
      pressedBdColor: AppColors.darkBgActiveButtonState,
      disabledBdColor: AppColors.grayDisable,
      iconColor: AppColors.grayWhite,
      iconPressedColor: AppColors.grayWhite,
      iconDisabledColor: AppColors.grayWhite,
      dropDownBgColor: AppColors.darkBgBgElements,
      dropDownPressedBgColor: AppColors.darkBgStroke,
      dropDownDisabledBgColor: AppColors.grayDisable,
    );
  }

  factory KwPopupButtonColorPallet.yellow() {
    return const KwPopupButtonColorPallet._(
      textColor: AppColors.blackBlack,
      textPressedColor: AppColors.blackBlack,
      textDisabledColor: AppColors.grayWhite,
      bgColor: AppColors.primaryYellow,
      pressedBdColor: AppColors.buttonPrimaryYellowActive,
      disabledBdColor: AppColors.grayDisable,
      iconColor: AppColors.blackBlack,
      iconPressedColor: AppColors.blackBlack,
      iconDisabledColor: AppColors.grayWhite,
      dropDownBgColor: AppColors.buttonPrimaryYellowDrop,
      dropDownPressedBgColor: AppColors.buttonPrimaryYellowActiveDrop,
      dropDownDisabledBgColor: AppColors.grayDisable,
    );
  }

  factory KwPopupButtonColorPallet.transparent() {
    return const KwPopupButtonColorPallet._(
      textColor: AppColors.blackBlack,
      textPressedColor: AppColors.blackBlack,
      textDisabledColor: AppColors.grayDisable,
      bgColor: Colors.transparent,
      pressedBdColor: Colors.transparent,
      disabledBdColor: Colors.transparent,
      iconColor: AppColors.blackBlack,
      iconPressedColor: AppColors.grayWhite,
      iconDisabledColor: AppColors.grayWhite,
      dropDownBgColor: AppColors.buttonOutline,
      dropDownPressedBgColor: AppColors.darkBgActiveButtonState,
      dropDownDisabledBgColor: AppColors.grayDisable,
    );
  }

  KwPopupButtonColorPallet copyWith({
    Color? textColor,
    Color? textPressedColor,
    Color? textDisabledColor,
    Color? bgColor,
    Color? pressedBdColor,
    Color? disabledBdColor,
    Color? iconColor,
    Color? iconPressedColor,
    Color? iconDisabledColor,
    Color? dropDownBgColor,
    Color? dropDownPressedBgColor,
    Color? dropDownDisabledBgColor,
  }) {
    return KwPopupButtonColorPallet._(
      textColor: textColor ?? this.textColor,
      textPressedColor: textPressedColor ?? this.textPressedColor,
      textDisabledColor: textDisabledColor ?? this.textDisabledColor,
      bgColor: bgColor ?? this.bgColor,
      pressedBdColor: pressedBdColor ?? this.pressedBdColor,
      disabledBdColor: disabledBdColor ?? this.disabledBdColor,
      iconColor: iconColor ?? this.iconColor,
      iconPressedColor: iconPressedColor ?? this.iconPressedColor,
      iconDisabledColor: iconDisabledColor ?? this.iconDisabledColor,
      dropDownBgColor: dropDownBgColor ?? this.dropDownBgColor,
      dropDownPressedBgColor:
          dropDownPressedBgColor ?? this.dropDownPressedBgColor,
      dropDownDisabledBgColor:
          dropDownDisabledBgColor ?? this.dropDownDisabledBgColor,
    );
  }
}

class _KwButtonPopUpOverlayMenu extends StatefulWidget {
  const _KwButtonPopUpOverlayMenu({
    required this.child,
    required this.controller,
    required this.opacity,
    required this.layerLink,
    required this.popUpPadding,
    required this.items,
  });

  final Widget child;
  final _KwButtonListenableOverlayPortalController controller;

  final double opacity;

  final LayerLink layerLink;

  final double popUpPadding;

  final List<KwPopUpButtonItem> items;

  @override
  State<_KwButtonPopUpOverlayMenu> createState() =>
      _KwButtonPopUpOverlayMenuState();
}

class _KwButtonPopUpOverlayMenuState extends State<_KwButtonPopUpOverlayMenu> {
  late final _KwButtonListenableOverlayPortalController _controller;

  @override
  void initState() {
    _controller = widget.controller;

    _controller.addListener(() {
      try {
        if (context.mounted) {
          setState(() {});
        }
      } catch (e) {
        print(e);
      }
    });
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return OverlayPortal(
      controller: _controller,
      overlayChildBuilder: (context) {
        return CompositedTransformFollower(
          followerAnchor: Alignment.bottomCenter,
          targetAnchor: Alignment.topCenter,
          offset: const Offset(0, -8),
          link: widget.layerLink,
          child: GestureDetector(
              onTap: () {
                _controller.hide();
              },
              child: Container(
                color: Colors.transparent,
                child: Padding(
                  padding:
                      EdgeInsets.symmetric(horizontal: widget.popUpPadding),
                  child: AnimatedOpacity(
                    duration: const Duration(milliseconds: 150),
                    opacity: widget.opacity,
                    child: Align(
                      alignment: Alignment.bottomCenter,
                      child: Container(
                        decoration: BoxDecoration(
                          color: AppColors.grayWhite,
                          borderRadius: BorderRadius.circular(24),
                          border: Border.all(
                              color: AppColors.grayTintStroke, width: 1),
                          boxShadow: [
                            BoxShadow(
                              color:
                                  Colors.black.withAlpha((255 * 0.07).toInt()),
                              offset: const Offset(0, 8),
                              blurRadius: 17,
                            ),
                            BoxShadow(
                              color:
                                  Colors.black.withAlpha((255 * 0.06).toInt()),
                              offset: const Offset(0, 30),
                              blurRadius: 30,
                            )
                          ],
                        ),
                        child: Column(
                          crossAxisAlignment: CrossAxisAlignment.stretch,
                          mainAxisSize: MainAxisSize.min,
                          children: widget.items
                              .expand((e) => [
                                    _buildItem(e.title, e.onTap, e.color),
                                    if (widget.items.last != e)
                                      const Divider(
                                        color: AppColors.grayTintStroke,
                                        height: 0,
                                      ),
                                  ])
                              .toList(),
                        ),
                      ),
                    ),
                  ),
                ),
              )),
        );
      },
      child: widget.child,
    );
  }

  Widget _buildItem(String title, VoidCallback onTap, Color color) {
    return GestureDetector(
      onTap: () {
        onTap();
        _controller.hide();
      },
      child: Container(
        height: 52,
        color: Colors.transparent,
        child: Center(
          child: Text(
            title,
            style: AppTextStyles.bodyMediumMed.copyWith(color: color),
          ),
        ),
      ),
    );
  }

  @override
  void dispose() {
    if (context.mounted) _controller.hide();
    super.dispose();
  }
}

class _KwButtonListenableOverlayPortalController
    extends OverlayPortalController {
  List<VoidCallback> listeners = [];
  Future<void> Function()? onShow;
  Future<void> Function()? onHide;

  _KwButtonListenableOverlayPortalController();

  addOnShowListener(Future<void> Function() listener) {
    onShow = listener;
  }

  addOnHideListener(Future<void> Function() listener) {
    onHide = listener;
  }

  @override
  void show() async {
    super.show();
    try {
      for (var element in listeners) {
        element();
      }
    } catch (e) {
      if (kDebugMode) {
        print(e);
      }
    }

    if (onShow != null) {
      await onShow!();
    }
  }

  @override
  void hide() async {
    if (onHide != null) {
      await onHide!();
    }
    try {
      super.hide();
    } catch (e) {
      if (kDebugMode) {
        print(e);
      }
    }
    for (var element in listeners) {
      try {
        element();
      } catch (e) {
        if (kDebugMode) {
          print(e);
        }
      }
    }
  }

  void addListener(VoidCallback listener) {
    listeners.add(listener);
  }
}
