using System.Text.Json;
using System.Text.Json.Serialization;
using HoneyBox.Core.Interfaces;
using HoneyBox.Model.Data;
using HoneyBox.Model.Models.Payment;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;

namespace HoneyBox.Core.Services;

/// <summary>
/// 微信支付配置服务实现
/// 从数据库读取配置，支持多商户、多小程序
/// </summary>
public class WechatPayConfigService : IWechatPayConfigService
{
    private readonly HoneyBoxDbContext _dbContext;
    private readonly IRedisService _redisService;
    private readonly ILogger<WechatPayConfigService> _logger;
    private readonly Random _random = new();

    private const string MERCHANTS_CACHE_KEY = "wechatpay:merchants";
    private const string MINIPROGRAMS_CACHE_KEY = "wechatpay:miniprograms";
    private static readonly TimeSpan CACHE_DURATION = TimeSpan.FromMinutes(5);

    public WechatPayConfigService(
        HoneyBoxDbContext dbContext,
        IRedisService redisService,
        ILogger<WechatPayConfigService> logger)
    {
        _dbContext = dbContext;
        _redisService = redisService;
        _logger = logger;
    }

    private async Task<List<WechatPayMerchantConfig>> LoadMerchantsAsync()
    {
        var cachedJson = await _redisService.GetStringAsync(MERCHANTS_CACHE_KEY);
        if (!string.IsNullOrEmpty(cachedJson))
        {
            try
            {
                var cached = JsonSerializer.Deserialize<List<WechatPayMerchantConfig>>(cachedJson);
                if (cached != null && cached.Count > 0) return cached;
            }
            catch { }
        }

        var merchants = new List<WechatPayMerchantConfig>();
        try
        {
            var settingConfig = await _dbContext.Configs
                .Where(c => c.ConfigKey == "weixinpay_setting")
                .Select(c => c.ConfigValue)
                .FirstOrDefaultAsync();

            if (!string.IsNullOrEmpty(settingConfig))
            {
                var setting = JsonSerializer.Deserialize<DbWeixinPaySetting>(settingConfig, JsonOptions);
                if (setting?.Merchants != null)
                {
                    foreach (var m in setting.Merchants.Where(x => x.IsEnabled == "1"))
                    {
                        merchants.Add(new WechatPayMerchantConfig
                        {
                            Name = m.Name ?? "",
                            MchId = m.MchId ?? "",
                            Key = m.ApiKey ?? "",
                            OrderPrefix = m.OrderPrefix ?? "",
                            PayVersion = m.PayVersion ?? "V2",
                            ApiV3Key = m.ApiV3Key,
                            CertSerialNo = m.CertSerialNo,
                            PrivateKeyPath = m.PrivateKeyPath,
                            WechatPublicKeyId = m.WechatPublicKeyId,
                            WechatPublicKeyPath = m.WechatPublicKeyPath,
                            NotifyUrl = !string.IsNullOrEmpty(m.NotifyUrl) ? m.NotifyUrl : "https://api.zfunbox.cn/api/notify"
                        });
                    }
                }
            }

            var weixinpayConfig = await _dbContext.Configs
                .Where(c => c.ConfigKey == "weixinpay")
                .Select(c => c.ConfigValue)
                .FirstOrDefaultAsync();

            if (!string.IsNullOrEmpty(weixinpayConfig))
            {
                var config = JsonSerializer.Deserialize<DbWeixinPayConfig>(weixinpayConfig, JsonOptions);
                if (config != null && !string.IsNullOrEmpty(config.MchId) && !merchants.Any(m => m.MchId == config.MchId))
                {
                    merchants.Add(new WechatPayMerchantConfig
                    {
                        Name = "默认商户",
                        MchId = config.MchId,
                        AppId = config.AppId ?? "",
                        Key = config.Keys ?? "",
                        OrderPrefix = "MYH",
                        PayVersion = "V2",
                        NotifyUrl = "https://api.zfunbox.cn/api/notify"
                    });
                }
            }

            _logger.LogInformation("从数据库加载了 {Count} 个商户配置", merchants.Count);
            if (merchants.Count > 0)
            {
                await _redisService.SetStringAsync(MERCHANTS_CACHE_KEY, JsonSerializer.Serialize(merchants), CACHE_DURATION);
            }
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "加载商户配置失败");
        }

        return merchants;
    }

    private async Task<List<MiniprogramConfig>> LoadMiniprogramsAsync()
    {
        var cachedJson = await _redisService.GetStringAsync(MINIPROGRAMS_CACHE_KEY);
        if (!string.IsNullOrEmpty(cachedJson))
        {
            try
            {
                var cached = JsonSerializer.Deserialize<List<MiniprogramConfig>>(cachedJson);
                if (cached != null && cached.Count > 0) return cached;
            }
            catch { }
        }

        var miniprograms = new List<MiniprogramConfig>();
        try
        {
            var settingConfig = await _dbContext.Configs
                .Where(c => c.ConfigKey == "miniprogram_setting")
                .Select(c => c.ConfigValue)
                .FirstOrDefaultAsync();

            if (!string.IsNullOrEmpty(settingConfig))
            {
                var setting = JsonSerializer.Deserialize<DbMiniprogramSetting>(settingConfig, JsonOptions);
                if (setting?.Miniprograms != null)
                {
                    foreach (var m in setting.Miniprograms)
                    {
                        miniprograms.Add(new MiniprogramConfig
                        {
                            Name = m.Name ?? "",
                            AppId = m.AppId ?? "",
                            AppSecret = m.AppSecret ?? "",
                            OrderPrefix = m.OrderPrefix ?? "",
                            IsDefault = m.IsDefault == 1,
                            Merchants = m.Merchants ?? new List<string>()
                        });
                    }
                }
            }

            _logger.LogInformation("从数据库加载了 {Count} 个小程序配置", miniprograms.Count);
            if (miniprograms.Count > 0)
            {
                await _redisService.SetStringAsync(MINIPROGRAMS_CACHE_KEY, JsonSerializer.Serialize(miniprograms), CACHE_DURATION);
            }
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "加载小程序配置失败");
        }

        return miniprograms;
    }

    public WechatPayMerchantConfig GetDefaultConfig()
    {
        var merchants = LoadMerchantsAsync().GetAwaiter().GetResult();
        return merchants.FirstOrDefault() ?? new WechatPayMerchantConfig();
    }

    public WechatPayMerchantConfig GetMerchantByOrderNo(string orderNo)
    {
        var merchants = LoadMerchantsAsync().GetAwaiter().GetResult();
        var miniprograms = LoadMiniprogramsAsync().GetAwaiter().GetResult();

        if (string.IsNullOrEmpty(orderNo) || merchants.Count == 0)
            return GetDefaultConfig();

        var miniprogram = miniprograms.FirstOrDefault(m => m.IsDefault) ?? miniprograms.FirstOrDefault();
        WechatPayMerchantConfig? selectedMerchant = null;
        string appId = miniprogram?.AppId ?? "";

        if (miniprogram != null && miniprogram.Merchants.Count > 0)
        {
            var associatedMerchants = merchants.Where(m => miniprogram.Merchants.Contains(m.MchId)).ToList();
            if (associatedMerchants.Count > 0)
            {
                selectedMerchant = GetRandomMerchant(associatedMerchants);
                _logger.LogDebug("从小程序关联商户中选择: MchId={MchId}", selectedMerchant?.MchId);
            }
        }

        selectedMerchant ??= merchants.FirstOrDefault();
        if (selectedMerchant == null) return new WechatPayMerchantConfig();

        return new WechatPayMerchantConfig
        {
            Name = selectedMerchant.Name,
            MchId = selectedMerchant.MchId,
            AppId = appId,
            Key = selectedMerchant.Key,
            OrderPrefix = selectedMerchant.OrderPrefix,
            Weight = selectedMerchant.Weight,
            NotifyUrl = selectedMerchant.NotifyUrl,
            PayVersion = selectedMerchant.PayVersion,
            ApiV3Key = selectedMerchant.ApiV3Key,
            CertSerialNo = selectedMerchant.CertSerialNo,
            PrivateKeyPath = selectedMerchant.PrivateKeyPath,
            WechatPublicKeyId = selectedMerchant.WechatPublicKeyId,
            WechatPublicKeyPath = selectedMerchant.WechatPublicKeyPath
        };
    }

    public WechatPayMerchantConfig? GetMerchantByPrefix(string merchantPrefix)
    {
        if (string.IsNullOrEmpty(merchantPrefix)) return null;
        var merchants = LoadMerchantsAsync().GetAwaiter().GetResult();
        return merchants.FirstOrDefault(m => !string.IsNullOrEmpty(m.OrderPrefix) && m.OrderPrefix.Equals(merchantPrefix, StringComparison.OrdinalIgnoreCase));
    }

    public MiniprogramConfig? GetMiniprogramByPrefix(string miniprogramPrefix)
    {
        if (string.IsNullOrEmpty(miniprogramPrefix)) return null;
        var miniprograms = LoadMiniprogramsAsync().GetAwaiter().GetResult();
        return miniprograms.FirstOrDefault(m => !string.IsNullOrEmpty(m.OrderPrefix) && m.OrderPrefix.Equals(miniprogramPrefix, StringComparison.OrdinalIgnoreCase));
    }

    public MiniprogramConfig? GetMiniprogramByDomain(string domain) => GetDefaultMiniprogram();

    public MiniprogramConfig? GetDefaultMiniprogram()
    {
        var miniprograms = LoadMiniprogramsAsync().GetAwaiter().GetResult();
        return miniprograms.FirstOrDefault(m => m.IsDefault) ?? miniprograms.FirstOrDefault();
    }

    public OrderPrefixInfo? ExtractOrderPrefix(string orderNo)
    {
        if (string.IsNullOrEmpty(orderNo) || (!orderNo.StartsWith("MH_") && !orderNo.StartsWith("FH_")))
            return null;
        if (orderNo.Length < 6) return null;
        return new OrderPrefixInfo
        {
            MerchantPrefix = orderNo.Substring(3, 3),
            MiniprogramPrefix = orderNo.Length >= 8 ? orderNo.Substring(6, 2) : null
        };
    }

    public WechatPayMerchantConfig? GetRandomMerchant(IEnumerable<WechatPayMerchantConfig> merchants)
    {
        var list = merchants.ToList();
        if (list.Count == 0) return null;
        if (list.Count == 1) return list[0];

        var totalWeight = list.Sum(m => m.Weight > 0 ? m.Weight : 1);
        var randomWeight = _random.Next(1, totalWeight + 1);
        var currentWeight = 0;

        foreach (var merchant in list)
        {
            currentWeight += merchant.Weight > 0 ? merchant.Weight : 1;
            if (randomWeight <= currentWeight) return merchant;
        }
        return list[0];
    }

    public (WechatPayMerchantConfig Merchant, string AppId) GetWxPayConfig()
    {
        var merchant = GetMerchantByOrderNo("");
        return (merchant, merchant.AppId);
    }

    public (WechatPayMerchantConfig? Merchant, string AppId) GetFixedWxPayConfig(string orderPrefix)
    {
        var merchant = GetMerchantByPrefix(orderPrefix);
        if (merchant == null)
        {
            var config = GetWxPayConfig();
            return (config.Merchant, config.AppId);
        }
        var miniprogram = GetDefaultMiniprogram();
        return (merchant, miniprogram?.AppId ?? merchant.AppId);
    }

    private static readonly JsonSerializerOptions JsonOptions = new() { PropertyNameCaseInsensitive = true };

    private class DbWeixinPaySetting { [JsonPropertyName("merchants")] public List<DbMerchantConfig>? Merchants { get; set; } }
    private class DbMerchantConfig
    {
        [JsonPropertyName("name")] public string? Name { get; set; }
        [JsonPropertyName("mch_id")] public string? MchId { get; set; }
        [JsonPropertyName("order_prefix")] public string? OrderPrefix { get; set; }
        [JsonPropertyName("api_key")] public string? ApiKey { get; set; }
        [JsonPropertyName("is_enabled")] public string? IsEnabled { get; set; }
        [JsonPropertyName("pay_version")] public string? PayVersion { get; set; }
        [JsonPropertyName("api_v3_key")] public string? ApiV3Key { get; set; }
        [JsonPropertyName("cert_serial_no")] public string? CertSerialNo { get; set; }
        [JsonPropertyName("private_key_path")] public string? PrivateKeyPath { get; set; }
        [JsonPropertyName("wechat_public_key_id")] public string? WechatPublicKeyId { get; set; }
        [JsonPropertyName("wechat_public_key_path")] public string? WechatPublicKeyPath { get; set; }
        [JsonPropertyName("notify_url")] public string? NotifyUrl { get; set; }
    }
    private class DbWeixinPayConfig
    {
        [JsonPropertyName("appid")] public string? AppId { get; set; }
        [JsonPropertyName("mch_id")] public string? MchId { get; set; }
        [JsonPropertyName("keys")] public string? Keys { get; set; }
    }
    private class DbMiniprogramSetting { [JsonPropertyName("miniprograms")] public List<DbMiniprogramConfig>? Miniprograms { get; set; } }
    private class DbMiniprogramConfig
    {
        [JsonPropertyName("name")] public string? Name { get; set; }
        [JsonPropertyName("appid")] public string? AppId { get; set; }
        [JsonPropertyName("appsecret")] public string? AppSecret { get; set; }
        [JsonPropertyName("order_prefix")] public string? OrderPrefix { get; set; }
        [JsonPropertyName("is_default")] public int IsDefault { get; set; }
        [JsonPropertyName("merchants")] public List<string>? Merchants { get; set; }
    }
}
