namespace InABox.Avalonia.Router;

public enum RouterDirection
{
    Forward,
    Backward
}

public class HistoryRouter<TViewModelBase>: Router<TViewModelBase> where TViewModelBase: class
{
    
    private int _historyIndex = -1;
    private List<TViewModelBase> _history = new();
    private readonly uint _historyMaxSize = 100;

    public bool HasNext => _history.Count > 0 && _historyIndex < _history.Count - 1;
    public bool HasPrev => _historyIndex > 0;
    
    public event Action<TViewModelBase,RouterDirection>? CurrentViewModelChanging;
    
    public HistoryRouter(Func<Type, TViewModelBase> createViewModel) : base(createViewModel)
    {
    }
    
    // pushState
    // popState
    // replaceState

    public void Push(TViewModelBase item)
    {
        if (HasNext)
        {
            _history = _history.Take(_historyIndex + 1).ToList();
        }
        _history.Add(item);
        _historyIndex = _history.Count - 1;
        if (_history.Count > _historyMaxSize)
        {
            _history.RemoveAt(0);
        }
    }
    
    public TViewModelBase? Go(int offset = 0)
    {
        
        if (offset == 0)
        {
            return default;
        }

        var newIndex = _historyIndex + offset;
        if (newIndex < 0 || newIndex > _history.Count - 1)
        {
            return default;
        }
        
        _historyIndex = newIndex;
        var viewModel = _history.ElementAt(_historyIndex);
        
        CurrentViewModelChanging?.Invoke(viewModel, offset >= 0 ? RouterDirection.Forward : RouterDirection.Backward);
        CurrentViewModel = viewModel;
        return viewModel;
    }
    
    public TViewModelBase? Back() => HasPrev ? Go(-1) : default;
    
    public TViewModelBase? Forward() => HasNext ? Go(1) : default;

    private T InternalGoTo<T>(RouterDirection direction, Action<T>? configure = null) where T: TViewModelBase
    {
        var destination = InstantiateViewModel<T>(configure);
        CurrentViewModelChanging?.Invoke(destination, direction);
        CurrentViewModel = destination;
        Push(destination);
        return destination;
    }
    
    public T Reset<T>(Action<T>? configure = null) where T: TViewModelBase
    {
        _historyIndex = -1;
        _history.Clear();
        return InternalGoTo<T>(RouterDirection.Backward, configure);
    }
    
    public override T GoTo<T>(Action<T>? configure = null)
    {
        return InternalGoTo<T>(RouterDirection.Forward, configure);
    }
}