import 'package:calculator_widget/animated_button.dart';
import 'package:calculator_widget/calculator_model.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:translations/app_localizations.dart';

enum ButtonType { number, operation, clear }

const double _buttonsSpacing = 5;

class CalculatorWidget extends StatelessWidget {
  const CalculatorWidget({super.key});

  @override
  Widget build(BuildContext context) =>
      ProviderScope(child: _CalculatorWidget());
}

class _CalculatorWidget extends ConsumerWidget {
  final FocusNode focusKeyboard = FocusNode();

  _CalculatorWidget();

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    return Shortcuts(
      shortcuts: <LogicalKeySet, Intent>{
        LogicalKeySet(LogicalKeyboardKey.control, LogicalKeyboardKey.keyV):
            const ActivateIntent(),
      },
      child: Actions(
        actions: <Type, Action<Intent>>{
          ActivateIntent: CallbackAction<ActivateIntent>(
            onInvoke: (ActivateIntent intent) {
              Clipboard.getData(Clipboard.kTextPlain).then((value) {
                if (value != null) {
                  final clipboardContent = value.text;
                  if (clipboardContent != null &&
                      clipboardContent.length < 30) {
                    ref
                        .read(Calculator.provider.notifier)
                        .submitString(clipboardContent);
                  }
                }
              });
              return null;
            },
          ),
        },
        child: SafeArea(
          child: SizedBox(
            height: 480,
            child: Builder(
              builder: (context) {
                focusKeyboard.requestFocus();
                return KeyboardListener(
                  focusNode: focusKeyboard,
                  onKeyEvent: (KeyEvent event) {
                    if (event.runtimeType.toString() == 'KeyDownEvent') {
                      switch (event.logicalKey) {
                        case LogicalKeyboardKey.backspace:
                          ref
                              .read(Calculator.provider.notifier)
                              .adaptiveDeleteClear();
                        case LogicalKeyboardKey.delete:
                          ref.read(Calculator.provider.notifier).clearAll();
                        case LogicalKeyboardKey.enter:
                          ref
                              .read(Calculator.provider.notifier)
                              .submitChar('=');
                        default:
                          ref
                              .read(Calculator.provider.notifier)
                              .submitChar(event.character ?? '');
                      }
                    }
                  },
                  child: Column(
                    children: <Widget>[
                      Expanded(
                        flex: 3,
                        child: Container(
                          decoration: BoxDecoration(
                            color: Theme.of(context).colorScheme.surface,
                            borderRadius: const BorderRadius.all(
                              Radius.circular(30),
                            ),
                          ),
                          child: Column(
                            children: [
                              // handle
                              Center(
                                child: Padding(
                                  padding: const EdgeInsets.symmetric(
                                    vertical: 8,
                                  ),
                                  child: Container(
                                    width: 32,
                                    height: 4,
                                    decoration: BoxDecoration(
                                      color: Theme.of(context)
                                          .colorScheme
                                          .onSurfaceVariant
                                          .withValues(alpha: 0.4),
                                      borderRadius: BorderRadius.circular(2),
                                    ),
                                  ),
                                ),
                              ),
                              const Expanded(child: CalculatorHeader()),
                            ],
                          ),
                        ),
                      ),
                      const Expanded(flex: 7, child: CalculatorNumpad()),
                    ],
                  ),
                );
              },
            ),
          ),
        ),
      ),
    );
  }
}

class CalculatorHeader extends ConsumerWidget {
  const CalculatorHeader({super.key});

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    final text = ref.watch(Calculator.provider);
    final previewText = ref.watch(previewResultProvider);
    final operation = ref.watch(selectedOperationProvider);

    return Row(
      mainAxisAlignment: MainAxisAlignment.spaceBetween,
      children: <Widget>[
        Expanded(
          child: Padding(
            padding: const EdgeInsets.symmetric(horizontal: 10),
            child: Column(
              mainAxisAlignment: MainAxisAlignment.center,
              crossAxisAlignment: CrossAxisAlignment.start,
              children: [
                SelectableText(
                  text,
                  style: TextStyle(
                    fontSize: 45,
                    fontWeight: FontWeight.bold,
                    color: Theme.of(context).colorScheme.onSurface,
                  ),
                  maxLines: 1,
                  textScaler: TextScaler.noScaling,
                  scrollPhysics: const ClampingScrollPhysics(),
                ),
                if (previewText.isNotEmpty)
                  SelectableText(
                    previewText,
                    style: TextStyle(
                      fontSize: 20,
                      fontWeight: FontWeight.normal,
                      color: Theme.of(
                        context,
                      ).colorScheme.onSurface.withValues(alpha: 0.5),
                    ),
                    maxLines: 1,
                    textScaler: TextScaler.noScaling,
                    scrollPhysics: const ClampingScrollPhysics(),
                  ),
              ],
            ),
          ),
        ),
        SizedBox(
          width: 50,
          child: Center(
            child: ref.watch(isResultProvider)
                ? IconButton(
                    tooltip: AppLocalizations.of(context)?.copy,
                    icon: Icon(
                      Icons.content_copy_outlined,
                      color: Theme.of(context).colorScheme.onSurface,
                    ),
                    onPressed: () {
                      Clipboard.setData(ClipboardData(text: text));
                      HapticFeedback.heavyImpact();
                    },
                  )
                : text.isEmpty
                ? IconButton(
                    tooltip: AppLocalizations.of(context)?.paste,
                    icon: Icon(
                      Icons.content_paste_outlined,
                      color: Theme.of(context).colorScheme.onSurface,
                    ),
                    onPressed: () {
                      Clipboard.getData(Clipboard.kTextPlain).then((value) {
                        final cliboard = value?.text;
                        if (cliboard != null) {
                          ref
                              .watch(Calculator.provider.notifier)
                              .submitString(cliboard);
                        }
                      });
                      HapticFeedback.heavyImpact();
                    },
                  )
                : Text(
                    operation != null ? operation.toString() : '',
                    style: TextStyle(
                      fontSize: 45.0,
                      fontWeight: FontWeight.bold,
                      color: Theme.of(context).colorScheme.onSurface,
                    ),
                    textScaler: TextScaler.noScaling,
                    maxLines: 1,
                  ),
          ),
        ),
      ],
    );
  }
}

class CalculatorNumpad extends ConsumerWidget {
  const CalculatorNumpad({super.key});

  static const double breakPoint1 = 500;
  static const double breakPoint2 = 610;
  static const decimalSeparator = '.';

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    final calcWidth = MediaQuery.sizeOf(context).width;

    return Padding(
      padding: const EdgeInsets.all(_buttonsSpacing),
      child: Row(
        children: <Widget>[
          if (calcWidth > breakPoint2)
            Column(
              children: <Widget>[
                CalculatorButton(
                  text: 'x²',
                  buttonType: ButtonType.operation,
                  onPressed: () {
                    ref.read(Calculator.provider.notifier).square();
                  },
                ),
                CalculatorButton(
                  text: 'ln',
                  buttonType: ButtonType.operation,
                  onPressed: () {
                    ref.read(Calculator.provider.notifier).ln();
                  },
                ),
                CalculatorButton(
                  text: 'n!',
                  buttonType: ButtonType.operation,
                  onPressed: () {
                    ref.read(Calculator.provider.notifier).factorial();
                  },
                ),
                CalculatorButton(
                  text: '1/x',
                  buttonType: ButtonType.operation,
                  onPressed: () {
                    ref.read(Calculator.provider.notifier).reciprocal();
                  },
                ),
              ].map((e) => Expanded(child: e)).toList(),
            ),
          if (calcWidth > breakPoint1)
            Column(
              children: <Widget>[
                CalculatorButton(
                  text: '%',
                  buttonType: ButtonType.operation,
                  onPressed: ref.read(Calculator.provider.notifier).percentage,
                ),
                CalculatorButton(
                  text: '√',
                  buttonType: ButtonType.operation,
                  onPressed: () {
                    ref.read(Calculator.provider.notifier).squareRoot();
                  },
                ),
                CalculatorButton(
                  text: 'log',
                  buttonType: ButtonType.operation,
                  onPressed: () {
                    ref.read(Calculator.provider.notifier).log10();
                  },
                ),
                CalculatorButton(
                  text: 'π',
                  buttonType: ButtonType.operation,
                  onPressed: () {
                    ref.read(Calculator.provider.notifier).submitChar('π');
                  },
                ),
              ].map((e) => Expanded(child: e)).toList(),
            ),
          ...List.generate(
            3,
            (columnIndex) => Column(
              children: [
                ...List.generate(3, (rowIndex) {
                  final char = (7 - 3 * rowIndex + columnIndex).toString();
                  return CalculatorButton(
                    text: char,
                    buttonType: ButtonType.number,
                    onPressed: () {
                      ref.read(Calculator.provider.notifier).submitChar(char);
                    },
                  );
                }),
                if (columnIndex == 0)
                  CalculatorButton(
                    text: decimalSeparator,
                    buttonType: ButtonType.operation,
                    onPressed: () {
                      ref
                          .read(Calculator.provider.notifier)
                          .submitChar(decimalSeparator);
                    },
                  )
                else if (columnIndex == 1)
                  CalculatorButton(
                    text: '0',
                    buttonType: ButtonType.number,
                    onPressed: () {
                      ref.read(Calculator.provider.notifier).submitChar('0');
                    },
                  )
                else if (columnIndex == 2)
                  CalculatorButton(
                    text: '=',
                    buttonType: ButtonType.operation,
                    onPressed: () {
                      ref.read(Calculator.provider.notifier).submitChar('=');
                    },
                  ),
              ].map((e) => Expanded(child: e)).toList(),
            ),
          ),
          Column(
            children: <Widget>[
              CalculatorButton(
                text: ref.read(endNumberProvider) ? 'AC' : '←',
                buttonType: ButtonType.clear,
                onPressed: () {
                  ref.read(Calculator.provider.notifier).adaptiveDeleteClear();
                },
                onLongPress: () {
                  ref.read(Calculator.provider.notifier).clearAll();
                },
              ),
              CalculatorButton(
                text: '÷',
                buttonType: ButtonType.operation,
                onPressed: () {
                  ref.read(Calculator.provider.notifier).submitChar('/');
                },
              ),
              CalculatorButton(
                text: '×',
                buttonType: ButtonType.operation,
                onPressed: () {
                  ref.read(Calculator.provider.notifier).submitChar('*');
                },
              ),
              CalculatorButton(
                text: '−',
                buttonType: ButtonType.operation,
                onPressed: () {
                  ref.read(Calculator.provider.notifier).submitChar('-');
                },
              ),
              CalculatorButton(
                text: '+',
                buttonType: ButtonType.operation,
                onPressed: () {
                  ref.read(Calculator.provider.notifier).submitChar('+');
                },
              ),
            ].map((e) => Expanded(child: e)).toList(),
          ),
        ].map((e) => Expanded(child: e)).toList(),
      ),
    );
  }
}

class CalculatorButton extends StatelessWidget {
  final String? text;
  final void Function()? onPressed;
  final void Function()? onLongPress;
  final ButtonType buttonType;

  const CalculatorButton({
    super.key,
    this.text,
    this.onLongPress,
    this.onPressed,
    required this.buttonType,
  });

  @override
  Widget build(BuildContext context) {
    final foregroundColor = switch (buttonType) {
      ButtonType.number => Theme.of(context).colorScheme.onPrimaryContainer,
      ButtonType.operation => Theme.of(
        context,
      ).colorScheme.onSecondaryContainer,
      ButtonType.clear => Theme.of(context).colorScheme.onTertiaryContainer,
    };

    final backgroundColor = switch (buttonType) {
      ButtonType.number => Theme.of(context).colorScheme.primaryContainer,
      ButtonType.operation => Theme.of(context).colorScheme.secondaryContainer,
      ButtonType.clear => Theme.of(context).colorScheme.tertiaryContainer,
    };

    return Padding(
      padding: const EdgeInsets.all(_buttonsSpacing),
      child: AnimatedButton(
        initialRadius: 60,
        finalRadius: 20,
        foregroundColor: foregroundColor,
        backgroundColor: backgroundColor,
        onPressed: () {
          if (onPressed != null) {
            HapticFeedback.heavyImpact();
            onPressed!();
          }
        },
        onLongPress: () {
          if (onLongPress != null) {
            HapticFeedback.heavyImpact();
            onLongPress!();
          }
        },
        child: SizedBox.expand(
          child: Center(
            child: text == "←"
                ? const Icon(Icons.backspace_outlined)
                : Text(
                    text ?? '',
                    style: const TextStyle(fontSize: 27),
                    maxLines: 1,
                    textScaler: TextScaler.noScaling,
                  ),
          ),
        ),
      ),
    );
  }
}
