// Copyright (C) 2023 WYATT GROUP
// Please see the AUTHORS file for details.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.

import 'package:flutter/material.dart' hide ButtonStyle;
import 'package:flutter/services.dart';
import 'package:gap/gap.dart';
import 'package:wyatt_bloc_helper/wyatt_bloc_helper.dart';
import 'package:wyatt_ui_components/wyatt_ui_components.dart';
import 'package:wyatt_ui_kit/src/components/buttons/cubit/button_cubit.dart';
import 'package:wyatt_ui_kit/src/components/buttons/cubit/invalid_button_cubit.dart';
import 'package:wyatt_ui_kit/src/components/buttons/cubit/state_listener.dart';
import 'package:wyatt_ui_kit/src/components/buttons/file_selection_button/dotter_border_child.dart';
import 'package:wyatt_ui_kit/src/components/buttons/file_selection_button/file_selection_button_theme_resolver.dart';
import 'package:wyatt_ui_kit/src/components/gradients/gradient_text.dart';

class FileSelectionButtonScreen
    extends CubitScreen<InvalidButtonCubit, ButtonState> {
  const FileSelectionButtonScreen({
    this.leading,
    this.title,
    this.subTitle,
    this.disabledStyle,
    this.normalStyle,
    this.hoveredStyle,
    this.focusedStyle,
    this.tappedStyle,
    this.selectedStyle,
    this.invalidStyle,
    this.onPressed,
    this.disabled,
    this.mainAxisSize,
    this.themeResolver,
    super.key,
  });

  final Widget? leading;
  final TextWrapper? title;
  final TextWrapper? subTitle;
  final MainAxisSize? mainAxisSize;

  final FileSelectionButtonStyle? disabledStyle;
  final FileSelectionButtonStyle? normalStyle;
  final FileSelectionButtonStyle? hoveredStyle;
  final FileSelectionButtonStyle? focusedStyle;
  final FileSelectionButtonStyle? tappedStyle;
  final FileSelectionButtonStyle? selectedStyle;
  final FileSelectionButtonStyle? invalidStyle;

  final void Function(ControlState state)? onPressed;
  final ValueNotifier<bool>? disabled;
  final FileSelectionButtonThemeResolver? themeResolver;

  @override
  InvalidButtonCubit create(BuildContext context) => InvalidButtonCubit();

  @override
  InvalidButtonCubit init(BuildContext context, InvalidButtonCubit bloc) {
    disabled?.addListener(
      () => StateListener.listen<InvalidButtonCubit>(disabled, bloc),
    );

    /// Set the initial state depending on the disabled value
    /// after adding the listener.
    if (disabled?.value ?? false) {
      bloc.disable();
    }
    return bloc;
  }

  /// Negotiate the theme to get a complete style.
  FileSelectionButtonStyle _resolve(BuildContext context, ButtonState state) {
    final FileSelectionButtonThemeResolver resolver = themeResolver ??
        FileSelectionButtonThemeResolver(
          customStyleFn: (context, {extra}) {
            FileSelectionButtonStyle? style;
            switch (extra?.state) {
              case ControlState.disabled:
                style = disabledStyle;
                break;
              case ControlState.focused:
                style = focusedStyle;
                break;
              case ControlState.hovered:
                style = hoveredStyle;
                break;
              case ControlState.tapped:
                style = tappedStyle;
                break;
              case ControlState.normal:
              case null:
                style = normalStyle;
                break;
            }
            if (extra?.isSelected ?? false) {
              style = selectedStyle;
            }
            if (extra?.isInvalid ?? false) {
              style = invalidStyle;
            }

            return style;
          },
        );
    return resolver.negotiate(context, extra: state);
  }

  @override
  Widget onBuild(BuildContext context, ButtonState state) {
    final style = _resolve(context, state);

    return Focus(
      onFocusChange: (hasFocus) =>
          hasFocus ? bloc(context).onFocus() : bloc(context).onUnfocus(),
      onKeyEvent: (focusNode, event) {
        if (event.logicalKey == LogicalKeyboardKey.enter && state.isFocused) {
          onPressed?.call(state.state);
          bloc(context).onClickUpOut();
          return KeyEventResult.handled;
        }
        return KeyEventResult.ignored;
      },
      child: MouseRegion(
        cursor: SystemMouseCursors.click,
        onEnter: (event) {
          bloc(context).onMouseEnter();
        },
        onExit: (event) {
          bloc(context).onMouseLeave();
        },
        child: GestureDetector(
          onTapDown: (details) {
            bloc(context).onClickDown();
          },
          onTapUp: (details) {
            onPressed?.call(state.state);
            bloc(context).onClickUpIn();
          },
          onTapCancel: () {
            onPressed?.call(state.state);
            bloc(context).onClickUpOut();
          },
          child: DotterBorderChild(
            style: style,
            child: DecoratedBox(
              decoration: BoxDecoration(
                color: style.backgroundColors?.color,
                // if no gradient colors => no default value
                gradient: (style.backgroundColors?.isGradient ?? false)
                    ? LinearGradient(
                        colors: style.backgroundColors!.colors,
                      )
                    : null,
                boxShadow: [
                  if (style.shadow != null) ...[style.shadow!]
                ],
                borderRadius: style.radius,
              ),
              child: ConstrainedBox(
                constraints: const BoxConstraints(
                  minWidth: 200,
                  minHeight: 50,
                ), // min sizes for Material buttons
                child: Padding(
                  padding: style.padding ?? EdgeInsets.zero,
                  child: Row(
                    mainAxisSize: mainAxisSize ?? MainAxisSize.min,
                    children: [
                      if (leading != null) ...[
                        leading ?? const SizedBox.shrink(),
                        Gap((style.padding?.horizontal ?? 10) / 2),
                      ],
                      Column(
                        mainAxisAlignment: MainAxisAlignment.spaceBetween,
                        crossAxisAlignment: CrossAxisAlignment.start,
                        children: [
                          /// Choose color
                          /// title.style.color ??
                          ///  buttonStyle.title.style.color ??
                          ///    context.textTheme.titleLarge.color
                          ///
                          /// Choose gradient
                          /// title.gradient ??
                          ///  buttonStyle.foregroundColor.colors ??
                          ///    null
                          ///
                          /// More infos in `ThemeResolver` class
                          if (title != null) ...[
                            Text(
                              title!.data,
                              style: title!.style ?? style.title,
                              textAlign: title!.textAlign,
                              textDirection: title!.textDirection,
                              softWrap: title!.softWrap,
                              overflow: title!.overflow,
                              maxLines: title!.maxLines,
                              selectionColor: title!.selectionColor,
                            ).toGradient(
                              gradientColors: style.foregroundColors,
                            ),
                          ],

                          /// Choose color
                          /// subTitle.style.color ??
                          ///  buttonStyle.subTitle.style.color ??
                          ///    context.textTheme.subTitleLarge.color
                          ///
                          /// Choose gradient
                          /// subTitle.gradient ??
                          ///  buttonStyle.foregroundColor.colors ??
                          ///    null
                          ///
                          /// More infos in `ThemeResolver` class
                          if (subTitle != null) ...[
                            const Gap(5),
                            Text(
                              subTitle!.data,
                              style: subTitle!.style ?? style.subTitle,
                              textAlign: title!.textAlign,
                              textDirection: title!.textDirection,
                              softWrap: title!.softWrap,
                              overflow: title!.overflow,
                              maxLines: title!.maxLines,
                              selectionColor: title!.selectionColor,
                            ).toGradient(
                              gradientColors: style.foregroundColors,
                            ),
                          ],
                        ],
                      ),
                    ],
                  ),
                ),
              ),
            ),
          ),
        ),
      ),
    );
  }
}
