import 'dart:async';

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

///The [KwButtonFit] enum defines two possible values for the button fit:
/// *[expanded]: The button will expand to fill the available space.
/// *[shrinkWrap]: The button will wrap its content, taking up only as much space as needed.
enum KwButtonFit { expanded, shrinkWrap, circular }

class KwButton extends StatefulWidget {
  final String? label;
  final SvgGenImage? leftIcon;
  final SvgGenImage? rightIcon;
  final bool disabled;
  final Color color;
  final Color pressedColor;
  final Color disabledColor;
  final Color? textColors;
  final bool isOutlined;
  final VoidCallback onPressed;
  final KwButtonFit? fit;
  final double height;

  const KwButton._({
    required this.onPressed,
    required this.color,
    required this.isOutlined,
    required this.pressedColor,
    required this.disabledColor,
    this.disabled = false,
    this.label,
    this.leftIcon,
    this.rightIcon,
    this.textColors,
    this.height = 52,
    this.fit = KwButtonFit.expanded,
  }) : assert(label != null || leftIcon != null || rightIcon != null,
            'title or icon must be provided');

  /// Creates a standard dark button.
  const KwButton.primary({
    super.key,
    this.label,
    this.leftIcon,
    this.rightIcon,
    this.disabled = false,
    this.height = 52,
    this.fit = KwButtonFit.expanded,
    required this.onPressed,
  })  : color = AppColors.bgColorDark,
        pressedColor = AppColors.darkBgActiveButtonState,
        disabledColor = AppColors.grayDisable,
        textColors = Colors.white,
        isOutlined = false;

  /// Creates a white button.
  const KwButton.secondary({
    super.key,
    this.label,
    this.leftIcon,
    this.rightIcon,
    this.disabled = false,
    this.height = 52,
    this.fit = KwButtonFit.expanded,
    required this.onPressed,
  })  : color = Colors.white,
        pressedColor = AppColors.graySecondaryFrame,
        disabledColor = Colors.white,
        textColors = disabled ? AppColors.grayDisable : AppColors.blackBlack,
        isOutlined = false;

  /// Creates a yellow button.
  const KwButton.accent({
    super.key,
    this.label,
    this.leftIcon,
    this.rightIcon,
    this.disabled = false,
    this.height = 52,
    this.fit = KwButtonFit.expanded,
    required this.onPressed,
  })  : color = AppColors.primaryYellow,
        pressedColor = AppColors.darkBgActiveAccentButton,
        disabledColor = AppColors.navBarDisabled,
        textColors = disabled ? AppColors.darkBgInactive : AppColors.blackBlack,
        isOutlined = false;

  const KwButton.outlinedPrimary({
    super.key,
    this.label,
    this.leftIcon,
    this.rightIcon,
    this.disabled = false,
    this.height = 52,
    this.fit = KwButtonFit.expanded,
    required this.onPressed,
  })  : color = AppColors.bgColorDark,
        pressedColor = AppColors.darkBgActiveButtonState,
        disabledColor = AppColors.grayDisable,
        isOutlined = true,
        textColors = null;

  const KwButton.outlinedAccent({
    super.key,
    this.label,
    this.leftIcon,
    this.rightIcon,
    this.disabled = false,
    this.height = 52,
    this.fit = KwButtonFit.expanded,
    required this.onPressed,
  })  : color = AppColors.primaryYellow,
        pressedColor = AppColors.darkBgActiveAccentButton,
        disabledColor = AppColors.navBarDisabled,
        isOutlined = true,
        textColors = null;

  KwButton copyWith({
    String? label,
    SvgGenImage? icon,
    bool? disabled,
    Color? color,
    Color? pressedColor,
    Color? disabledColor,
    Color? textColors,
    bool? isOutlined,
    VoidCallback? onPressed,
    KwButtonFit? fit,
    double? height,
  }) {
    return KwButton._(
      label: label ?? this.label,
      leftIcon: icon ?? leftIcon,
      rightIcon: icon ?? rightIcon,
      disabled: disabled ?? this.disabled,
      color: color ?? this.color,
      pressedColor: pressedColor ?? this.pressedColor,
      disabledColor: disabledColor ?? this.disabledColor,
      textColors: textColors ?? this.textColors,
      isOutlined: isOutlined ?? this.isOutlined,
      onPressed: onPressed ?? this.onPressed,
      fit: fit ?? this.fit,
      height: height ?? this.height,
    );
  }

  @override
  State<KwButton> createState() => _KwButtonState();
}

class _KwButtonState extends State<KwButton> {
  bool pressed = false;
  Timer? _tapCancelTimer;

  @override
  Widget build(BuildContext context) {
    return widget.fit == KwButtonFit.shrinkWrap
        ? Row(children: [_buildButton(context)])
        : _buildButton(context);
  }

  Widget _buildButton(BuildContext context) {
    return AnimatedContainer(
      duration: const Duration(milliseconds: 200),
      height: widget.height,
      width: widget.fit == KwButtonFit.circular ? widget.height : null,
      decoration: BoxDecoration(
        color: _getColor(),
        border: _getBorder(),
        borderRadius: BorderRadius.circular(widget.height / 2),
      ),
      child: Material(
        color: Colors.transparent,
        child: InkWell(
          onTapDown: widget.disabled ? null : _onTapDown,
          onTapCancel: widget.disabled ? null : _onTapCancel,
          onTapUp: widget.disabled ? null : _onTapUp,
          borderRadius: BorderRadius.circular(widget.height / 2),
          highlightColor:
              widget.isOutlined ? Colors.transparent : widget.pressedColor,
          splashColor:
              widget.isOutlined ? Colors.transparent : widget.pressedColor,
          child: _buildButtonContent(context),
        ),
      ),
    );
  }

  Center _buildButtonContent(BuildContext context) {
    return Center(
      child: Row(
        mainAxisAlignment: MainAxisAlignment.center,
        children: [
          _buildHorizontalPadding(),
          if (widget.leftIcon != null)
            Center(
              child: widget.leftIcon!.svg(
                height: 16,
                width: 16,
                colorFilter: ColorFilter.mode(
                  _getTextColor(),
                  BlendMode.srcIn,
                ),
              ),
            ),
          if (widget.leftIcon != null && widget.label != null)
            const SizedBox(width: 4),
          if (widget.label != null)
            Text(
              widget.label!,
              style: AppTextStyles.bodyMediumMed.copyWith(
                color: _getTextColor(),
              ),
            ),
          if (widget.rightIcon != null && widget.label != null)
            const SizedBox(width: 4),
          if (widget.rightIcon != null)
            Center(
              child: widget.rightIcon!.svg(
                height: 16,
                width: 16,
                colorFilter: ColorFilter.mode(
                  _getTextColor(),
                  BlendMode.srcIn,
                ),
              ),
            ),
          _buildHorizontalPadding()
        ],
      ),
    );
  }

  Gap _buildHorizontalPadding() => Gap(
        widget.fit == KwButtonFit.circular ? 0 : (widget.height < 40 ? 12 : 20),
      );

  void _onTapDown(details) {
    setState(() {
      pressed = true;
    });
  }

  void _onTapCancel() {
    setState(() {
      pressed = false;
    });
  }

  void _onTapUp(details) {
    _tapCancelTimer?.cancel();
    _tapCancelTimer = Timer(
      const Duration(milliseconds: 50),
      _onTapCancel,
    );

    widget.onPressed();
  }

  Border? _getBorder() {
    return widget.isOutlined
        ? Border.all(
            color: widget.disabled
                ? widget.disabledColor
                : pressed
                    ? widget.pressedColor
                    : widget.color,
            width: 1,
          )
        : null;
  }

  Color _getColor() {
    return widget.isOutlined
        ? Colors.transparent
        : widget.disabled
            ? widget.disabledColor
            : widget.color;
  }

  Color _getTextColor() {
    return widget.textColors ??
        (pressed
            ? widget.pressedColor
            : widget.disabled
                ? widget.disabledColor
                : widget.color);
  }

  @override
  void dispose() {
    _tapCancelTimer?.cancel();
    super.dispose();
  }
}
