// Copyright (c) 2025-2026 GeWuYou
// SPDX-License-Identifier: Apache-2.0

using System.Collections.Concurrent;
using System.Globalization;
using System.IO;
using System.Text.Json;
using GFramework.Core.Abstractions.Configuration;
using GFramework.Core.Abstractions.Events;
using GFramework.Core.Abstractions.Logging;
using GFramework.Core.Logging;

namespace GFramework.Core.Configuration;

/// <summary>
///     配置管理器实现，提供线程安全的配置存储和访问
///     线程安全：所有公共方法都是线程安全的
/// </summary>
public class ConfigurationManager : IConfigurationManager
{
    /// <summary>
    ///     Key 参数验证错误消息常量
    /// </summary>
    private const string KeyCannotBeNullOrEmptyMessage = "Key cannot be null or whitespace.";

    /// <summary>
    ///     Path 参数验证错误消息常量
    /// </summary>
    private const string PathCannotBeNullOrEmptyMessage = "Path cannot be null or whitespace.";

    /// <summary>
    ///     JSON 参数验证错误消息常量
    /// </summary>
    private const string JsonCannotBeNullOrEmptyMessage = "JSON cannot be null or whitespace.";

    /// <summary>
    ///     配置存储字典（线程安全）
    /// </summary>
    private readonly ConcurrentDictionary<string, object> _configs = new(StringComparer.Ordinal);

    private readonly ILogger _logger = LoggerFactoryResolver.Provider.CreateLogger(nameof(ConfigurationManager));

    /// <summary>
    ///     用于保护监听器列表的锁
    /// </summary>
#if NET9_0_OR_GREATER
    // net9.0 及以上目标使用专用 Lock，以满足分析器对专用同步原语的建议。
    private readonly System.Threading.Lock _watcherLock = new();
#else
    // net8.0 目标仍回退到 object 锁，以保持多目标编译兼容性。
    private readonly object _watcherLock = new();
#endif

    /// <summary>
    ///     配置监听器字典（线程安全）
    ///     键：配置键，值：监听器列表
    /// </summary>
    private readonly ConcurrentDictionary<string, List<Delegate>> _watchers = new(StringComparer.Ordinal);

    /// <summary>
    ///     获取配置数量
    /// </summary>
    public int Count => _configs.Count;

    /// <summary>
    ///     获取指定键的配置值
    /// </summary>
    public T? GetConfig<T>(string key)
    {
        if (string.IsNullOrWhiteSpace(key))
            throw new ArgumentException(KeyCannotBeNullOrEmptyMessage, nameof(key));

        if (_configs.TryGetValue(key, out var value))
        {
            return ConvertValue<T>(value);
        }

        return default;
    }

    /// <summary>
    ///     获取指定键的配置值，如果不存在则返回默认值
    /// </summary>
    public T GetConfig<T>(string key, T defaultValue)
    {
        if (string.IsNullOrWhiteSpace(key))
            throw new ArgumentException(KeyCannotBeNullOrEmptyMessage, nameof(key));

        if (_configs.TryGetValue(key, out var value))
        {
            return ConvertValue<T>(value);
        }

        return defaultValue;
    }

    /// <summary>
    ///     设置指定键的配置值
    /// </summary>
    public void SetConfig<T>(string key, T value)
    {
        if (string.IsNullOrWhiteSpace(key))
            throw new ArgumentException(KeyCannotBeNullOrEmptyMessage, nameof(key));

        // 先获取旧值，以便正确检测变更
        _configs.TryGetValue(key, out var oldValue);

        // 更新配置值
        _configs[key] = value!;

        // 只有在值真正变化时才触发监听器
        if (!EqualityComparer<object>.Default.Equals(oldValue, value))
        {
            NotifyWatchers(key, value);
        }
    }

    /// <summary>
    ///     检查指定键的配置是否存在
    /// </summary>
    public bool HasConfig(string key)
    {
        if (string.IsNullOrWhiteSpace(key))
            throw new ArgumentException(KeyCannotBeNullOrEmptyMessage, nameof(key));

        return _configs.ContainsKey(key);
    }

    /// <summary>
    ///     移除指定键的配置
    /// </summary>
    public bool RemoveConfig(string key)
    {
        if (string.IsNullOrWhiteSpace(key))
            throw new ArgumentException(KeyCannotBeNullOrEmptyMessage, nameof(key));

        var removed = _configs.TryRemove(key, out _);

        if (removed)
        {
            // 移除该键的所有监听器（使用锁保护）
            lock (_watcherLock)
            {
                _watchers.TryRemove(key, out _);
            }
        }

        return removed;
    }

    /// <summary>
    ///     清空所有配置
    /// </summary>
    public void Clear()
    {
        _configs.Clear();

        // 清空监听器（使用锁保护）
        lock (_watcherLock)
        {
            _watchers.Clear();
        }
    }

    /// <summary>
    ///     监听指定键的配置变化
    /// </summary>
    public IUnRegister WatchConfig<T>(string key, Action<T> onChange)
    {
        if (string.IsNullOrWhiteSpace(key))
            throw new ArgumentException(KeyCannotBeNullOrEmptyMessage, nameof(key));

        if (onChange == null)
            throw new ArgumentNullException(nameof(onChange));

        lock (_watcherLock)
        {
            if (!_watchers.TryGetValue(key, out var watchers))
            {
                watchers = new List<Delegate>();
                _watchers[key] = watchers;
            }

            watchers.Add(onChange);
        }

        return new ConfigWatcherUnRegister(() => UnwatchConfig(key, onChange));
    }

    /// <summary>
    ///     从 JSON 字符串加载配置
    /// </summary>
    public void LoadFromJson(string json)
    {
        if (string.IsNullOrWhiteSpace(json))
            throw new ArgumentException(JsonCannotBeNullOrEmptyMessage, nameof(json));

        var dict = JsonSerializer.Deserialize<Dictionary<string, JsonElement>>(json);
        if (dict == null)
            return;

        foreach (var kvp in dict)
        {
            _configs[kvp.Key] = kvp.Value;
        }
    }

    /// <summary>
    ///     将配置保存为 JSON 字符串
    /// </summary>
    public string SaveToJson()
    {
        var dict = _configs.ToDictionary(kvp => kvp.Key, kvp => kvp.Value, StringComparer.Ordinal);
        return JsonSerializer.Serialize(dict, new JsonSerializerOptions
        {
            WriteIndented = true
        });
    }

    /// <summary>
    ///     从文件加载配置
    /// </summary>
    public void LoadFromFile(string path)
    {
        if (string.IsNullOrWhiteSpace(path))
            throw new ArgumentException(PathCannotBeNullOrEmptyMessage, nameof(path));

        if (!File.Exists(path))
            throw new FileNotFoundException($"Configuration file not found: {path}");

        var json = File.ReadAllText(path);
        LoadFromJson(json);
    }

    /// <summary>
    ///     将配置保存到文件
    /// </summary>
    public void SaveToFile(string path)
    {
        if (string.IsNullOrWhiteSpace(path))
            throw new ArgumentException(PathCannotBeNullOrEmptyMessage, nameof(path));

        var directory = Path.GetDirectoryName(path);
        if (!string.IsNullOrEmpty(directory) && !Directory.Exists(directory))
        {
            Directory.CreateDirectory(directory);
        }

        var json = SaveToJson();
        File.WriteAllText(path, json);
    }

    /// <summary>
    ///     获取所有配置键
    /// </summary>
    public IEnumerable<string> GetAllKeys()
    {
        return _configs.Keys.ToList();
    }

    /// <summary>
    ///     取消监听指定键的配置变化
    /// </summary>
    private void UnwatchConfig<T>(string key, Action<T> onChange)
    {
        lock (_watcherLock)
        {
            if (_watchers.TryGetValue(key, out var watchers))
            {
                watchers.Remove(onChange);

                if (watchers.Count == 0)
                {
                    _watchers.TryRemove(key, out _);
                }
            }
        }
    }

    /// <summary>
    ///     通知监听器配置已变化
    /// </summary>
    private void NotifyWatchers<T>(string key, T newValue)
    {
        List<Delegate>? watchersCopy = null;

        lock (_watcherLock)
        {
            if (_watchers.TryGetValue(key, out var watchers))
            {
                watchersCopy = new List<Delegate>(watchers);
            }
        }

        if (watchersCopy == null)
            return;

        foreach (var watcher in watchersCopy)
        {
            try
            {
                if (watcher is Action<T> typedWatcher)
                {
                    typedWatcher(newValue);
                }
            }
            catch (Exception ex)
            {
                // 防止监听器异常影响其他监听器
                _logger.Error($"Error in config watcher for key '{key}'", ex);
            }
        }
    }

    /// <summary>
    ///     转换配置值到目标类型
    /// </summary>
    private static T ConvertValue<T>(object value)
    {
        if (value is T typedValue)
        {
            return typedValue;
        }

        // 处理 JsonElement 类型
        if (value is JsonElement jsonElement)
        {
            return JsonSerializer.Deserialize<T>(jsonElement.GetRawText())!;
        }

        // 尝试类型转换
        try
        {
            return (T)Convert.ChangeType(value, typeof(T), CultureInfo.InvariantCulture);
        }
        catch
        {
            return default!;
        }
    }
}
