using System.Text.Json;
using HoneyBox.Admin.Business.Models;
using HoneyBox.Admin.Business.Models.Config;
using HoneyBox.Admin.Business.Services;
using HoneyBox.Core.Interfaces;
using HoneyBox.Model.Data;
using HoneyBox.Model.Entities;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using Moq;
using Xunit;

namespace HoneyBox.Tests.Services;

/// <summary>
/// AdminConfigService 单元测试
/// </summary>
public class AdminConfigServiceTests : IDisposable
{
    private readonly HoneyBoxDbContext _dbContext;
    private readonly Mock<IRedisService> _mockRedisService;
    private readonly Mock<ILogger<AdminConfigService>> _mockLogger;
    private readonly AdminConfigService _configService;

    public AdminConfigServiceTests()
    {
        // 使用 InMemory 数据库
        var options = new DbContextOptionsBuilder<HoneyBoxDbContext>()
            .UseInMemoryDatabase(databaseName: Guid.NewGuid().ToString())
            .Options;

        _dbContext = new HoneyBoxDbContext(options);
        _mockRedisService = new Mock<IRedisService>();
        _mockLogger = new Mock<ILogger<AdminConfigService>>();

        // 默认 Redis 返回空值（模拟缓存未命中）
        _mockRedisService.Setup(x => x.GetStringAsync(It.IsAny<string>()))
            .ReturnsAsync((string?)null);

        _configService = new AdminConfigService(
            _dbContext,
            _mockRedisService.Object,
            _mockLogger.Object);
    }

    public void Dispose()
    {
        _dbContext.Dispose();
    }

    #region GetConfigAsync Tests

    [Fact]
    public async Task GetConfigAsync_WithExistingConfig_ReturnsConfig()
    {
        // Arrange
        var testConfig = new { name = "test", value = 123 };
        var configJson = JsonSerializer.Serialize(testConfig);
        _dbContext.Configs.Add(new Config
        {
            ConfigKey = "test_config",
            ConfigValue = configJson
        });
        await _dbContext.SaveChangesAsync();

        // Act
        var result = await _configService.GetConfigRawAsync("test_config");

        // Assert
        Assert.NotNull(result);
        Assert.Equal(configJson, result);
    }

    [Fact]
    public async Task GetConfigAsync_WithNonExistingConfig_ReturnsNull()
    {
        // Act
        var result = await _configService.GetConfigRawAsync("non_existing_config");

        // Assert
        Assert.Null(result);
    }

    [Fact]
    public async Task GetConfigAsync_WithCachedValue_ReturnsCachedValue()
    {
        // Arrange
        var cachedValue = "{\"cached\":true}";
        _mockRedisService.Setup(x => x.GetStringAsync("config:cached_config"))
            .ReturnsAsync(cachedValue);

        // Act
        var result = await _configService.GetConfigRawAsync("cached_config");

        // Assert
        Assert.Equal(cachedValue, result);
        // 验证没有查询数据库
        _mockRedisService.Verify(x => x.GetStringAsync("config:cached_config"), Times.Once);
    }

    #endregion

    #region UpdateConfigAsync Tests

    [Fact]
    public async Task UpdateConfigAsync_WithNewConfig_CreatesConfig()
    {
        // Arrange
        var testConfig = new { name = "new_config", value = 456 };

        // Act
        var result = await _configService.UpdateConfigAsync("new_config", testConfig);

        // Assert
        Assert.True(result);
        var savedConfig = await _dbContext.Configs.FirstOrDefaultAsync(c => c.ConfigKey == "new_config");
        Assert.NotNull(savedConfig);
        Assert.Contains("new_config", savedConfig.ConfigValue!);
    }

    [Fact]
    public async Task UpdateConfigAsync_WithExistingConfig_UpdatesConfig()
    {
        // Arrange
        _dbContext.Configs.Add(new Config
        {
            ConfigKey = "existing_config",
            ConfigValue = "{\"old\":true}"
        });
        await _dbContext.SaveChangesAsync();

        var newConfig = new { updated = true, value = 789 };

        // Act
        var result = await _configService.UpdateConfigAsync("existing_config", newConfig);

        // Assert
        Assert.True(result);
        var savedConfig = await _dbContext.Configs.FirstOrDefaultAsync(c => c.ConfigKey == "existing_config");
        Assert.NotNull(savedConfig);
        Assert.Contains("updated", savedConfig.ConfigValue!);
    }

    [Fact]
    public async Task UpdateConfigAsync_ClearsCache()
    {
        // Arrange
        var testConfig = new { name = "cache_test" };

        // Act
        await _configService.UpdateConfigAsync("cache_test", testConfig);

        // Assert
        _mockRedisService.Verify(x => x.DeleteAsync("config:cache_test"), Times.Once);
    }

    #endregion


    #region Validation Tests

    [Fact]
    public async Task ValidateConfigAsync_WeixinPaySetting_WithValidPrefixes_ReturnsNull()
    {
        // Arrange
        var setting = new WeixinPaySetting
        {
            Merchants = new List<WeixinPayMerchant>
            {
                new() { Name = "商户1", MchId = "123", OrderPrefix = "ABC" },
                new() { Name = "商户2", MchId = "456", OrderPrefix = "DEF" }
            }
        };
        var json = JsonSerializer.Serialize(setting);

        // Act
        var result = await _configService.ValidateConfigAsync(ConfigKeys.WeixinPaySetting, json);

        // Assert
        Assert.Null(result);
    }

    [Fact]
    public async Task ValidateConfigAsync_WeixinPaySetting_WithInvalidPrefixLength_ReturnsError()
    {
        // Arrange
        var setting = new WeixinPaySetting
        {
            Merchants = new List<WeixinPayMerchant>
            {
                new() { Name = "商户1", MchId = "123", OrderPrefix = "AB" } // 只有2位
            }
        };
        var json = JsonSerializer.Serialize(setting);

        // Act
        var result = await _configService.ValidateConfigAsync(ConfigKeys.WeixinPaySetting, json);

        // Assert
        Assert.NotNull(result);
        Assert.Contains("3位字符", result);
    }

    [Fact]
    public async Task ValidateConfigAsync_WeixinPaySetting_WithDuplicatePrefixes_ReturnsError()
    {
        // Arrange
        var setting = new WeixinPaySetting
        {
            Merchants = new List<WeixinPayMerchant>
            {
                new() { Name = "商户1", MchId = "123", OrderPrefix = "ABC" },
                new() { Name = "商户2", MchId = "456", OrderPrefix = "ABC" } // 重复
            }
        };
        var json = JsonSerializer.Serialize(setting);

        // Act
        var result = await _configService.ValidateConfigAsync(ConfigKeys.WeixinPaySetting, json);

        // Assert
        Assert.NotNull(result);
        Assert.Contains("重复", result);
    }

    [Fact]
    public async Task ValidateConfigAsync_MiniprogramSetting_WithDefault_ReturnsNull()
    {
        // Arrange
        var setting = new MiniprogramSetting
        {
            Miniprograms = new List<MiniprogramConfig>
            {
                new() { Name = "小程序1", AppId = "wx123", IsDefault = 1, OrderPrefix = "AB" }
            }
        };
        var json = JsonSerializer.Serialize(setting);

        // Act
        var result = await _configService.ValidateConfigAsync(ConfigKeys.MiniprogramSetting, json);

        // Assert
        Assert.Null(result);
    }

    [Fact]
    public async Task ValidateConfigAsync_MiniprogramSetting_WithoutDefault_ReturnsError()
    {
        // Arrange
        var setting = new MiniprogramSetting
        {
            Miniprograms = new List<MiniprogramConfig>
            {
                new() { Name = "小程序1", AppId = "wx123", IsDefault = 0 }
            }
        };
        var json = JsonSerializer.Serialize(setting);

        // Act
        var result = await _configService.ValidateConfigAsync(ConfigKeys.MiniprogramSetting, json);

        // Assert
        Assert.NotNull(result);
        Assert.Contains("默认", result);
    }

    [Fact]
    public async Task ValidateConfigAsync_H5Setting_WithDefault_ReturnsNull()
    {
        // Arrange
        var setting = new H5Setting
        {
            H5Apps = new List<H5AppConfig>
            {
                new() { Name = "H5应用1", IsDefault = 1, OrderPrefix = "AB" }
            }
        };
        var json = JsonSerializer.Serialize(setting);

        // Act
        var result = await _configService.ValidateConfigAsync(ConfigKeys.H5Setting, json);

        // Assert
        Assert.Null(result);
    }

    [Fact]
    public async Task ValidateConfigAsync_H5Setting_WithoutDefault_ReturnsError()
    {
        // Arrange
        var setting = new H5Setting
        {
            H5Apps = new List<H5AppConfig>
            {
                new() { Name = "H5应用1", IsDefault = 0 }
            }
        };
        var json = JsonSerializer.Serialize(setting);

        // Act
        var result = await _configService.ValidateConfigAsync(ConfigKeys.H5Setting, json);

        // Assert
        Assert.NotNull(result);
        Assert.Contains("默认", result);
    }

    [Fact]
    public async Task ValidateConfigAsync_InvalidJson_ReturnsError()
    {
        // Act
        var result = await _configService.ValidateConfigAsync(ConfigKeys.Base, "invalid json {");

        // Assert
        Assert.NotNull(result);
        Assert.Contains("无效", result);
    }

    #endregion

    #region ClearConfigCacheAsync Tests

    [Fact]
    public async Task ClearConfigCacheAsync_CallsRedisDelete()
    {
        // Act
        await _configService.ClearConfigCacheAsync("test_key");

        // Assert
        _mockRedisService.Verify(x => x.DeleteAsync("config:test_key"), Times.Once);
    }

    #endregion
}
