using Microsoft.UI.Xaml.Controls;
using Sonex.Data.Records;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using Logger = Sonex.Client.Helpers.Logger;

namespace Sonex.Client.Controls.DataGridView;

// Odpowiedzialnosc pliku: globalna gestosc widoku (Compact/Comfortable/Large) i jej persystencja.

public sealed partial class DataGridView
{
    private enum ViewDensity
    {
        Compact,
        Comfortable,
        Large
    }

    private const double CompactHeaderHeight = 22d;
    private const double CompactRowHeight = 24d;
    private const double ComfortableHeaderHeight = 28d;
    private const double ComfortableRowHeight = 30d;
    private const double LargeHeaderHeight = 34d;
    private const double LargeRowHeight = 36d;

    private const string GlobalViewDensityPreferenceKey = "DataGridView.Size";

    private static readonly object _globalViewDensityLock = new();
    private static readonly List<WeakReference<DataGridView>> _globalViewDensityInstances = new();
    private static ViewDensity? _globalViewDensity;

    // Rejestracja instancji + natychmiastowa próba odtworzenia globalnej gęstości z cache.
    private void InitializeGlobalViewDensity()
    {
        RegisterGlobalViewDensityInstance();

        if (TryResolveGlobalViewDensity(out var density))
        {
            ApplyViewDensityCore(density);
        }
    }

    private void ReapplyGlobalViewDensityIfAvailable()
    {
        if (TryResolveGlobalViewDensity(out var density))
        {
            ApplyViewDensityCore(density);
        }
    }

    private void CleanupGlobalViewDensity()
    {
        lock (_globalViewDensityLock)
        {
            _globalViewDensityInstances.RemoveAll(reference =>
            {
                if (!reference.TryGetTarget(out var instance))
                {
                    return true;
                }

                return ReferenceEquals(instance, this);
            });
        }
    }

    private void ApplyViewDensity(ViewDensity density)
    {
        // Kolejność celowa: lokalnie -> cache -> broadcast -> zapis trwały.
        ApplyViewDensityCore(density);
        UpdateGlobalViewDensity(density);
        AccountPreferenceRecord.SetCachedValue(
            GlobalViewDensityPreferenceKey,
            ToGlobalViewDensityValue(density));
        BroadcastGlobalViewDensity(density, this);
        PersistGlobalViewDensity(density);
    }

    private void ApplyViewDensityCore(ViewDensity density)
    {
        var (targetHeaderHeight, targetRowHeight) = density switch
        {
            ViewDensity.Compact => (CompactHeaderHeight, CompactRowHeight),
            ViewDensity.Comfortable => (ComfortableHeaderHeight, ComfortableRowHeight),
            ViewDensity.Large => (LargeHeaderHeight, LargeRowHeight),
            _ => (CompactHeaderHeight, CompactRowHeight)
        };

        var headerPropertyChanged = false;
        var rowPropertyChanged = false;

        if (Math.Abs(HeaderHeight - targetHeaderHeight) > 0.001d)
        {
            HeaderHeight = targetHeaderHeight;
            headerPropertyChanged = true;
        }

        if (Math.Abs(RowsHeight - targetRowHeight) > 0.001d)
        {
            RowsHeight = targetRowHeight;
            rowPropertyChanged = true;
        }

        var internalChanged = false;
        if (!headerPropertyChanged && Math.Abs(_HeaderHeight - (float)targetHeaderHeight) > 0.001f)
        {
            _HeaderHeight = (float)targetHeaderHeight;
            internalChanged = true;
        }

        if (!rowPropertyChanged && Math.Abs(_RowsHeight - (float)targetRowHeight) > 0.001f)
        {
            _RowsHeight = (float)targetRowHeight;
            internalChanged = true;
        }

        if (internalChanged)
        {
            _NeedCalcVerticalScroll = true;
            RequestRender();
        }
    }

    private MenuFlyoutSubItem BuildViewSubMenu()
    {
        var currentDensity = GetCurrentViewDensity();
        var viewMenu = new MenuFlyoutSubItem
        {
            Text = "View",
            Icon = new SymbolIcon(Symbol.AllApps)
        };

        viewMenu.Items.Add(CreateViewDensityItem("Compact", ViewDensity.Compact, currentDensity));
        viewMenu.Items.Add(CreateViewDensityItem("Comfortable", ViewDensity.Comfortable, currentDensity));
        viewMenu.Items.Add(CreateViewDensityItem("Large", ViewDensity.Large, currentDensity));

        return viewMenu;
    }

    private ToggleMenuFlyoutItem CreateViewDensityItem(string text, ViewDensity density, ViewDensity currentDensity)
    {
        var item = new ToggleMenuFlyoutItem
        {
            Text = text,
            IsChecked = density == currentDensity
        };

        item.Click += (_, _) =>
        {
            ApplyViewDensity(density);
            item.IsChecked = true;
        };

        return item;
    }

    private ViewDensity GetCurrentViewDensity()
    {
        var compactScore = Math.Abs(HeaderHeight - CompactHeaderHeight) + Math.Abs(RowsHeight - CompactRowHeight);
        var comfortableScore = Math.Abs(HeaderHeight - ComfortableHeaderHeight) + Math.Abs(RowsHeight - ComfortableRowHeight);
        var largeScore = Math.Abs(HeaderHeight - LargeHeaderHeight) + Math.Abs(RowsHeight - LargeRowHeight);

        if (comfortableScore <= compactScore && comfortableScore <= largeScore)
        {
            return ViewDensity.Comfortable;
        }

        if (largeScore <= compactScore && largeScore <= comfortableScore)
        {
            return ViewDensity.Large;
        }

        return ViewDensity.Compact;
    }

    private static string ToGlobalViewDensityValue(ViewDensity density)
    {
        return density switch
        {
            ViewDensity.Compact => "Compact",
            ViewDensity.Comfortable => "Comfortable",
            ViewDensity.Large => "Large",
            _ => "Compact"
        };
    }

    private static bool TryParseGlobalViewDensity(string? rawValue, out ViewDensity density)
    {
        density = ViewDensity.Compact;
        if (string.IsNullOrWhiteSpace(rawValue))
        {
            return false;
        }

        var value = rawValue.Trim();
        if (value.Equals("Compact", StringComparison.OrdinalIgnoreCase))
        {
            density = ViewDensity.Compact;
            return true;
        }

        if (value.Equals("Comfortable", StringComparison.OrdinalIgnoreCase))
        {
            density = ViewDensity.Comfortable;
            return true;
        }

        if (value.Equals("Large", StringComparison.OrdinalIgnoreCase))
        {
            density = ViewDensity.Large;
            return true;
        }

        return false;
    }

    private static void UpdateGlobalViewDensity(ViewDensity density)
    {
        lock (_globalViewDensityLock)
        {
            _globalViewDensity = density;
        }
    }

    private static bool TryResolveGlobalViewDensity(out ViewDensity density)
    {
        lock (_globalViewDensityLock)
        {
            if (_globalViewDensity.HasValue)
            {
                density = _globalViewDensity.Value;
                return true;
            }
        }

        if (AccountPreferenceRecord.TryGetCachedValue(GlobalViewDensityPreferenceKey, out var cachedValue)
            && TryParseGlobalViewDensity(cachedValue, out density))
        {
            UpdateGlobalViewDensity(density);
            return true;
        }

        density = ViewDensity.Compact;
        return false;
    }

    private static void BroadcastGlobalViewDensity(ViewDensity density, DataGridView source)
    {
        List<DataGridView> instances;
        lock (_globalViewDensityLock)
        {
            instances = _globalViewDensityInstances
                .Select(reference =>
                {
                    reference.TryGetTarget(out var instance);
                    return instance;
                })
                .Where(instance => instance != null)
                .Cast<DataGridView>()
                .ToList();

            _globalViewDensityInstances.RemoveAll(reference => !reference.TryGetTarget(out _));
        }

        foreach (var instance in instances)
        {
            if (ReferenceEquals(instance, source))
            {
                continue;
            }

            try
            {
                if (instance.DispatcherQueue != null && !instance.DispatcherQueue.HasThreadAccess)
                {
                    instance.DispatcherQueue.TryEnqueue(() => instance.ApplyViewDensityCore(density));
                }
                else
                {
                    instance.ApplyViewDensityCore(density);
                }
            }
            catch (Exception ex)
            {
                Logger.Error(
                    ex,
                    source: nameof(DataGridView),
                    operation: "ViewDensity.BroadcastGlobalViewDensity");
            }
        }
    }

    private static async void PersistGlobalViewDensity(ViewDensity density)
    {
        try
        {
            await AccountPreferenceRecord.Update(
                GlobalViewDensityPreferenceKey,
                ToGlobalViewDensityValue(density));
        }
        catch (Exception ex)
        {
            Logger.Error(
                ex,
                source: nameof(DataGridView),
                operation: "ViewDensity.PersistGlobalViewDensity");
        }
    }

    private void RegisterGlobalViewDensityInstance()
    {
        lock (_globalViewDensityLock)
        {
            _globalViewDensityInstances.RemoveAll(reference =>
            {
                if (!reference.TryGetTarget(out var instance))
                {
                    return true;
                }

                return ReferenceEquals(instance, this);
            });

            _globalViewDensityInstances.Add(new WeakReference<DataGridView>(this));
        }
    }
}
