using CommunityToolkit.Mvvm.ComponentModel;
using Sonex.DBWrapper;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Threading.Tasks;
using Logger = Sonex.Client.Helpers.Logger;

namespace Sonex.Client.Models;

public partial class AccountPreferencesModel : ObservableObject
{
    [ObservableProperty]
    private string key = string.Empty;

    [ObservableProperty]
    private string value = string.Empty;

    private static readonly object _cacheLock = new();
    private static readonly Dictionary<string, string> _cache = new(StringComparer.OrdinalIgnoreCase);

    public static IReadOnlyDictionary<string, string> Cache
    {
        get
        {
            lock (_cacheLock)
            {
                return new Dictionary<string, string>(_cache, StringComparer.OrdinalIgnoreCase);
            }
        }
    }

    public static async Task<DB.Result<AccountPreferencesModel>> GetAll()
    {
        try
        {
            return await DB.QueryListAsync<AccountPreferencesModel>(
                "SELECT \"key\" AS Key, \"value\" AS Value FROM sonex.account_preferences_get();");
        }
        catch (Exception ex)
        {
            Logger.Error(
                ex,
                source: nameof(AccountPreferencesModel),
                operation: nameof(GetAll));
            return new DB.Result<AccountPreferencesModel>
            {
                Success = false,
                ErrorMessage = ex.Message,
                ErrorStackTrace = ex.StackTrace
            };
        }
    }

    public static async Task<DB.Result<AccountPreferencesModel>> LoadAllToCache()
    {
        try
        {
            var result = await GetAll();
            if (!result.Success)
            {
                return result;
            }

            lock (_cacheLock)
            {
                _cache.Clear();
                foreach (var item in result.Items)
                {
                    if (string.IsNullOrWhiteSpace(item.Key))
                    {
                        continue;
                    }

                    _cache[item.Key] = item.Value ?? string.Empty;
                }
            }

            return result;
        }
        catch (Exception ex)
        {
            Logger.Error(
                ex,
                source: nameof(AccountPreferencesModel),
                operation: nameof(LoadAllToCache));
            return new DB.Result<AccountPreferencesModel>
            {
                Success = false,
                ErrorMessage = ex.Message,
                ErrorStackTrace = ex.StackTrace
            };
        }
    }

    public static async Task<DB.SingleResult<bool>> Update(string key, string value)
    {
        if (string.IsNullOrWhiteSpace(key))
        {
            return new DB.SingleResult<bool>
            {
                Success = false,
                Item = false,
                ErrorMessage = "Preference key cannot be empty."
            };
        }

        try
        {
            var safeKey = key.Trim();
            var safeValue = value ?? string.Empty;
            var result = await DB.QuerySingleAsync<bool>(
                "SELECT sonex.account_preferences_update(@Key, @Value);",
                new { Key = safeKey, Value = safeValue });

            if (result.Success && result.Item == true)
            {
                SetCachedValue(safeKey, safeValue);
            }

            return result;
        }
        catch (Exception ex)
        {
            Logger.Error(
                ex,
                source: nameof(AccountPreferencesModel),
                operation: nameof(Update));
            return new DB.SingleResult<bool>
            {
                Success = false,
                Item = false,
                ErrorMessage = ex.Message,
                ErrorStackTrace = ex.StackTrace
            };
        }
    }

    public static void SetCachedValue(string key, string value)
    {
        if (string.IsNullOrWhiteSpace(key))
        {
            return;
        }

        var safeKey = key.Trim();
        var safeValue = value ?? string.Empty;

        lock (_cacheLock)
        {
            _cache[safeKey] = safeValue;
        }
    }

    public static bool TryGetCachedValue(string key, out string value)
    {
        value = string.Empty;
        if (string.IsNullOrWhiteSpace(key))
        {
            return false;
        }

        lock (_cacheLock)
        {
            return _cache.TryGetValue(key.Trim(), out value);
        }
    }
}
