using System;
using System.Collections.Generic;
using Darkmatter.Core.Contracts.Features.History;

namespace Darkmatter.Features.History
{
    public sealed class UndoStack : IUndoStack
    {
        private const int Capacity = 20;

        private readonly LinkedList<ICommand> _undo = new();
        private readonly Stack<ICommand> _redo = new();

        public event Action OnStackChanged;
        public bool CanUndo => _undo.Count > 0;
        public bool CanRedo => _redo.Count > 0;

        public void Push(ICommand cmd)
        {
            cmd.Execute();
            _undo.AddLast(cmd);
            if (_undo.Count > Capacity) _undo.RemoveFirst();
            _redo.Clear();
            OnStackChanged?.Invoke();
        }

        public void Undo()
        {
            if (!CanUndo) return;
            var cmd = _undo.Last!.Value;
            _undo.RemoveLast();
            cmd.Undo();
            _redo.Push(cmd);
            OnStackChanged?.Invoke();
        }

        public void Redo()
        {
            if (!CanRedo) return;
            var cmd = _redo.Pop();
            cmd.Execute();
            _undo.AddLast(cmd);
            OnStackChanged?.Invoke();
        }

        public void Clear()
        {
            foreach (var cmd in _undo) cmd.Undo();
            _undo.Clear();
            _redo.Clear();
            OnStackChanged?.Invoke();
        }
    }
}