using System;
using System.Diagnostics;
using CommunityToolkit.Mvvm.Messaging;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using Microsoft.UI.Xaml.Navigation;
using Wino.Core.ViewModels;
using Wino.Messaging.Client.Shell;
using WinoNavigationMode = Wino.Core.Domain.Models.Navigation.NavigationMode;

namespace Wino.Mail.WinUI;

public partial class BasePage : Page, IRecipient<LanguageChanged>
{
    private bool _isPreparedForClose;

    public void Receive(LanguageChanged message)
    {
        OnLanguageChanged();
    }

    public virtual void OnLanguageChanged() { }

    /// <summary>
    /// Register message recipients for this page. Override to register specific message types.
    /// </summary>
    protected virtual void RegisterRecipients() { }

    /// <summary>
    /// Unregister message recipients for this page. Override to unregister specific message types.
    /// </summary>
    protected virtual void UnregisterRecipients() { }

    public virtual CoreBaseViewModel? AssociatedViewModel => null;

    public virtual void PrepareForClose()
    {
        if (_isPreparedForClose)
            return;

        _isPreparedForClose = true;

        WeakReferenceMessenger.Default.Unregister<LanguageChanged>(this);
        UnregisterRecipients();
    }

    protected void ResetPreparedForCloseState()
    {
        _isPreparedForClose = false;
    }

    protected bool IsPreparedForClose => _isPreparedForClose;
}

public abstract class BasePage<T> : BasePage where T : CoreBaseViewModel
{
    public T ViewModel { get; } = WinoApplication.Current.Services.GetService<T>() ?? throw new ArgumentException($"Can't resolve '{typeof(T)}' as view model.");
    public override CoreBaseViewModel AssociatedViewModel => ViewModel;

    protected BasePage()
    {
        ViewModel.Dispatcher = new WinUIDispatcher(DispatcherQueue);

        Loaded += PageLoaded;
        Unloaded += PageUnloaded;
    }

    private void PageUnloaded(object sender, RoutedEventArgs e)
    {
        Loaded -= PageLoaded;
        Unloaded -= PageUnloaded;
    }

    private void PageLoaded(object sender, RoutedEventArgs e) => ViewModel.OnPageLoaded();

    ~BasePage() { Debug.WriteLine($"Disposed {GetType().Name}"); }

    protected override void OnNavigatedTo(NavigationEventArgs e)
    {
        base.OnNavigatedTo(e);

        var mode = GetNavigationMode(e.NavigationMode);
        var parameter = e.Parameter;

        ResetPreparedForCloseState();
        WeakReferenceMessenger.Default.Register<LanguageChanged>(this);
        RegisterRecipients();

        ViewModel.OnNavigatedTo(mode, parameter);
    }

    protected override void OnNavigatingFrom(NavigatingCancelEventArgs e)
    {
        base.OnNavigatingFrom(e);

        var mode = GetNavigationMode(e.NavigationMode);
        var parameter = e.Parameter;

        PrepareForClose(mode, parameter);

        GC.Collect();
    }

    public override void PrepareForClose()
    {
        PrepareForClose(WinoNavigationMode.New, null);
    }

    private void PrepareForClose(WinoNavigationMode mode, object? parameter)
    {
        if (IsPreparedForClose)
            return;

        base.PrepareForClose();
        ViewModel.OnNavigatedFrom(mode, parameter!);
    }

    private WinoNavigationMode GetNavigationMode(NavigationMode mode)
    {
        return (WinoNavigationMode)mode;
    }
}
