// Copyright 2014 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

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

void main() {
  runApp(const MaterialApp(title: 'Focus Demo', home: FocusDemo()));
}

class DemoButton extends StatefulWidget {
  const DemoButton({
    super.key,
    required this.name,
    this.canRequestFocus = true,
    this.autofocus = false,
  });

  final String name;
  final bool canRequestFocus;
  final bool autofocus;

  @override
  State<DemoButton> createState() => _DemoButtonState();
}

class _DemoButtonState extends State<DemoButton> {
  late final FocusNode focusNode = FocusNode(
    debugLabel: widget.name,
    canRequestFocus: widget.canRequestFocus,
  );

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

  @override
  void didUpdateWidget(DemoButton oldWidget) {
    super.didUpdateWidget(oldWidget);
    focusNode.canRequestFocus = widget.canRequestFocus;
  }

  void _handleOnPressed() {
    focusNode.requestFocus();
    print('Button ${widget.name} pressed.');
    debugDumpFocusTree();
  }

  @override
  Widget build(BuildContext context) {
    return TextButton(
      focusNode: focusNode,
      autofocus: widget.autofocus,
      style: ButtonStyle(
        overlayColor: WidgetStateProperty.resolveWith<Color>((Set<WidgetState> states) {
          if (states.contains(WidgetState.focused)) {
            return Colors.red.withOpacity(0.25);
          }
          if (states.contains(WidgetState.hovered)) {
            return Colors.blue.withOpacity(0.25);
          }
          return Colors.transparent;
        }),
      ),
      onPressed: () => _handleOnPressed(),
      child: Text(widget.name),
    );
  }
}

class FocusDemo extends StatefulWidget {
  const FocusDemo({super.key});

  @override
  State<FocusDemo> createState() => _FocusDemoState();
}

class _FocusDemoState extends State<FocusDemo> {
  FocusNode? outlineFocus;

  @override
  void initState() {
    super.initState();
    outlineFocus = FocusNode(debugLabel: 'Demo Focus Node');
  }

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

  KeyEventResult _handleKeyPress(FocusNode node, KeyEvent event) {
    if (event is KeyDownEvent) {
      print('Scope got key event: ${event.logicalKey}, $node');
      print('Keys down: ${HardwareKeyboard.instance.logicalKeysPressed}');
      if (event.logicalKey == LogicalKeyboardKey.tab) {
        debugDumpFocusTree();
        if (HardwareKeyboard.instance.logicalKeysPressed.contains(LogicalKeyboardKey.shiftLeft) ||
            HardwareKeyboard.instance.logicalKeysPressed.contains(LogicalKeyboardKey.shiftRight)) {
          print('Moving to previous.');
          node.previousFocus();
          return KeyEventResult.handled;
        } else {
          print('Moving to next.');
          node.nextFocus();
          return KeyEventResult.handled;
        }
      }
      final TraversalDirection? direction = switch (event.logicalKey) {
        LogicalKeyboardKey.arrowLeft => TraversalDirection.left,
        LogicalKeyboardKey.arrowRight => TraversalDirection.right,
        LogicalKeyboardKey.arrowUp => TraversalDirection.up,
        LogicalKeyboardKey.arrowDown => TraversalDirection.down,
        _ => null,
      };
      if (direction != null) {
        node.focusInDirection(direction);
        return KeyEventResult.handled;
      }
    }
    return KeyEventResult.ignored;
  }

  @override
  Widget build(BuildContext context) {
    final TextTheme textTheme = Theme.of(context).textTheme;

    return FocusTraversalGroup(
      policy: ReadingOrderTraversalPolicy(),
      child: FocusScope(
        debugLabel: 'Scope',
        onKeyEvent: _handleKeyPress,
        autofocus: true,
        child: DefaultTextStyle(
          style: textTheme.headlineMedium!,
          child: Scaffold(
            appBar: AppBar(title: const Text('Focus Demo')),
            floatingActionButton: FloatingActionButton(child: const Text('+'), onPressed: () {}),
            body: Center(
              child: Builder(
                builder: (BuildContext context) {
                  return Column(
                    mainAxisAlignment: MainAxisAlignment.center,
                    children: <Widget>[
                      const Row(
                        mainAxisAlignment: MainAxisAlignment.center,
                        children: <Widget>[DemoButton(name: 'One', autofocus: true)],
                      ),
                      const Row(
                        mainAxisAlignment: MainAxisAlignment.center,
                        children: <Widget>[
                          DemoButton(name: 'Two'),
                          DemoButton(name: 'Three', canRequestFocus: false),
                        ],
                      ),
                      const Row(
                        mainAxisAlignment: MainAxisAlignment.center,
                        children: <Widget>[
                          DemoButton(name: 'Four'),
                          DemoButton(name: 'Five'),
                          DemoButton(name: 'Six'),
                        ],
                      ),
                      OutlinedButton(
                        onPressed: () => print('pressed'),
                        child: const Text('PRESS ME'),
                      ),
                      const Padding(
                        padding: EdgeInsets.all(8.0),
                        child: TextField(
                          decoration: InputDecoration(labelText: 'Enter Text', filled: true),
                        ),
                      ),
                      const Padding(
                        padding: EdgeInsets.all(8.0),
                        child: TextField(
                          decoration: InputDecoration(
                            border: OutlineInputBorder(),
                            labelText: 'Enter Text',
                            filled: false,
                          ),
                        ),
                      ),
                    ],
                  );
                },
              ),
            ),
          ),
        ),
      ),
    );
  }
}
