namespace Pilz.Collections.SimpleHistory;

public class HistoryStack
{
    private readonly Stack<HistoryPoint> stackPast = new();
    private readonly Stack<HistoryPoint> stackFuture = new();

    /// <summary>
    /// Gets the count of history points.
    /// </summary>
    /// <returns></returns>
    public int ChangesCount => stackPast.Count;

    /// <summary>
    /// Gets the current stack of all past HistoryPoints that are used for the Undo function.
    /// </summary>
    /// <returns></returns>
    public HistoryPoint[] PastHistoryPoints => [.. stackPast];

    /// <summary>
    /// Gets the current stack of all future HistoryPoints that are used for the Redo function.
    /// </summary>
    /// <returns></returns>
    public HistoryPoint[] FutureHistoryPoints => [.. stackFuture];

    /// <summary>
    /// Checks if the History has past changes.
    /// </summary>
    /// <returns></returns>
    public bool HasChanges() => stackPast.Count > 0;

    /// <summary>
    /// Patch Object States and call Undo Actions.
    /// </summary>
    public HistoryPoint? Undo()
    {
        HistoryPoint? ret;

        if (stackPast.Count > 0)
        {
            var hp = stackPast.Pop();
            hp.Undo();
            stackFuture.Push(hp);
            ret = hp;
        }
        else
            ret = null;

        return ret;
    }

    /// <summary>
    /// Patch Object States and call Redo Actions.
    /// </summary>
    public HistoryPoint? Redo()
    {
        HistoryPoint? ret;

        if (stackFuture.Count > 0)
        {
            var hp = stackFuture.Pop();
            hp.Redo();
            stackPast.Push(hp);
            ret = hp;
        }
        else
            ret = null;

        return ret;
    }

    /// <summary>
    /// Clear the History.
    /// </summary>
    public void Clear()
    {
        stackPast.Clear();
        stackFuture.Clear();
    }

    /// <summary>
    /// Store a History Point.
    /// </summary>
    /// <param name="point">The History Point to add to the past changes.</param>
    /// <param name="newName">The name to set for the History Point.</param>
    public void Store(HistoryPoint point, string newName)
    {
        point.Name = newName;
        Store(point);
    }

    /// <summary>
    /// Store a History Point.
    /// </summary>
    /// <param name="point">The History Point to add to the past changes.</param>
    public void Store(HistoryPoint point)
    {
        stackPast.Push(point);
        stackFuture.Clear();
    }
}