using HoneyBox.Core.Services;
using HoneyBox.Model.Data;
using HoneyBox.Model.Entities;
using HoneyBox.Model.Models.Payment;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Diagnostics;
using Microsoft.Extensions.Logging;
using Moq;
using Xunit;

namespace HoneyBox.Tests.Integration;

/// <summary>
/// 支付服务集成测试
/// 测试余额扣减、积分扣减、哈尼券扣减和混合支付
/// Requirements: 3.1-6.7
/// </summary>
public class PaymentServiceIntegrationTests
{
    private readonly Mock<ILogger<PaymentService>> _mockLogger;

    public PaymentServiceIntegrationTests()
    {
        _mockLogger = new Mock<ILogger<PaymentService>>();
    }

    private HoneyBoxDbContext CreateInMemoryDbContext()
    {
        var options = new DbContextOptionsBuilder<HoneyBoxDbContext>()
            .UseInMemoryDatabase(databaseName: Guid.NewGuid().ToString())
            .ConfigureWarnings(w => w.Ignore(InMemoryEventId.TransactionIgnoredWarning))
            .Options;

        return new HoneyBoxDbContext(options);
    }

    private PaymentService CreatePaymentService(HoneyBoxDbContext dbContext)
    {
        return new PaymentService(dbContext, _mockLogger.Object);
    }

    private async Task<User> CreateTestUserAsync(
        HoneyBoxDbContext dbContext, 
        decimal money = 100, 
        decimal integral = 1000, 
        decimal money2 = 500)
    {
        var user = new User
        {
            Id = 1,
            OpenId = "test_openid_123456",
            Uid = "test_uid",
            Nickname = "测试用户",
            HeadImg = "avatar.jpg",
            Mobile = "13800138000",
            Money = money,
            Integral = integral,
            Money2 = money2,
            IsTest = 0,
            Status = 1,
            CreatedAt = DateTime.Now,
            UpdatedAt = DateTime.Now
        };
        await dbContext.Users.AddAsync(user);
        await dbContext.SaveChangesAsync();
        return user;
    }

    #region 余额扣减测试 (Requirements 3.1-3.5)

    /// <summary>
    /// 测试余额扣减 - 成功扣减
    /// Requirements: 3.3, 3.4
    /// </summary>
    [Fact]
    public async Task DeductBalanceAsync_SufficientBalance_DeductsSuccessfully()
    {
        // Arrange
        var dbContext = CreateInMemoryDbContext();
        var user = await CreateTestUserAsync(dbContext, money: 100);
        var service = CreatePaymentService(dbContext);

        // Act
        var result = await service.DeductBalanceAsync(user.Id, 30, "测试扣减", "TST_ORDER_001");

        // Assert
        Assert.True(result.Success);
        Assert.Equal(70, result.RemainingBalance);

        // Verify user balance updated
        var updatedUser = await dbContext.Users.FindAsync(user.Id);
        Assert.NotNull(updatedUser);
        Assert.Equal(70, updatedUser.Money);

        // Verify profit_money record created
        var profitRecord = await dbContext.ProfitMoneys.FirstOrDefaultAsync(p => p.UserId == user.Id);
        Assert.NotNull(profitRecord);
        Assert.Equal(-30, profitRecord.ChangeMoney);
        Assert.Equal(70, profitRecord.Money);
    }

    /// <summary>
    /// 测试余额扣减 - 余额不足
    /// Requirements: 3.2
    /// </summary>
    [Fact]
    public async Task DeductBalanceAsync_InsufficientBalance_ReturnsFalse()
    {
        // Arrange
        var dbContext = CreateInMemoryDbContext();
        var user = await CreateTestUserAsync(dbContext, money: 20);
        var service = CreatePaymentService(dbContext);

        // Act
        var result = await service.DeductBalanceAsync(user.Id, 50, "测试扣减");

        // Assert
        Assert.False(result.Success);
        Assert.Contains("不足", result.Message);

        // Verify user balance unchanged
        var updatedUser = await dbContext.Users.FindAsync(user.Id);
        Assert.NotNull(updatedUser);
        Assert.Equal(20, updatedUser.Money);
    }

    /// <summary>
    /// 测试余额扣减 - 用户不存在
    /// Requirements: 3.1
    /// </summary>
    [Fact]
    public async Task DeductBalanceAsync_UserNotFound_ReturnsFalse()
    {
        // Arrange
        var dbContext = CreateInMemoryDbContext();
        var service = CreatePaymentService(dbContext);

        // Act
        var result = await service.DeductBalanceAsync(999, 30, "测试扣减");

        // Assert
        Assert.False(result.Success);
        Assert.Contains("用户不存在", result.Message);
    }

    /// <summary>
    /// 测试余额扣减 - 零金额
    /// Requirements: 3.3
    /// </summary>
    [Fact]
    public async Task DeductBalanceAsync_ZeroAmount_ReturnsSuccess()
    {
        // Arrange
        var dbContext = CreateInMemoryDbContext();
        var user = await CreateTestUserAsync(dbContext, money: 100);
        var service = CreatePaymentService(dbContext);

        // Act
        var result = await service.DeductBalanceAsync(user.Id, 0, "测试扣减");

        // Assert
        Assert.True(result.Success);
        Assert.Contains("无需扣减", result.Message);
    }

    /// <summary>
    /// 测试余额扣减 - 精确计算
    /// Requirements: 3.3, 3.4
    /// </summary>
    [Fact]
    public async Task DeductBalanceAsync_PreciseCalculation_CalculatesCorrectly()
    {
        // Arrange
        var dbContext = CreateInMemoryDbContext();
        var user = await CreateTestUserAsync(dbContext, money: 100.50m);
        var service = CreatePaymentService(dbContext);

        // Act
        var result = await service.DeductBalanceAsync(user.Id, 30.25m, "测试扣减");

        // Assert
        Assert.True(result.Success);
        Assert.Equal(70.25m, result.RemainingBalance);

        var updatedUser = await dbContext.Users.FindAsync(user.Id);
        Assert.NotNull(updatedUser);
        Assert.Equal(70.25m, updatedUser.Money);
    }

    #endregion

    #region 积分扣减测试 (Requirements 4.1-4.5)

    /// <summary>
    /// 测试积分扣减 - 成功扣减
    /// Requirements: 4.3, 4.4
    /// </summary>
    [Fact]
    public async Task DeductIntegralAsync_SufficientIntegral_DeductsSuccessfully()
    {
        // Arrange
        var dbContext = CreateInMemoryDbContext();
        var user = await CreateTestUserAsync(dbContext, integral: 1000);
        var service = CreatePaymentService(dbContext);

        // Act
        var result = await service.DeductIntegralAsync(user.Id, 300, "测试扣减", "TST_ORDER_001");

        // Assert
        Assert.True(result.Success);
        Assert.Equal(700, result.RemainingBalance);

        // Verify user integral updated
        var updatedUser = await dbContext.Users.FindAsync(user.Id);
        Assert.NotNull(updatedUser);
        Assert.Equal(700, updatedUser.Integral);

        // Verify profit_integral record created
        var profitRecord = await dbContext.ProfitIntegrals.FirstOrDefaultAsync(p => p.UserId == user.Id);
        Assert.NotNull(profitRecord);
        Assert.Equal(-300, profitRecord.ChangeMoney);
    }

    /// <summary>
    /// 测试积分扣减 - 积分不足
    /// Requirements: 4.2
    /// </summary>
    [Fact]
    public async Task DeductIntegralAsync_InsufficientIntegral_ReturnsFalse()
    {
        // Arrange
        var dbContext = CreateInMemoryDbContext();
        var user = await CreateTestUserAsync(dbContext, integral: 200);
        var service = CreatePaymentService(dbContext);

        // Act
        var result = await service.DeductIntegralAsync(user.Id, 500, "测试扣减");

        // Assert
        Assert.False(result.Success);
        Assert.Contains("不足", result.Message);
    }

    /// <summary>
    /// 测试积分扣减 - 用户不存在
    /// Requirements: 4.1
    /// </summary>
    [Fact]
    public async Task DeductIntegralAsync_UserNotFound_ReturnsFalse()
    {
        // Arrange
        var dbContext = CreateInMemoryDbContext();
        var service = CreatePaymentService(dbContext);

        // Act
        var result = await service.DeductIntegralAsync(999, 300, "测试扣减");

        // Assert
        Assert.False(result.Success);
        Assert.Contains("用户不存在", result.Message);
    }

    #endregion

    #region 哈尼券扣减测试 (Requirements 5.1-5.4)

    /// <summary>
    /// 测试哈尼券扣减 - 成功扣减
    /// Requirements: 5.3, 5.4
    /// </summary>
    [Fact]
    public async Task DeductMoney2Async_SufficientMoney2_DeductsSuccessfully()
    {
        // Arrange
        var dbContext = CreateInMemoryDbContext();
        var user = await CreateTestUserAsync(dbContext, money2: 500);
        var service = CreatePaymentService(dbContext);

        // Act
        var result = await service.DeductMoney2Async(user.Id, 200, "测试扣减", "TST_ORDER_001");

        // Assert
        Assert.True(result.Success);
        Assert.Equal(300, result.RemainingBalance);

        // Verify user money2 updated
        var updatedUser = await dbContext.Users.FindAsync(user.Id);
        Assert.NotNull(updatedUser);
        Assert.Equal(300, updatedUser.Money2);

        // Verify profit_money2 record created
        var profitRecord = await dbContext.ProfitMoney2s.FirstOrDefaultAsync(p => p.UserId == user.Id);
        Assert.NotNull(profitRecord);
        Assert.Equal(-200, profitRecord.ChangeMoney);
    }

    /// <summary>
    /// 测试哈尼券扣减 - 哈尼券不足
    /// Requirements: 5.2
    /// </summary>
    [Fact]
    public async Task DeductMoney2Async_InsufficientMoney2_ReturnsFalse()
    {
        // Arrange
        var dbContext = CreateInMemoryDbContext();
        var user = await CreateTestUserAsync(dbContext, money2: 100);
        var service = CreatePaymentService(dbContext);

        // Act
        var result = await service.DeductMoney2Async(user.Id, 300, "测试扣减");

        // Assert
        Assert.False(result.Success);
        Assert.Contains("不足", result.Message);
    }

    /// <summary>
    /// 测试哈尼券扣减 - 用户不存在
    /// Requirements: 5.1
    /// </summary>
    [Fact]
    public async Task DeductMoney2Async_UserNotFound_ReturnsFalse()
    {
        // Arrange
        var dbContext = CreateInMemoryDbContext();
        var service = CreatePaymentService(dbContext);

        // Act
        var result = await service.DeductMoney2Async(999, 200, "测试扣减");

        // Assert
        Assert.False(result.Success);
        Assert.Contains("用户不存在", result.Message);
    }

    #endregion

    #region 资产增加测试

    /// <summary>
    /// 测试余额增加 - 成功增加
    /// </summary>
    [Fact]
    public async Task AddBalanceAsync_ValidAmount_AddsSuccessfully()
    {
        // Arrange
        var dbContext = CreateInMemoryDbContext();
        var user = await CreateTestUserAsync(dbContext, money: 100);
        var service = CreatePaymentService(dbContext);

        // Act
        var result = await service.AddBalanceAsync(user.Id, 50, "充值", "TST_RECHARGE_001");

        // Assert
        Assert.True(result);

        var updatedUser = await dbContext.Users.FindAsync(user.Id);
        Assert.NotNull(updatedUser);
        Assert.Equal(150, updatedUser.Money);
    }

    /// <summary>
    /// 测试积分增加 - 成功增加
    /// </summary>
    [Fact]
    public async Task AddIntegralAsync_ValidAmount_AddsSuccessfully()
    {
        // Arrange
        var dbContext = CreateInMemoryDbContext();
        var user = await CreateTestUserAsync(dbContext, integral: 1000);
        var service = CreatePaymentService(dbContext);

        // Act
        var result = await service.AddIntegralAsync(user.Id, 500, "奖励", "TST_REWARD_001");

        // Assert
        Assert.True(result);

        var updatedUser = await dbContext.Users.FindAsync(user.Id);
        Assert.NotNull(updatedUser);
        Assert.Equal(1500, updatedUser.Integral);
    }

    /// <summary>
    /// 测试哈尼券增加 - 成功增加
    /// </summary>
    [Fact]
    public async Task AddMoney2Async_ValidAmount_AddsSuccessfully()
    {
        // Arrange
        var dbContext = CreateInMemoryDbContext();
        var user = await CreateTestUserAsync(dbContext, money2: 500);
        var service = CreatePaymentService(dbContext);

        // Act
        var result = await service.AddMoney2Async(user.Id, 200, "推荐奖励", "TST_INVITE_001");

        // Assert
        Assert.True(result);

        var updatedUser = await dbContext.Users.FindAsync(user.Id);
        Assert.NotNull(updatedUser);
        Assert.Equal(700, updatedUser.Money2);
    }

    #endregion

    #region 混合支付测试 (Requirements 6.1-6.7)

    /// <summary>
    /// 测试混合支付 - 余额+积分+哈尼券组合扣减
    /// Requirements: 6.1-6.4
    /// </summary>
    [Fact]
    public async Task MixedPayment_AllAssets_DeductsInOrder()
    {
        // Arrange
        var dbContext = CreateInMemoryDbContext();
        var user = await CreateTestUserAsync(dbContext, money: 50, integral: 1000, money2: 500);
        var service = CreatePaymentService(dbContext);

        // Act - Simulate mixed payment order: balance -> integral -> money2
        var balanceResult = await service.DeductBalanceAsync(user.Id, 30, "购买商品", "TST_ORDER_001");
        var integralResult = await service.DeductIntegralAsync(user.Id, 500, "购买商品", "TST_ORDER_001");
        var money2Result = await service.DeductMoney2Async(user.Id, 200, "购买商品", "TST_ORDER_001");

        // Assert
        Assert.True(balanceResult.Success);
        Assert.True(integralResult.Success);
        Assert.True(money2Result.Success);

        var updatedUser = await dbContext.Users.FindAsync(user.Id);
        Assert.NotNull(updatedUser);
        Assert.Equal(20, updatedUser.Money);      // 50 - 30 = 20
        Assert.Equal(500, updatedUser.Integral);  // 1000 - 500 = 500
        Assert.Equal(300, updatedUser.Money2);    // 500 - 200 = 300
    }

    /// <summary>
    /// 测试混合支付 - 部分资产不足时继续其他扣减
    /// Requirements: 6.5
    /// </summary>
    [Fact]
    public async Task MixedPayment_PartialInsufficientBalance_ContinuesWithOthers()
    {
        // Arrange
        var dbContext = CreateInMemoryDbContext();
        var user = await CreateTestUserAsync(dbContext, money: 10, integral: 1000, money2: 500);
        var service = CreatePaymentService(dbContext);

        // Act - Try to deduct more balance than available, then use integral
        var balanceResult = await service.DeductBalanceAsync(user.Id, 50, "购买商品", "TST_ORDER_001");
        var integralResult = await service.DeductIntegralAsync(user.Id, 500, "购买商品", "TST_ORDER_001");

        // Assert
        Assert.False(balanceResult.Success); // Balance insufficient
        Assert.True(integralResult.Success); // Integral deduction succeeds

        var updatedUser = await dbContext.Users.FindAsync(user.Id);
        Assert.NotNull(updatedUser);
        Assert.Equal(10, updatedUser.Money);      // Unchanged
        Assert.Equal(500, updatedUser.Integral);  // 1000 - 500 = 500
    }

    /// <summary>
    /// 测试混合支付 - 全额资产支付（无需微信支付）
    /// Requirements: 6.6
    /// </summary>
    [Fact]
    public async Task MixedPayment_FullAssetPayment_NoWechatNeeded()
    {
        // Arrange
        var dbContext = CreateInMemoryDbContext();
        // Total order: 30元
        // Balance: 10元, Integral: 1000 (=10元), Money2: 1000 (=10元)
        var user = await CreateTestUserAsync(dbContext, money: 10, integral: 1000, money2: 1000);
        var service = CreatePaymentService(dbContext);

        // Act - Deduct all assets to cover 30元 order
        var balanceResult = await service.DeductBalanceAsync(user.Id, 10, "购买商品", "TST_ORDER_001");
        var integralResult = await service.DeductIntegralAsync(user.Id, 1000, "购买商品", "TST_ORDER_001");
        var money2Result = await service.DeductMoney2Async(user.Id, 1000, "购买商品", "TST_ORDER_001");

        // Assert - All deductions successful
        Assert.True(balanceResult.Success);
        Assert.True(integralResult.Success);
        Assert.True(money2Result.Success);

        var updatedUser = await dbContext.Users.FindAsync(user.Id);
        Assert.NotNull(updatedUser);
        Assert.Equal(0, updatedUser.Money);
        Assert.Equal(0, updatedUser.Integral);
        Assert.Equal(0, updatedUser.Money2);
    }

    #endregion

    #region 支付记录测试 (Requirements 8.1-8.3)

    /// <summary>
    /// 测试支付记录 - 创建记录
    /// Requirements: 8.1, 8.2
    /// </summary>
    [Fact]
    public async Task RecordPaymentAsync_ValidData_CreatesRecord()
    {
        // Arrange
        var dbContext = CreateInMemoryDbContext();
        var user = await CreateTestUserAsync(dbContext);
        var service = CreatePaymentService(dbContext);

        // Act
        var result = await service.RecordPaymentAsync(
            user.Id, 
            "TST_ORDER_001", 
            30.00m, 
            PaymentType.WechatPay, 
            "微信支付");

        // Assert
        Assert.True(result);

        var record = await dbContext.ProfitPays.FirstOrDefaultAsync(p => p.OrderNum == "TST_ORDER_001");
        Assert.NotNull(record);
        Assert.Equal(user.Id, record.UserId);
        Assert.Equal(30.00m, record.ChangeMoney);
        Assert.Equal((byte)PaymentType.WechatPay, record.PayType);
    }

    /// <summary>
    /// 测试支付记录 - 查询记录
    /// Requirements: 8.3
    /// </summary>
    [Fact]
    public async Task GetPaymentRecordsAsync_HasRecords_ReturnsRecords()
    {
        // Arrange
        var dbContext = CreateInMemoryDbContext();
        var user = await CreateTestUserAsync(dbContext);
        var service = CreatePaymentService(dbContext);

        // Create some payment records
        await service.RecordPaymentAsync(user.Id, "TST_ORDER_001", 30.00m, PaymentType.WechatPay, "微信支付");
        await service.RecordPaymentAsync(user.Id, "TST_ORDER_002", 20.00m, PaymentType.BalancePay, "余额支付");

        // Act
        var records = await service.GetPaymentRecordsAsync(user.Id);

        // Assert
        Assert.Equal(2, records.Count);
    }

    /// <summary>
    /// 测试支付记录 - 检查订单是否有支付记录
    /// Requirements: 8.1
    /// </summary>
    [Fact]
    public async Task HasPaymentRecordAsync_RecordExists_ReturnsTrue()
    {
        // Arrange
        var dbContext = CreateInMemoryDbContext();
        var user = await CreateTestUserAsync(dbContext);
        var service = CreatePaymentService(dbContext);

        await service.RecordPaymentAsync(user.Id, "TST_ORDER_001", 30.00m, PaymentType.WechatPay, "微信支付");

        // Act
        var hasRecord = await service.HasPaymentRecordAsync("TST_ORDER_001");
        var noRecord = await service.HasPaymentRecordAsync("TST_ORDER_999");

        // Assert
        Assert.True(hasRecord);
        Assert.False(noRecord);
    }

    /// <summary>
    /// 测试支付记录 - 根据订单号获取记录
    /// Requirements: 8.3
    /// </summary>
    [Fact]
    public async Task GetPaymentRecordByOrderNumAsync_RecordExists_ReturnsRecord()
    {
        // Arrange
        var dbContext = CreateInMemoryDbContext();
        var user = await CreateTestUserAsync(dbContext);
        var service = CreatePaymentService(dbContext);

        await service.RecordPaymentAsync(user.Id, "TST_ORDER_001", 30.00m, PaymentType.WechatPay, "微信支付");

        // Act
        var record = await service.GetPaymentRecordByOrderNumAsync("TST_ORDER_001");

        // Assert
        Assert.NotNull(record);
        Assert.Equal("TST_ORDER_001", record.OrderNum);
        Assert.Equal("30.00", record.ChangeMoney);
        Assert.Equal("微信支付", record.PayTypeText);
    }

    #endregion

    #region 余额验证测试

    /// <summary>
    /// 测试余额验证 - 余额充足
    /// </summary>
    [Fact]
    public async Task ValidateBalanceAsync_SufficientBalance_ReturnsTrue()
    {
        // Arrange
        var dbContext = CreateInMemoryDbContext();
        var user = await CreateTestUserAsync(dbContext, money: 100);
        var service = CreatePaymentService(dbContext);

        // Act
        var result = await service.ValidateBalanceAsync(user.Id, 50);

        // Assert
        Assert.True(result);
    }

    /// <summary>
    /// 测试余额验证 - 余额不足
    /// </summary>
    [Fact]
    public async Task ValidateBalanceAsync_InsufficientBalance_ReturnsFalse()
    {
        // Arrange
        var dbContext = CreateInMemoryDbContext();
        var user = await CreateTestUserAsync(dbContext, money: 30);
        var service = CreatePaymentService(dbContext);

        // Act
        var result = await service.ValidateBalanceAsync(user.Id, 50);

        // Assert
        Assert.False(result);
    }

    /// <summary>
    /// 测试积分验证 - 积分充足
    /// </summary>
    [Fact]
    public async Task ValidateIntegralAsync_SufficientIntegral_ReturnsTrue()
    {
        // Arrange
        var dbContext = CreateInMemoryDbContext();
        var user = await CreateTestUserAsync(dbContext, integral: 1000);
        var service = CreatePaymentService(dbContext);

        // Act
        var result = await service.ValidateIntegralAsync(user.Id, 500);

        // Assert
        Assert.True(result);
    }

    /// <summary>
    /// 测试哈尼券验证 - 哈尼券充足
    /// </summary>
    [Fact]
    public async Task ValidateMoney2Async_SufficientMoney2_ReturnsTrue()
    {
        // Arrange
        var dbContext = CreateInMemoryDbContext();
        var user = await CreateTestUserAsync(dbContext, money2: 500);
        var service = CreatePaymentService(dbContext);

        // Act
        var result = await service.ValidateMoney2Async(user.Id, 300);

        // Assert
        Assert.True(result);
    }

    #endregion
}
