// 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 'dart:collection';
import 'dart:io';

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

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

/// A class that can hold invocation information that an [UndoableAction] can
/// use to undo/redo itself.
///
/// Instances of this class are returned from [UndoableAction]s and placed on
/// the undo stack when they are invoked.
class Memento extends Object with Diagnosticable {
  const Memento({
    required this.name,
    required this.undo,
    required this.redo,
  });

  /// Returns true if this Memento can be used to undo.
  ///
  /// Subclasses could override to provide their own conditions when a command is
  /// undoable.
  bool get canUndo => true;

  /// Returns true if this Memento can be used to redo.
  ///
  /// Subclasses could override to provide their own conditions when a command is
  /// redoable.
  bool get canRedo => true;

  final String name;
  final VoidCallback undo;
  final ValueGetter<Memento> redo;

  @override
  void debugFillProperties(DiagnosticPropertiesBuilder properties) {
    super.debugFillProperties(properties);
    properties.add(StringProperty('name', name));
    properties.add(FlagProperty('undo', value: undo != null, ifTrue: 'undo'));
    properties.add(FlagProperty('redo', value: redo != null, ifTrue: 'redo'));
  }
}

/// Undoable Actions

/// An [ActionDispatcher] subclass that manages the invocation of undoable
/// actions.
class UndoableActionDispatcher extends ActionDispatcher implements Listenable {
  /// Constructs a new [UndoableActionDispatcher].
  ///
  /// The [maxUndoLevels] argument must not be null.
  UndoableActionDispatcher({
    int maxUndoLevels = _defaultMaxUndoLevels,
  })  : assert(maxUndoLevels != null),
        _maxUndoLevels = maxUndoLevels;

  // A stack of actions that have been performed. The most recent action
  // performed is at the end of the list.
  final DoubleLinkedQueue<Memento> _completedActions = DoubleLinkedQueue<Memento>();
  // A stack of actions that can be redone. The most recent action performed is
  // at the end of the list.
  final List<Memento> _undoneActions = <Memento>[];

  static const int _defaultMaxUndoLevels = 1000;

  /// The maximum number of undo levels allowed.
  ///
  /// If this value is set to a value smaller than the number of completed
  /// actions, then the stack of completed actions is truncated to only include
  /// the last [maxUndoLevels] actions.
  int get maxUndoLevels => _maxUndoLevels;
  int _maxUndoLevels;
  set maxUndoLevels(int value) {
    _maxUndoLevels = value;
    _pruneActions();
  }

  final Set<VoidCallback> _listeners = <VoidCallback>{};

  @override
  void addListener(VoidCallback listener) {
    _listeners.add(listener);
  }

  @override
  void removeListener(VoidCallback listener) {
    _listeners.remove(listener);
  }

  /// Notifies listeners that the [ActionDispatcher] has changed state.
  ///
  /// May only be called by subclasses.
  @protected
  void notifyListeners() {
    for (final VoidCallback callback in _listeners) {
      callback();
    }
  }

  @override
  Object? invokeAction(Action<Intent> action, Intent intent, [BuildContext? context]) {
    final Object? result = super.invokeAction(action, intent, context);
    print('Invoking ${action is UndoableAction ? 'undoable ' : ''}$intent as $action: $this ');
    if (action is UndoableAction) {
      _completedActions.addLast(result! as Memento);
      _undoneActions.clear();
      _pruneActions();
      notifyListeners();
    }
    return result;
  }

  // Enforces undo level limit.
  void _pruneActions() {
    while (_completedActions.length > _maxUndoLevels) {
      _completedActions.removeFirst();
    }
  }

  /// Returns true if there is an action on the stack that can be undone.
  bool get canUndo {
    if (_completedActions.isNotEmpty) {
      return _completedActions.first.canUndo;
    }
    return false;
  }

  /// Returns true if an action that has been undone can be re-invoked.
  bool get canRedo {
    if (_undoneActions.isNotEmpty) {
      return _undoneActions.first.canRedo;
    }
    return false;
  }

  /// Undoes the last action executed if possible.
  ///
  /// Returns true if the action was successfully undone.
  bool undo() {
    print('Undoing. $this');
    if (!canUndo) {
      return false;
    }
    final Memento memento = _completedActions.removeLast();
    memento.undo();
    _undoneActions.add(memento);
    notifyListeners();
    return true;
  }

  /// Re-invokes a previously undone action, if possible.
  ///
  /// Returns true if the action was successfully invoked.
  bool redo() {
    print('Redoing. $this');
    if (!canRedo) {
      return false;
    }
    final Memento memento = _undoneActions.removeLast();
    final Memento replacement = memento.redo();
    _completedActions.add(replacement);
    _pruneActions();
    notifyListeners();
    return true;
  }

  @override
  void debugFillProperties(DiagnosticPropertiesBuilder properties) {
    super.debugFillProperties(properties);
    properties.add(IntProperty('undoable items', _completedActions.length));
    properties.add(IntProperty('redoable items', _undoneActions.length));
    properties.add(IterableProperty<Memento>('undo stack', _completedActions));
    properties.add(IterableProperty<Memento>('redo stack', _undoneActions));
  }
}

class UndoIntent extends Intent {
  const UndoIntent();
}

class UndoAction extends Action<UndoIntent> {
  @override
  bool isEnabled(UndoIntent intent) {
    final BuildContext? buildContext = primaryFocus?.context ?? FocusDemo.appKey.currentContext;
    if (buildContext == null) {
      return false;
    }
    final UndoableActionDispatcher manager = Actions.of(buildContext) as UndoableActionDispatcher;
    return manager.canUndo;
  }

  @override
  void invoke(UndoIntent intent) {
    final BuildContext? buildContext = primaryFocus?.context ?? FocusDemo.appKey.currentContext;
    if (buildContext == null) {
      return;
    }
    final UndoableActionDispatcher manager = Actions.of(primaryFocus?.context ?? FocusDemo.appKey.currentContext!) as UndoableActionDispatcher;
    manager.undo();
  }
}

class RedoIntent extends Intent {
  const RedoIntent();
}

class RedoAction extends Action<RedoIntent> {
  @override
  bool isEnabled(RedoIntent intent) {
    final BuildContext? buildContext = primaryFocus?.context ?? FocusDemo.appKey.currentContext;
    if (buildContext == null) {
      return false;
    }
    final UndoableActionDispatcher manager = Actions.of(buildContext) as UndoableActionDispatcher;
    return manager.canRedo;
  }

  @override
  RedoAction invoke(RedoIntent intent) {
    final BuildContext? buildContext = primaryFocus?.context ?? FocusDemo.appKey.currentContext;
    if (buildContext == null) {
      return this;
    }
    final UndoableActionDispatcher manager = Actions.of(buildContext) as UndoableActionDispatcher;
    manager.redo();
    return this;
  }
}

/// An action that can be undone.
abstract class UndoableAction<T extends Intent> extends Action<T> {
  /// The [Intent] this action was originally invoked with.
  Intent? get invocationIntent => _invocationTag;
  Intent? _invocationTag;

  @protected
  set invocationIntent(Intent? value) => _invocationTag = value;

  @override
  @mustCallSuper
  void invoke(T intent) {
    invocationIntent = intent;
  }
}

class UndoableFocusActionBase<T extends Intent> extends UndoableAction<T> {
  @override
  @mustCallSuper
  Memento invoke(T intent) {
    super.invoke(intent);
    final FocusNode? previousFocus = primaryFocus;
    return Memento(name: previousFocus!.debugLabel!, undo: () {
      previousFocus.requestFocus();
    }, redo: () {
      return invoke(intent);
    });
  }
}

class UndoableRequestFocusAction extends UndoableFocusActionBase<RequestFocusIntent> {
  @override
  Memento invoke(RequestFocusIntent intent) {
    final Memento memento = super.invoke(intent);
    intent.focusNode.requestFocus();
    return memento;
  }
}

/// Actions for manipulating focus.
class UndoableNextFocusAction extends UndoableFocusActionBase<NextFocusIntent> {
  @override
  Memento invoke(NextFocusIntent intent) {
    final Memento memento = super.invoke(intent);
    primaryFocus?.nextFocus();
    return memento;
  }
}

class UndoablePreviousFocusAction extends UndoableFocusActionBase<PreviousFocusIntent> {
  @override
  Memento invoke(PreviousFocusIntent intent) {
    final Memento memento = super.invoke(intent);
    primaryFocus?.previousFocus();
    return memento;
  }
}

class UndoableDirectionalFocusAction extends UndoableFocusActionBase<DirectionalFocusIntent> {
  TraversalDirection? direction;

  @override
  Memento invoke(DirectionalFocusIntent intent) {
    final Memento memento = super.invoke(intent);
    primaryFocus?.focusInDirection(intent.direction);
    return memento;
  }
}

/// A button class that takes focus when clicked.
class DemoButton extends StatefulWidget {
  const DemoButton({super.key, required this.name});

  final String name;

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

class _DemoButtonState extends State<DemoButton> {
  late final FocusNode _focusNode = FocusNode(debugLabel: widget.name);
  final GlobalKey _nameKey = GlobalKey();

  void _handleOnPressed() {
    print('Button ${widget.name} pressed.');
    setState(() {
      Actions.invoke(_nameKey.currentContext!, RequestFocusIntent(_focusNode));
    });
  }

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

  @override
  Widget build(BuildContext context) {
    return TextButton(
      focusNode: _focusNode,
      style: ButtonStyle(
        foregroundColor: const MaterialStatePropertyAll<Color>(Colors.black),
        overlayColor: MaterialStateProperty.resolveWith<Color>((Set<MaterialState> states) {
          if (states.contains(MaterialState.focused)) {
            return Colors.red;
          }
          if (states.contains(MaterialState.hovered)) {
            return Colors.blue;
          }
          return Colors.transparent;
        }),
      ),
      onPressed: () => _handleOnPressed(),
      child: Text(widget.name, key: _nameKey),
    );
  }
}

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

  static GlobalKey appKey = GlobalKey();

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

class _FocusDemoState extends State<FocusDemo> {
  final FocusNode outlineFocus = FocusNode(debugLabel: 'Demo Focus Node');
  late final UndoableActionDispatcher dispatcher = UndoableActionDispatcher();
  bool canUndo = false;
  bool canRedo = false;

  @override
  void initState() {
    super.initState();
    canUndo = dispatcher.canUndo;
    canRedo = dispatcher.canRedo;
    dispatcher.addListener(_handleUndoStateChange);
  }

  void _handleUndoStateChange() {
    if (dispatcher.canUndo != canUndo) {
      setState(() {
        canUndo = dispatcher.canUndo;
      });
    }
    if (dispatcher.canRedo != canRedo) {
      setState(() {
        canRedo = dispatcher.canRedo;
      });
    }
  }

  @override
  void dispose() {
    dispatcher.removeListener(_handleUndoStateChange);
    outlineFocus.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    final TextTheme textTheme = Theme.of(context).textTheme;
    return Actions(
      dispatcher: dispatcher,
      actions: <Type, Action<Intent>>{
        RequestFocusIntent: UndoableRequestFocusAction(),
        NextFocusIntent: UndoableNextFocusAction(),
        PreviousFocusIntent: UndoablePreviousFocusAction(),
        DirectionalFocusIntent: UndoableDirectionalFocusAction(),
        UndoIntent: UndoAction(),
        RedoIntent: RedoAction(),
      },
      child: FocusTraversalGroup(
        policy: ReadingOrderTraversalPolicy(),
        child: Shortcuts(
          shortcuts: <ShortcutActivator, Intent>{
            SingleActivator(LogicalKeyboardKey.keyZ, meta: Platform.isMacOS, control: !Platform.isMacOS, shift: true): const RedoIntent(),
            SingleActivator(LogicalKeyboardKey.keyZ, meta: Platform.isMacOS, control: !Platform.isMacOS): const UndoIntent(),
          },
          child: FocusScope(
            key: FocusDemo.appKey,
            debugLabel: 'Scope',
            autofocus: true,
            child: DefaultTextStyle(
              style: textTheme.headlineMedium!,
              child: Scaffold(
                appBar: AppBar(
                  title: const Text('Actions Demo'),
                ),
                body: Center(
                  child: Builder(builder: (BuildContext context) {
                    return Column(
                      mainAxisAlignment: MainAxisAlignment.center,
                      children: <Widget>[
                        Row(
                          mainAxisAlignment: MainAxisAlignment.center,
                          children: const <Widget>[
                            DemoButton(name: 'One'),
                            DemoButton(name: 'Two'),
                            DemoButton(name: 'Three'),
                          ],
                        ),
                        Row(
                          mainAxisAlignment: MainAxisAlignment.center,
                          children: const <Widget>[
                            DemoButton(name: 'Four'),
                            DemoButton(name: 'Five'),
                            DemoButton(name: 'Six'),
                          ],
                        ),
                        Row(
                          mainAxisAlignment: MainAxisAlignment.center,
                          children: const <Widget>[
                            DemoButton(name: 'Seven'),
                            DemoButton(name: 'Eight'),
                            DemoButton(name: 'Nine'),
                          ],
                        ),
                        Row(
                          mainAxisAlignment: MainAxisAlignment.center,
                          children: <Widget>[
                            Padding(
                              padding: const EdgeInsets.all(8.0),
                              child: ElevatedButton(
                                onPressed: canUndo
                                    ? () {
                                        Actions.invoke(context, const UndoIntent());
                                      }
                                    : null,
                                child: const Text('UNDO'),
                              ),
                            ),
                            Padding(
                              padding: const EdgeInsets.all(8.0),
                              child: ElevatedButton(
                                onPressed: canRedo
                                    ? () {
                                        Actions.invoke(context, const RedoIntent());
                                      }
                                    : null,
                                child: const Text('REDO'),
                              ),
                            ),
                          ],
                        ),
                      ],
                    );
                  }),
                ),
              ),
            ),
          ),
        ),
      ),
    );
  }
}
