using HoneyBox.Admin.Business.Controllers;
using HoneyBox.Admin.Business.Models;
using HoneyBox.Admin.Business.Models.DesignatedPrize;
using HoneyBox.Admin.Business.Services;
using HoneyBox.Admin.Business.Services.Interfaces;
using HoneyBox.Model.Data;
using HoneyBox.Model.Entities;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using Moq;
using Xunit;

namespace HoneyBox.Tests.Integration;

/// <summary>
/// DesignatedPrizeController API 集成测试
/// 测试完整 CRUD 流程和错误响应
/// Requirements: 4.1, 4.2, 4.3, 4.4, 4.5
/// </summary>
public class DesignatedPrizeControllerTests : IDisposable
{
    private readonly HoneyBoxDbContext _dbContext;
    private readonly IDesignatedPrizeService _service;
    private readonly DesignatedPrizeController _controller;

    public DesignatedPrizeControllerTests()
    {
        var options = new DbContextOptionsBuilder<HoneyBoxDbContext>()
            .UseInMemoryDatabase(databaseName: Guid.NewGuid().ToString())
            .Options;

        _dbContext = new HoneyBoxDbContext(options);
        var mockLogger = new Mock<ILogger<DesignatedPrizeService>>();
        _service = new DesignatedPrizeService(_dbContext, mockLogger.Object);
        _controller = new DesignatedPrizeController(_service);
    }

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

    #region GetList Tests (Requirements 4.2)

    /// <summary>
    /// 测试获取配置列表 - 成功返回配置
    /// Requirements: 4.2
    /// </summary>
    [Fact]
    public async Task GetList_WithExistingGoods_ReturnsConfigs()
    {
        // Arrange
        await SeedTestDataAsync();
        var goods = await _dbContext.Goods.FirstAsync();

        // Act
        var result = await _controller.GetList(goods.Id);

        // Assert
        var okResult = Assert.IsType<OkObjectResult>(result);
        var response = Assert.IsType<ApiResponse<List<DesignatedPrizeDto>>>(okResult.Value);
        Assert.Equal(0, response.Code);
        Assert.NotNull(response.Data);
        Assert.Single(response.Data);
    }

    /// <summary>
    /// 测试获取配置列表 - 商品不存在返回错误
    /// Requirements: 4.2
    /// </summary>
    [Fact]
    public async Task GetList_WithNonExistingGoods_ReturnsNotFoundError()
    {
        // Act
        var result = await _controller.GetList(99999);

        // Assert
        var okResult = Assert.IsType<OkObjectResult>(result);
        var response = Assert.IsType<ApiResponse>(okResult.Value);
        Assert.Equal(BusinessErrorCodes.NotFound, response.Code);
        Assert.Contains("盒子不存在", response.Message);
    }

    #endregion

    #region Create Tests (Requirements 4.1, 4.5)

    /// <summary>
    /// 测试创建配置 - 成功创建
    /// Requirements: 4.1
    /// </summary>
    [Fact]
    public async Task Create_WithValidRequest_ReturnsCreatedConfig()
    {
        // Arrange
        await SeedGoodsWithPrizesAndUsersAsync();
        var goods = await _dbContext.Goods.FirstAsync();
        var prize = await _dbContext.GoodsItems.FirstAsync(gi => gi.GoodsId == goods.Id);
        var user = await _dbContext.Users.FirstAsync();

        var request = new CreateDesignatedPrizeRequest
        {
            GoodsItemId = prize.Id,
            UserId = user.Id,
            Remark = "测试备注"
        };

        // Act
        var result = await _controller.Create(goods.Id, request);

        // Assert
        var okResult = Assert.IsType<OkObjectResult>(result);
        var response = Assert.IsType<ApiResponse<DesignatedPrizeDto>>(okResult.Value);
        Assert.Equal(0, response.Code);
        Assert.NotNull(response.Data);
        Assert.Equal(goods.Id, response.Data.GoodsId);
        Assert.Equal(prize.Id, response.Data.GoodsItemId);
        Assert.Equal(user.Id, response.Data.UserId);
    }

    /// <summary>
    /// 测试创建配置 - 商品不存在返回404
    /// Requirements: 4.1
    /// </summary>
    [Fact]
    public async Task Create_WithNonExistingGoods_ReturnsNotFoundError()
    {
        // Arrange
        var request = new CreateDesignatedPrizeRequest
        {
            GoodsItemId = 1,
            UserId = 1
        };

        // Act
        var result = await _controller.Create(99999, request);

        // Assert
        var okResult = Assert.IsType<OkObjectResult>(result);
        var response = Assert.IsType<ApiResponse>(okResult.Value);
        Assert.Equal(BusinessErrorCodes.NotFound, response.Code);
        Assert.Contains("盒子不存在", response.Message);
    }

    /// <summary>
    /// 测试创建配置 - 奖品不存在返回404
    /// Requirements: 4.1
    /// </summary>
    [Fact]
    public async Task Create_WithNonExistingPrize_ReturnsNotFoundError()
    {
        // Arrange
        await SeedGoodsWithPrizesAndUsersAsync();
        var goods = await _dbContext.Goods.FirstAsync();
        var user = await _dbContext.Users.FirstAsync();

        var request = new CreateDesignatedPrizeRequest
        {
            GoodsItemId = 99999,
            UserId = user.Id
        };

        // Act
        var result = await _controller.Create(goods.Id, request);

        // Assert
        var okResult = Assert.IsType<OkObjectResult>(result);
        var response = Assert.IsType<ApiResponse>(okResult.Value);
        Assert.Equal(BusinessErrorCodes.NotFound, response.Code);
        Assert.Contains("奖品不存在", response.Message);
    }

    /// <summary>
    /// 测试创建配置 - 用户不存在返回404
    /// Requirements: 4.1
    /// </summary>
    [Fact]
    public async Task Create_WithNonExistingUser_ReturnsNotFoundError()
    {
        // Arrange
        await SeedGoodsWithPrizesAndUsersAsync();
        var goods = await _dbContext.Goods.FirstAsync();
        var prize = await _dbContext.GoodsItems.FirstAsync(gi => gi.GoodsId == goods.Id);

        var request = new CreateDesignatedPrizeRequest
        {
            GoodsItemId = prize.Id,
            UserId = 99999
        };

        // Act
        var result = await _controller.Create(goods.Id, request);

        // Assert
        var okResult = Assert.IsType<OkObjectResult>(result);
        var response = Assert.IsType<ApiResponse>(okResult.Value);
        Assert.Equal(BusinessErrorCodes.NotFound, response.Code);
        Assert.Contains("用户不存在", response.Message);
    }

    /// <summary>
    /// 测试创建配置 - 重复配置返回400
    /// Requirements: 4.5
    /// </summary>
    [Fact]
    public async Task Create_WithDuplicateConfig_ReturnsConflictError()
    {
        // Arrange
        await SeedTestDataAsync();
        var existingConfig = await _dbContext.GoodsDesignatedPrizes.FirstAsync();
        var user = await _dbContext.Users.FirstAsync();

        var request = new CreateDesignatedPrizeRequest
        {
            GoodsItemId = existingConfig.GoodsItemId,
            UserId = user.Id
        };

        // Act
        var result = await _controller.Create(existingConfig.GoodsId, request);

        // Assert
        var okResult = Assert.IsType<OkObjectResult>(result);
        var response = Assert.IsType<ApiResponse>(okResult.Value);
        Assert.Equal(BusinessErrorCodes.Conflict, response.Code);
        Assert.Contains("该奖品已配置指定用户", response.Message);
    }

    #endregion

    #region Update Tests (Requirements 4.3)

    /// <summary>
    /// 测试更新配置 - 成功更新
    /// Requirements: 4.3
    /// </summary>
    [Fact]
    public async Task Update_WithValidRequest_ReturnsUpdatedConfig()
    {
        // Arrange
        await SeedTestDataAsync();
        var config = await _dbContext.GoodsDesignatedPrizes.FirstAsync();

        var request = new UpdateDesignatedPrizeRequest
        {
            IsActive = false,
            Remark = "更新后的备注"
        };

        // Act
        var result = await _controller.Update(config.GoodsId, config.Id, request);

        // Assert
        var okResult = Assert.IsType<OkObjectResult>(result);
        var response = Assert.IsType<ApiResponse<DesignatedPrizeDto>>(okResult.Value);
        Assert.Equal(0, response.Code);
        Assert.NotNull(response.Data);
        Assert.False(response.Data.IsActive);
        Assert.Equal("更新后的备注", response.Data.Remark);
    }

    /// <summary>
    /// 测试更新配置 - 配置不存在返回404
    /// Requirements: 4.3
    /// </summary>
    [Fact]
    public async Task Update_WithNonExistingConfig_ReturnsNotFoundError()
    {
        // Arrange
        var request = new UpdateDesignatedPrizeRequest
        {
            IsActive = false
        };

        // Act
        var result = await _controller.Update(1, 99999, request);

        // Assert
        var okResult = Assert.IsType<OkObjectResult>(result);
        var response = Assert.IsType<ApiResponse>(okResult.Value);
        Assert.Equal(BusinessErrorCodes.NotFound, response.Code);
        Assert.Contains("配置不存在", response.Message);
    }

    #endregion

    #region Delete Tests (Requirements 4.4)

    /// <summary>
    /// 测试删除配置 - 成功删除
    /// Requirements: 4.4
    /// </summary>
    [Fact]
    public async Task Delete_WithExistingConfig_ReturnsSuccess()
    {
        // Arrange
        await SeedTestDataAsync();
        var config = await _dbContext.GoodsDesignatedPrizes.FirstAsync();

        // Act
        var result = await _controller.Delete(config.GoodsId, config.Id);

        // Assert
        var okResult = Assert.IsType<OkObjectResult>(result);
        var response = Assert.IsType<ApiResponse>(okResult.Value);
        Assert.Equal(0, response.Code);
        Assert.Contains("删除成功", response.Message);

        // Verify deletion
        var deletedConfig = await _dbContext.GoodsDesignatedPrizes.FindAsync(config.Id);
        Assert.Null(deletedConfig);
    }

    /// <summary>
    /// 测试删除配置 - 配置不存在返回404
    /// Requirements: 4.4
    /// </summary>
    [Fact]
    public async Task Delete_WithNonExistingConfig_ReturnsNotFoundError()
    {
        // Act
        var result = await _controller.Delete(1, 99999);

        // Assert
        var okResult = Assert.IsType<OkObjectResult>(result);
        var response = Assert.IsType<ApiResponse>(okResult.Value);
        Assert.Equal(BusinessErrorCodes.NotFound, response.Code);
        Assert.Contains("配置不存在", response.Message);
    }

    #endregion

    #region Full CRUD Flow Test

    /// <summary>
    /// 测试完整 CRUD 流程
    /// Requirements: 4.1, 4.2, 4.3, 4.4
    /// </summary>
    [Fact]
    public async Task FullCrudFlow_WorksCorrectly()
    {
        // Arrange
        await SeedGoodsWithPrizesAndUsersAsync();
        var goods = await _dbContext.Goods.FirstAsync();
        var prize = await _dbContext.GoodsItems.FirstAsync(gi => gi.GoodsId == goods.Id);
        var user = await _dbContext.Users.FirstAsync();

        // Step 1: Create
        var createRequest = new CreateDesignatedPrizeRequest
        {
            GoodsItemId = prize.Id,
            UserId = user.Id,
            Remark = "初始备注"
        };
        var createResult = await _controller.Create(goods.Id, createRequest);
        var createResponse = Assert.IsType<ApiResponse<DesignatedPrizeDto>>(
            Assert.IsType<OkObjectResult>(createResult).Value);
        Assert.Equal(0, createResponse.Code);
        var configId = createResponse.Data!.Id;

        // Step 2: Read (List)
        var listResult = await _controller.GetList(goods.Id);
        var listResponse = Assert.IsType<ApiResponse<List<DesignatedPrizeDto>>>(
            Assert.IsType<OkObjectResult>(listResult).Value);
        Assert.Equal(0, listResponse.Code);
        Assert.Single(listResponse.Data!);
        Assert.Equal(configId, listResponse.Data[0].Id);

        // Step 3: Update
        var updateRequest = new UpdateDesignatedPrizeRequest
        {
            IsActive = false,
            Remark = "更新后的备注"
        };
        var updateResult = await _controller.Update(goods.Id, configId, updateRequest);
        var updateResponse = Assert.IsType<ApiResponse<DesignatedPrizeDto>>(
            Assert.IsType<OkObjectResult>(updateResult).Value);
        Assert.Equal(0, updateResponse.Code);
        Assert.False(updateResponse.Data!.IsActive);
        Assert.Equal("更新后的备注", updateResponse.Data.Remark);

        // Step 4: Delete
        var deleteResult = await _controller.Delete(goods.Id, configId);
        var deleteResponse = Assert.IsType<ApiResponse>(
            Assert.IsType<OkObjectResult>(deleteResult).Value);
        Assert.Equal(0, deleteResponse.Code);

        // Verify deletion
        var finalListResult = await _controller.GetList(goods.Id);
        var finalListResponse = Assert.IsType<ApiResponse<List<DesignatedPrizeDto>>>(
            Assert.IsType<OkObjectResult>(finalListResult).Value);
        Assert.Empty(finalListResponse.Data!);
    }

    #endregion

    #region Helper Methods

    private async Task SeedTestDataAsync()
    {
        var user = new User
        {
            OpenId = "test_openid",
            Uid = "test_uid",
            Nickname = "测试用户",
            HeadImg = "http://test.com/avatar.jpg",
            Mobile = "13800138000",
            CreatedAt = DateTime.Now,
            UpdatedAt = DateTime.Now
        };
        _dbContext.Users.Add(user);
        await _dbContext.SaveChangesAsync();

        var goods = new Good
        {
            Title = "测试商品",
            ImgUrl = "http://test.com/goods.jpg",
            ImgUrlDetail = "http://test.com/goods_detail.jpg",
            Price = 100,
            Type = 1,
            Status = 1,
            Stock = 100,
            CreatedAt = DateTime.Now,
            UpdatedAt = DateTime.Now
        };
        _dbContext.Goods.Add(goods);
        await _dbContext.SaveChangesAsync();

        var prize = new GoodsItem
        {
            GoodsId = goods.Id,
            Num = 1,
            Title = "A赏",
            ImgUrl = "http://test.com/prize.jpg",
            Stock = 1,
            SurplusStock = 1,
            Price = 500,
            Money = 300,
            ScMoney = 250,
            RealPro = 1,
            GoodsType = 1,
            PrizeCode = "PC001",
            CreatedAt = DateTime.Now,
            UpdatedAt = DateTime.Now
        };
        _dbContext.GoodsItems.Add(prize);
        await _dbContext.SaveChangesAsync();

        var config = new GoodsDesignatedPrize
        {
            GoodsId = goods.Id,
            GoodsItemId = prize.Id,
            UserId = user.Id,
            IsActive = true,
            Remark = "测试配置",
            CreatedAt = DateTime.Now
        };
        _dbContext.GoodsDesignatedPrizes.Add(config);
        await _dbContext.SaveChangesAsync();
    }

    private async Task SeedGoodsWithPrizesAndUsersAsync()
    {
        var user = new User
        {
            OpenId = "test_openid",
            Uid = "test_uid",
            Nickname = "测试用户",
            HeadImg = "http://test.com/avatar.jpg",
            Mobile = "13800138000",
            CreatedAt = DateTime.Now,
            UpdatedAt = DateTime.Now
        };
        _dbContext.Users.Add(user);
        await _dbContext.SaveChangesAsync();

        var goods = new Good
        {
            Title = "测试商品",
            ImgUrl = "http://test.com/goods.jpg",
            ImgUrlDetail = "http://test.com/goods_detail.jpg",
            Price = 100,
            Type = 1,
            Status = 1,
            Stock = 100,
            CreatedAt = DateTime.Now,
            UpdatedAt = DateTime.Now
        };
        _dbContext.Goods.Add(goods);
        await _dbContext.SaveChangesAsync();

        var prizes = new List<GoodsItem>
        {
            new()
            {
                GoodsId = goods.Id,
                Num = 1,
                Title = "A赏",
                ImgUrl = "http://test.com/prize1.jpg",
                Stock = 1,
                SurplusStock = 1,
                Price = 500,
                Money = 300,
                ScMoney = 250,
                RealPro = 1,
                GoodsType = 1,
                PrizeCode = "PC001",
                CreatedAt = DateTime.Now,
                UpdatedAt = DateTime.Now
            },
            new()
            {
                GoodsId = goods.Id,
                Num = 2,
                Title = "B赏",
                ImgUrl = "http://test.com/prize2.jpg",
                Stock = 5,
                SurplusStock = 5,
                Price = 200,
                Money = 100,
                ScMoney = 80,
                RealPro = 5,
                GoodsType = 1,
                PrizeCode = "PC002",
                CreatedAt = DateTime.Now,
                UpdatedAt = DateTime.Now
            }
        };
        _dbContext.GoodsItems.AddRange(prizes);
        await _dbContext.SaveChangesAsync();
    }

    #endregion
}
