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 DataChanges : Page
{
    private const int LogsLimit = 10000;
    private CancellationTokenSource? _loadLogsCts;
    private bool _isUnloaded;

    public DataChanges()
    {
        try
        {
            InitializeComponent();

            DetailsTabView.ItemType = typeof(DataChangeRecord);
            DataGrid.ItemsType = typeof(DataChangeRecord);
            RootFilter.SetColumns(BuildLogFilterColumns(), BuildDefaultFilters());
            RootFilter.FilterChanged += RootFilter_FilterChanged;
            Unloaded += DataChanges_Unloaded;
        }
        catch (Exception ex)
        {
            Logger.Error(
                ex,
                source: nameof(DataChanges),
                operation: "DataChanges.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(DataChangeRecord);

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

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

            await this.ShowMessageAsync(result);
            Debug.WriteLine(result.ErrorData ?? $"Loaded data changes: {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 DataChangeRecord row)
        {
            DetailsTabView.Load(row);
        }
        else
        {
            DetailsTabView.Load(null);
        }
    }

    private void DataChanges_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("ID", "id", typeof(long)),
            new("Changed at", "changed_at_filter", typeof(DateTime)),
            new("Action", "action_type", typeof(string)),
            new("Account", "account_name", typeof(string)),
            new("Table", "table_name", typeof(string)),
            new("Key name", "key_name", typeof(string)),
            new("Key value", "key_value", typeof(string)),
            new("Before", "value_before_text", typeof(string)),
            new("After", "value_after_text", typeof(string))
        ];
    }

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