import 'dart:async';

import 'package:flutter/services.dart';
import 'package:flutter/widgets.dart';

/// 다이얼로그에서 ESC/Enter 키를 처리하고 포커스를 트랩하는 래퍼 위젯.
class DialogKeyboardShortcuts extends StatefulWidget {
  const DialogKeyboardShortcuts({
    super.key,
    required this.child,
    this.onEscape,
    this.onSubmit,
    this.enableFocusTrap = true,
  });

  final Widget child;
  final VoidCallback? onEscape;
  final FutureOr<void> Function()? onSubmit;
  final bool enableFocusTrap;

  @override
  State<DialogKeyboardShortcuts> createState() =>
      _DialogKeyboardShortcutsState();
}

class _DialogKeyboardShortcutsState extends State<DialogKeyboardShortcuts> {
  late final FocusScopeNode _focusScopeNode;

  @override
  void initState() {
    super.initState();
    _focusScopeNode = FocusScopeNode(debugLabel: 'DialogKeyboardShortcuts');
  }

  @override
  void dispose() {
    _focusScopeNode.dispose();
    super.dispose();
  }

  bool get _hasSubmitHandler => widget.onSubmit != null;

  bool _shouldHandleSubmitKey() {
    if (!_hasSubmitHandler) {
      return false;
    }
    final primaryFocus = FocusManager.instance.primaryFocus;
    if (primaryFocus == null) {
      return true;
    }
    final context = primaryFocus.context;
    if (context == null) {
      return true;
    }
    EditableText? editable;
    final widget = context.widget;
    if (widget is EditableText) {
      editable = widget;
    } else {
      editable = context.findAncestorWidgetOfExactType<EditableText>();
    }
    if (editable != null) {
      // Multi-line 입력에서는 엔터 키를 입력값으로 전달한다.
      final bool isMultiline =
          editable.maxLines == null || editable.maxLines! > 1;
      if (isMultiline) {
        return false;
      }
    }
    return true;
  }

  Map<ShortcutActivator, Intent> get _shortcuts {
    final shortcuts = <ShortcutActivator, Intent>{
      LogicalKeySet(LogicalKeyboardKey.escape): const _DismissIntent(),
    };
    if (_hasSubmitHandler) {
      shortcuts[LogicalKeySet(LogicalKeyboardKey.enter)] =
          const _SubmitIntent();
      shortcuts[LogicalKeySet(LogicalKeyboardKey.numpadEnter)] =
          const _SubmitIntent();
    }
    return shortcuts;
  }

  Map<Type, Action<Intent>> get _actions {
    return <Type, Action<Intent>>{
      _DismissIntent: CallbackAction<_DismissIntent>(
        onInvoke: (intent) {
          widget.onEscape?.call();
          return null;
        },
      ),
      _SubmitIntent: CallbackAction<_SubmitIntent>(
        onInvoke: (intent) {
          if (_shouldHandleSubmitKey()) {
            final callback = widget.onSubmit;
            if (callback != null) {
              final result = callback();
              if (result is Future<void>) {
                return result;
              }
            }
          }
          return null;
        },
      ),
    };
  }

  @override
  Widget build(BuildContext context) {
    Widget content = widget.child;

    if (widget.enableFocusTrap) {
      content = FocusTraversalGroup(
        policy: WidgetOrderTraversalPolicy(),
        child: FocusScope(
          node: _focusScopeNode,
          autofocus: true,
          child: content,
        ),
      );
    } else {
      content = FocusTraversalGroup(
        policy: WidgetOrderTraversalPolicy(),
        child: FocusScope(autofocus: true, child: content),
      );
    }

    return Shortcuts(
      shortcuts: _shortcuts,
      child: Actions(actions: _actions, child: content),
    );
  }
}

class _DismissIntent extends Intent {
  const _DismissIntent();
}

class _SubmitIntent extends Intent {
  const _SubmitIntent();
}
