using System;
using System.Diagnostics.Tracing;
using Avalonia.Layout;
using CommunityToolkit.Mvvm.ComponentModel;
using DialogHostAvalonia;
using InABox.Avalonia.Components;
using InABox.Avalonia.Router;

namespace InABox.Avalonia;


public interface IViewModelBase
{
    Task Activate();
    Task Deactivate();

    bool OnBackButtonPressed();

    bool BackButtonVisible { get; set; }
    
    bool ProgressVisible { get; set; }
    AvaloniaMenuItemCollection PrimaryMenu { get; set; }
    AvaloniaMenuItemCollection SecondaryMenu { get; set; }
}

public interface IPopupViewModel
{
    bool IsClosed { get; }
}

/// <summary>
/// Indicates that this view model can be a module or a popup.
/// </summary>
public interface IDualFunctionViewModel : IPopupViewModel, IViewModelBase
{
    bool IsPopup { get; set; }
}

public interface IAlignedPopup
{
    HorizontalAlignment HorizontalAlignment { get; }
    VerticalAlignment VerticalAlignment { get; }
}

public interface IPopupViewModel<TResult> : IPopupViewModel
{
    TResult? GetResult();
}

public static class Navigation
{
    private static readonly HistoryRouter<IViewModelBase> _router;

    static Navigation()
    {
        _router = new HistoryRouter<IViewModelBase>(x => Activator.CreateInstance(x) as IViewModelBase);
        _router.CurrentViewModelChanging += (@base, direction) => CurrentViewModelChanging?.Invoke(@base, direction);
        _router.CurrentViewModelChanged += @base => CurrentViewModelChanged?.Invoke(@base);
    }

    public static void Back()
    {
        _router.Back();
    }

    public static void Navigate<T>(Action<T>? configure = null) where T : IViewModelBase
    {
        _router.GoTo<T>(configure);
    }

    public static async Task<object?> Popup<T>(Action<T>? configure = null, bool canTapAway = true)
        where T : IViewModelBase, IPopupViewModel
    {
        var viewModel = _router.InstantiateViewModel<T>(configure);
        return await Popup(viewModel, canTapAway);
    }

    public static async Task<object?> Popup<T>(T viewModel, bool canTapAway = true)
        where T : IViewModelBase, IPopupViewModel
    {
        if (viewModel is IDualFunctionViewModel dualFunction)
        {
            dualFunction.IsPopup = true;
        }
        await viewModel.Activate();
        var _result = await DialogHostAvalonia.DialogHost.Show(viewModel, (object sender, DialogClosingEventArgs eventArgs) =>
        {
            if(!canTapAway && !viewModel.IsClosed)
            {
                eventArgs.Cancel();
            }
        });
        await viewModel.Deactivate();
        return _result;
    }

    public static async Task<TResult?> Popup<T, TResult>(Action<T>? configure = null, bool canTapAway = true)
        where T : IViewModelBase, IPopupViewModel<TResult>
    {
        var viewModel = _router.InstantiateViewModel<T>(configure);
        return await Popup<T, TResult>(viewModel, canTapAway);
    }

    public static async Task<TResult?> Popup<T, TResult>(T viewModel, bool canTapAway = true)
        where T : IViewModelBase, IPopupViewModel<TResult>
    {
        if (viewModel is IDualFunctionViewModel dualFunction)
        {
            dualFunction.IsPopup = true;
        }
        await viewModel.Activate();
        var _result = await DialogHostAvalonia.DialogHost.Show(viewModel, (object sender, DialogClosingEventArgs eventArgs) =>
        {
            if(!canTapAway && !viewModel.IsClosed)
            {
                eventArgs.Cancel();
            }
        });
        await viewModel.Deactivate();
        return viewModel.GetResult();
    }

    public static void Reset<T>(Action<T>? configure = null) where T : IViewModelBase
    {
        _router.Reset<T>(configure);
    }

    public static event Action<IViewModelBase, RouterDirection>? CurrentViewModelChanging;

    public static event Action<IViewModelBase>? CurrentViewModelChanged;
}

public class BasePopupViewModel<TResult> : ObservableObject, IPopupViewModel<TResult?>, IViewModelBase
{
    #region IPopupViewModel

    public bool IsClosed { get; private set; }

    protected TResult? _result;

    public TResult? GetResult()
    {
        return _result;
    }

    public void Close(TResult? result)
    {
        _result = result;
        IsClosed = true;
        DialogHost.GetDialogSession(null)?.Close();
    }

    #endregion

    #region IViewModel

    public bool BackButtonVisible { get; set; }
    public bool ProgressVisible { get; set; }
    public AvaloniaMenuItemCollection PrimaryMenu { get; set; } = new();
    public AvaloniaMenuItemCollection SecondaryMenu { get; set; } = new();

    public Task Activate()
    {
        return Task.CompletedTask;
    }

    public Task Deactivate()
    {
        return Task.CompletedTask;
    }

    public virtual bool OnBackButtonPressed()
    {
        return true;
    }

    #endregion
}
