using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using Sonex.Client.Controls.DataGridView;
using Sonex.Client.Controls.Filters;
using Sonex.Client.Dialogs;
using Sonex.Data.Records;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Threading;
using System.Threading.Tasks;
using Logger = Sonex.Client.Helpers.Logger;

namespace Sonex.Client.Pages.Administrator.SystemLogs;

public sealed partial class ApplicationErrors : Page
{
    private const int LogsLimit = 10000;
    private CancellationTokenSource? _loadLogsCts;
    private bool _isUnloaded;

    public ApplicationErrors()
    {
        try
        {
            InitializeComponent();

            DetailsTabView.ItemType = typeof(AppLoggerRecord);
            RootFilter.SetColumns(BuildLogFilterColumns(), BuildDefaultFilters());
            RootFilter.FilterChanged += RootFilter_FilterChanged;
            Unloaded += ApplicationErrors_Unloaded;
        }
        catch (Exception ex)
        {
            Logger.Error(
                ex,
                source: nameof(ApplicationErrors),
                operation: "ApplicationErrors.ctor");
        }
    }

    private async void DataGrid_RefreshRequested(object? sender, EventArgs e)
    {
        await LoadLogsAsync();
    }

    private async void RootFilter_FilterChanged(object? sender, EventArgs e)
    {
        if (_isUnloaded)
        {
            return;
        }

        await LoadLogsAsync();
    }

    private async void RefreshButton_Click(object sender, RoutedEventArgs e)
    {
        await LoadLogsAsync();
    }

    private async Task LoadLogsAsync()
    {
        _isUnloaded = false;
        _loadLogsCts?.Cancel();
        _loadLogsCts?.Dispose();
        _loadLogsCts = new CancellationTokenSource();
        var ct = _loadLogsCts.Token;

        SetRefreshButtonsEnabled(false);
        DataGrid.LoadingRing = true;
        DataGrid.ItemsType = typeof(AppLoggerRecord);

        try
        {
            var filter = RootFilter.BuildSql();
            var result = await AppLoggerRecord.GetAll(
                LogsLimit,
                filter.WhereSql,
                filter.Parameters,
                ct);

            if (ct.IsCancellationRequested || _isUnloaded)
            {
                return;
            }

            await this.ShowMessageAsync(result);
            Debug.WriteLine(result.ErrorData ?? $"Loaded app logs: {result.Items.Count}");
            DataGrid.ItemsSource = result.Items;
            DetailsTabView.Load(null);
        }
        finally
        {
            if (!ct.IsCancellationRequested && !_isUnloaded)
            {
                DataGrid.LoadingRing = false;
                SetRefreshButtonsEnabled(true);
            }
        }
    }

    private void DataGrid_OnChangeActiveRow(object sender, DataGridView.DataGridStateChangedEventArgs e)
    {
        if (e.Row is AppLoggerRecord row)
        {
            DetailsTabView.Load(row);
        }
        else
        {
            DetailsTabView.Load(null);
        }
    }

    private void ApplicationErrors_Unloaded(object sender, RoutedEventArgs e)
    {
        _isUnloaded = true;
        _loadLogsCts?.Cancel();
        _loadLogsCts?.Dispose();
        _loadLogsCts = null;

        DataGrid.LoadingRing = false;
        DataGrid.ItemsSource = null;
        DataGrid.ItemsType = null;
        DetailsTabView.Load(null);
    }

    private void SetRefreshButtonsEnabled(bool isEnabled)
    {
        DataGrid.RefreshButtonEnabled = isEnabled;
        RefreshDetailsButton.IsEnabled = isEnabled;
    }

    private static IReadOnlyList<SqlFilterColumn> BuildLogFilterColumns()
    {
        return
        [
            new("Error ID", "error_id", typeof(string)),
            new("Occurred at", "occurred_at", typeof(DateTime)),
            new("Level", "level", typeof(string)),
            new("Application", "application_name", typeof(string)),
            new("Version", "app_version", typeof(string)),
            new("Instance", "instance_id", typeof(string)),
            new("User", "user_name", typeof(string)),
            new("Machine", "machine_name", typeof(string)),
            new("OS version", "os_version", typeof(string)),
            new("Page title", "current_page_title", typeof(string)),
            new("Page", "current_page", typeof(string)),
            new("Source", "source", typeof(string)),
            new("Operation", "operation", typeof(string)),
            new("Unhandled", "is_unhandled", typeof(bool)),
            new("Message", "message", typeof(string)),
            new("Reported message", "reported_message", typeof(string)),
            new("Exception type", "exception_type", typeof(string)),
            new("Exception", "exception_text", typeof(string)),
            new("Context", "context", typeof(string)),
            new("Exception data", "exception_data", typeof(string))
        ];
    }

    private static IReadOnlyList<SqlFilterDefaultRule> BuildDefaultFilters()
    {
        return
        [
            new("occurred_at", SqlFilterComparison.Contains, DateTime.Now.Date),
            new("user_name", SqlFilterComparison.Contains),
            new("machine_name", SqlFilterComparison.Contains)
        ];
    }
}
