// 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: MaterialStateProperty.all<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.headline4!,
              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'),
                              ),
                            ),
                          ],
                        ),
                      ],
                    );
                  }),
                ),
              ),
            ),
          ),
        ),
      ),
    );
  }
}
