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

namespace HoneyBox.Tests.Integration;

/// <summary>
/// 任务服务集成测试
/// Requirements: 8.1-8.7
/// </summary>
public class TaskServiceIntegrationTests
{
    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 TaskService CreateTaskService(HoneyBoxDbContext dbContext)
    {
        var mockLogger = new Mock<ILogger<TaskService>>();
        return new TaskService(dbContext, mockLogger.Object);
    }

    private User CreateTestUser(int id, int? ouQi = 100)
    {
        return new User
        {
            Id = id,
            OpenId = $"openid_{Guid.NewGuid():N}",
            Uid = $"uid_{Guid.NewGuid():N}",
            Nickname = "测试用户",
            HeadImg = "",
            OuQi = ouQi,
            CreatedAt = DateTime.Now,
            UpdatedAt = DateTime.Now
        };
    }

    [Fact]
    public async Task GetTaskList_DailyTasks_ReturnsCorrectTasks()
    {
        var dbContext = CreateInMemoryDbContext();
        var service = CreateTaskService(dbContext);
        var userId = 1;

        await dbContext.Tasks.AddRangeAsync(new List<T_Task>
        {
            new() { Title = "每日签到", Type = 1, Cate = 1, Number = 1, ZNumber = 10, Sort = 1, CreatedAt = DateTime.Now, UpdatedAt = DateTime.Now },
            new() { Title = "每日抽赏", Type = 1, Cate = 2, Number = 3, ZNumber = 20, Sort = 2, CreatedAt = DateTime.Now, UpdatedAt = DateTime.Now },
            new() { Title = "每周任务", Type = 2, Cate = 1, Number = 5, ZNumber = 50, Sort = 1, CreatedAt = DateTime.Now, UpdatedAt = DateTime.Now }
        });
        await dbContext.SaveChangesAsync();

        var result = await service.GetTaskListAsync(userId, 1);
        Assert.Equal(2, result.TaskList.Count);
        Assert.All(result.TaskList, t => Assert.Equal(1, t.Type));
    }

    [Fact]
    public async Task GetTaskList_WeeklyTasks_ReturnsCorrectTasks()
    {
        var dbContext = CreateInMemoryDbContext();
        var service = CreateTaskService(dbContext);
        var userId = 1;

        await dbContext.Tasks.AddRangeAsync(new List<T_Task>
        {
            new() { Title = "每日签到", Type = 1, Cate = 1, Number = 1, ZNumber = 10, Sort = 1, CreatedAt = DateTime.Now, UpdatedAt = DateTime.Now },
            new() { Title = "每周邀请", Type = 2, Cate = 1, Number = 5, ZNumber = 50, Sort = 1, CreatedAt = DateTime.Now, UpdatedAt = DateTime.Now },
            new() { Title = "每周抽赏", Type = 2, Cate = 2, Number = 10, ZNumber = 100, Sort = 2, CreatedAt = DateTime.Now, UpdatedAt = DateTime.Now }
        });
        await dbContext.SaveChangesAsync();

        var result = await service.GetTaskListAsync(userId, 2);
        Assert.Equal(2, result.TaskList.Count);
        Assert.All(result.TaskList, t => Assert.Equal(2, t.Type));
    }

    [Fact]
    public async Task GetTaskList_InvitationTask_CalculatesProgressCorrectly()
    {
        var dbContext = CreateInMemoryDbContext();
        var service = CreateTaskService(dbContext);
        var userId = 1;

        var task = new T_Task { Title = "邀请好友", Type = 1, Cate = 1, Number = 3, ZNumber = 30, Sort = 1, CreatedAt = DateTime.Now, UpdatedAt = DateTime.Now };
        await dbContext.Tasks.AddAsync(task);

        // 创建被邀请用户 (今天注册)
        await dbContext.Users.AddRangeAsync(new List<User>
        {
            new() { Pid = userId, OpenId = $"openid_{Guid.NewGuid():N}", Uid = $"uid_{Guid.NewGuid():N}", Nickname = "用户1", HeadImg = "", CreatedAt = DateTime.Now, UpdatedAt = DateTime.Now },
            new() { Pid = userId, OpenId = $"openid_{Guid.NewGuid():N}", Uid = $"uid_{Guid.NewGuid():N}", Nickname = "用户2", HeadImg = "", CreatedAt = DateTime.Now, UpdatedAt = DateTime.Now }
        });
        await dbContext.SaveChangesAsync();

        var result = await service.GetTaskListAsync(userId, 1);
        var inviteTask = result.TaskList.First(t => t.Cate == 1);
        Assert.Equal(2, inviteTask.YwcCount);
        Assert.Equal(0, inviteTask.IsComplete);
        Assert.Equal(67, inviteTask.Percentage);
    }

    [Fact]
    public async Task GetTaskList_LotteryTask_CalculatesProgressCorrectly()
    {
        var dbContext = CreateInMemoryDbContext();
        var service = CreateTaskService(dbContext);
        var userId = 1;

        var task = new T_Task { Title = "每日抽赏", Type = 1, Cate = 2, Number = 3, ZNumber = 20, Sort = 1, CreatedAt = DateTime.Now, UpdatedAt = DateTime.Now };
        await dbContext.Tasks.AddAsync(task);

        var todayTimestamp = (int)((DateTimeOffset)DateTime.Today).ToUnixTimeSeconds();
        await dbContext.Orders.AddRangeAsync(new List<Order>
        {
            new() { UserId = userId, PayType = 1, Status = 1, Addtime = todayTimestamp, OrderNum = "ORD001", GoodsId = 1, GoodsTitle = "商品1", Price = 10, Num = 1, CreatedAt = DateTime.Now, UpdatedAt = DateTime.Now },
            new() { UserId = userId, PayType = 2, Status = 1, Addtime = todayTimestamp, OrderNum = "ORD002", GoodsId = 1, GoodsTitle = "商品2", Price = 20, Num = 1, CreatedAt = DateTime.Now, UpdatedAt = DateTime.Now },
            new() { UserId = userId, PayType = 1, Status = 1, Addtime = todayTimestamp, OrderNum = "ORD003", GoodsId = 1, GoodsTitle = "商品3", Price = 30, Num = 1, CreatedAt = DateTime.Now, UpdatedAt = DateTime.Now }
        });
        await dbContext.SaveChangesAsync();

        var result = await service.GetTaskListAsync(userId, 1);
        var lotteryTask = result.TaskList.First(t => t.Cate == 2);
        Assert.Equal(3, lotteryTask.YwcCount);
        Assert.Equal(1, lotteryTask.IsComplete);
        Assert.Equal(100, lotteryTask.Percentage);
    }

    [Fact]
    public async Task GetTaskList_AlreadyClaimed_ShowsClaimedStatus()
    {
        var dbContext = CreateInMemoryDbContext();
        var service = CreateTaskService(dbContext);
        var userId = 1;

        var task = new T_Task { Title = "每日签到", Type = 1, Cate = 1, Number = 1, ZNumber = 10, Sort = 1, CreatedAt = DateTime.Now, UpdatedAt = DateTime.Now };
        await dbContext.Tasks.AddAsync(task);
        await dbContext.SaveChangesAsync();

        var userTask = new UserTask { UserId = userId, TaskId = task.Id, Type = 1, Cate = 1, Number = 1, ZNumber = 10, CreatedAt = DateTime.Now, UpdatedAt = DateTime.Now };
        await dbContext.UserTasks.AddAsync(userTask);
        await dbContext.SaveChangesAsync();

        var result = await service.GetTaskListAsync(userId, 1);
        var claimedTask = result.TaskList.First();
        Assert.Equal(2, claimedTask.IsComplete);
    }

    [Fact]
    public async Task ClaimTaskReward_Success_AddsOuQiReward()
    {
        var dbContext = CreateInMemoryDbContext();
        var service = CreateTaskService(dbContext);
        var userId = 1;

        var user = CreateTestUser(userId, 100);
        await dbContext.Users.AddAsync(user);

        var task = new T_Task { Title = "邀请好友", Type = 1, Cate = 1, Number = 1, ZNumber = 50, Sort = 1, CreatedAt = DateTime.Now, UpdatedAt = DateTime.Now };
        await dbContext.Tasks.AddAsync(task);

        // 创建被邀请用户 - 使用不同的Id避免冲突
        var invitedUser = CreateTestUser(100, 0);
        invitedUser.Pid = userId;
        invitedUser.Nickname = "被邀请用户";
        await dbContext.Users.AddAsync(invitedUser);
        await dbContext.SaveChangesAsync();

        var result = await service.ClaimTaskRewardAsync(userId, task.Id);
        Assert.Equal(50, result.Reward);
        Assert.Equal(150, result.CurrentOuQi);

        var updatedUser = await dbContext.Users.FindAsync(userId);
        Assert.Equal(150, updatedUser!.OuQi);

        var profitOuQi = await dbContext.ProfitOuQis.FirstOrDefaultAsync(p => p.UserId == userId);
        Assert.NotNull(profitOuQi);
        Assert.Equal(50, profitOuQi.ChangeMoney);
    }

    [Fact]
    public async Task ClaimTaskReward_TaskNotComplete_ThrowsException()
    {
        var dbContext = CreateInMemoryDbContext();
        var service = CreateTaskService(dbContext);
        var userId = 1;

        var task = new T_Task { Title = "邀请好友", Type = 1, Cate = 1, Number = 3, ZNumber = 50, Sort = 1, CreatedAt = DateTime.Now, UpdatedAt = DateTime.Now };
        await dbContext.Tasks.AddAsync(task);

        // 只邀请了1人
        var invitedUser = new User { Pid = userId, OpenId = $"openid_{Guid.NewGuid():N}", Uid = $"uid_{Guid.NewGuid():N}", Nickname = "被邀请用户", HeadImg = "", CreatedAt = DateTime.Now, UpdatedAt = DateTime.Now };
        await dbContext.Users.AddAsync(invitedUser);
        await dbContext.SaveChangesAsync();

        var ex = await Assert.ThrowsAsync<InvalidOperationException>(() => service.ClaimTaskRewardAsync(userId, task.Id));
        Assert.Equal("任务未完成", ex.Message);
    }

    [Fact]
    public async Task ClaimTaskReward_AlreadyClaimed_ThrowsException()
    {
        var dbContext = CreateInMemoryDbContext();
        var service = CreateTaskService(dbContext);
        var userId = 1;

        var user = CreateTestUser(userId, 100);
        await dbContext.Users.AddAsync(user);

        var task = new T_Task { Title = "邀请好友", Type = 1, Cate = 1, Number = 1, ZNumber = 50, Sort = 1, CreatedAt = DateTime.Now, UpdatedAt = DateTime.Now };
        await dbContext.Tasks.AddAsync(task);

        // 创建被邀请用户 - 使用不同的Id避免冲突
        var invitedUser = CreateTestUser(100, 0);
        invitedUser.Pid = userId;
        invitedUser.Nickname = "被邀请用户";
        await dbContext.Users.AddAsync(invitedUser);

        var userTask = new UserTask { UserId = userId, TaskId = task.Id, Type = 1, Cate = 1, Number = 1, ZNumber = 50, CreatedAt = DateTime.Now, UpdatedAt = DateTime.Now };
        await dbContext.UserTasks.AddAsync(userTask);
        await dbContext.SaveChangesAsync();

        var ex = await Assert.ThrowsAsync<InvalidOperationException>(() => service.ClaimTaskRewardAsync(userId, task.Id));
        Assert.Equal("你已经领取过了", ex.Message);
    }

    [Fact]
    public async Task ClaimTaskReward_TaskNotFound_ThrowsException()
    {
        var dbContext = CreateInMemoryDbContext();
        var service = CreateTaskService(dbContext);
        var userId = 1;

        var ex = await Assert.ThrowsAsync<InvalidOperationException>(() => service.ClaimTaskRewardAsync(userId, 999));
        Assert.Equal("任务不存在", ex.Message);
    }

    [Fact]
    public async Task GetTaskList_WeeklyTask_OnlyCountsCurrentWeek()
    {
        var dbContext = CreateInMemoryDbContext();
        var service = CreateTaskService(dbContext);
        var userId = 1;

        var task = new T_Task { Title = "每周邀请", Type = 2, Cate = 1, Number = 3, ZNumber = 100, Sort = 1, CreatedAt = DateTime.Now, UpdatedAt = DateTime.Now };
        await dbContext.Tasks.AddAsync(task);

        // 本周邀请的用户
        var thisWeekUser = new User { Pid = userId, OpenId = $"openid_{Guid.NewGuid():N}", Uid = $"uid_{Guid.NewGuid():N}", Nickname = "本周用户", HeadImg = "", CreatedAt = DateTime.Now, UpdatedAt = DateTime.Now };
        await dbContext.Users.AddAsync(thisWeekUser);

        // 上周邀请的用户 (不应计入)
        var lastWeekUser = new User { Pid = userId, OpenId = $"openid_{Guid.NewGuid():N}", Uid = $"uid_{Guid.NewGuid():N}", Nickname = "上周用户", HeadImg = "", CreatedAt = DateTime.Now.AddDays(-10), UpdatedAt = DateTime.Now.AddDays(-10) };
        await dbContext.Users.AddAsync(lastWeekUser);
        await dbContext.SaveChangesAsync();

        var result = await service.GetTaskListAsync(userId, 2);
        var weeklyTask = result.TaskList.First();
        Assert.Equal(1, weeklyTask.YwcCount);
    }

    [Fact]
    public async Task GetTaskList_DeletedTasks_NotReturned()
    {
        var dbContext = CreateInMemoryDbContext();
        var service = CreateTaskService(dbContext);
        var userId = 1;

        await dbContext.Tasks.AddRangeAsync(new List<T_Task>
        {
            new() { Title = "正常任务", Type = 1, Cate = 1, Number = 1, ZNumber = 10, Sort = 1, CreatedAt = DateTime.Now, UpdatedAt = DateTime.Now },
            new() { Title = "已删除任务", Type = 1, Cate = 2, Number = 3, ZNumber = 20, Sort = 2, DeletedAt = DateTime.Now, CreatedAt = DateTime.Now, UpdatedAt = DateTime.Now }
        });
        await dbContext.SaveChangesAsync();

        var result = await service.GetTaskListAsync(userId, 1);
        Assert.Single(result.TaskList);
        Assert.Equal("正常任务", result.TaskList[0].Title);
    }
}
