using FsCheck;
using FsCheck.Xunit;
using Microsoft.EntityFrameworkCore;
using MilitaryTrainingManagement.Data;
using MilitaryTrainingManagement.Models.Entities;
using MilitaryTrainingManagement.Models.Enums;
using MilitaryTrainingManagement.Services.Implementations;

namespace MilitaryTrainingManagement.Tests.Properties;

/// <summary>
/// 工作流状态属性测试
/// **功能：military-training-material-management，属性5：工作流状态修改限制**
/// **验证需求：需求5.1, 5.5**
/// </summary>
public class WorkflowStatePropertyTests
{
    /// <summary>
    /// 创建内存数据库上下文
    /// </summary>
    private static ApplicationDbContext CreateInMemoryContext(string dbName)
    {
        var options = new DbContextOptionsBuilder<ApplicationDbContext>()
            .UseInMemoryDatabase(databaseName: dbName)
            .Options;
        return new ApplicationDbContext(options);
    }

    /// <summary>
    /// 创建测试用的组织层级结构和用户
    /// </summary>
    private static (Dictionary<OrganizationalLevel, OrganizationalUnit> hierarchy, 
                    Dictionary<OrganizationalLevel, UserAccount> users) 
        CreateHierarchyWithUsers(ApplicationDbContext context)
    {
        // 创建师团
        var division = new OrganizationalUnit
        {
            Name = "师团",
            Level = OrganizationalLevel.Division,
            CreatedAt = DateTime.UtcNow
        };
        context.OrganizationalUnits.Add(division);
        context.SaveChanges();

        // 创建团
        var regiment = new OrganizationalUnit
        {
            Name = "团",
            Level = OrganizationalLevel.Regiment,
            ParentId = division.Id,
            CreatedAt = DateTime.UtcNow
        };
        context.OrganizationalUnits.Add(regiment);
        context.SaveChanges();

        // 创建营
        var battalion = new OrganizationalUnit
        {
            Name = "营",
            Level = OrganizationalLevel.Battalion,
            ParentId = regiment.Id,
            CreatedAt = DateTime.UtcNow
        };
        context.OrganizationalUnits.Add(battalion);
        context.SaveChanges();


        // 创建连
        var company = new OrganizationalUnit
        {
            Name = "连",
            Level = OrganizationalLevel.Company,
            ParentId = battalion.Id,
            CreatedAt = DateTime.UtcNow
        };
        context.OrganizationalUnits.Add(company);
        context.SaveChanges();

        var hierarchy = new Dictionary<OrganizationalLevel, OrganizationalUnit>
        {
            { OrganizationalLevel.Division, division },
            { OrganizationalLevel.Regiment, regiment },
            { OrganizationalLevel.Battalion, battalion },
            { OrganizationalLevel.Company, company }
        };

        // 为每个层级创建用户
        var users = new Dictionary<OrganizationalLevel, UserAccount>();
        foreach (var kvp in hierarchy)
        {
            var user = new UserAccount
            {
                Username = $"user_{kvp.Key}",
                PasswordHash = "hash",
                DisplayName = $"{kvp.Key} User",
                OrganizationalUnitId = kvp.Value.Id,
                IsActive = true,
                CreatedAt = DateTime.UtcNow
            };
            context.UserAccounts.Add(user);
            context.SaveChanges();
            users[kvp.Key] = user;
        }

        return (hierarchy, users);
    }

    /// <summary>
    /// 属性5：工作流状态修改限制 - 已审批的上报记录不能直接修改
    /// *对于任何*已提交的报告或人员记录，一旦被上级组织层级批准，应阻止直接修改
    /// **验证需求：需求5.1, 5.5**
    /// </summary>
    [Property(MaxTest = 100)]
    public bool ApprovedReportCannotBeDirectlyModified(PositiveInt completionValue)
    {
        var dbName = Guid.NewGuid().ToString();
        using var context = CreateInMemoryContext(dbName);
        var (hierarchy, users) = CreateHierarchyWithUsers(context);
        var workflowService = new WorkflowService(context);

        // 创建物资配额
        var allocation = new MaterialAllocation
        {
            Category = "弹药",
            MaterialName = "测试物资",
            Unit = "发",
            TotalQuota = 1000,
            CreatedByUnitId = hierarchy[OrganizationalLevel.Division].Id,
            CreatedAt = DateTime.UtcNow
        };
        context.MaterialAllocations.Add(allocation);
        context.SaveChanges();

        // 创建已审批的分配记录
        var distribution = new AllocationDistribution
        {
            AllocationId = allocation.Id,
            TargetUnitId = hierarchy[OrganizationalLevel.Regiment].Id,
            UnitQuota = 500,
            ActualCompletion = completionValue.Get,
            ReportedAt = DateTime.UtcNow,
            ReportedByUserId = users[OrganizationalLevel.Regiment].Id,
            IsApproved = true,  // 已被上级审批
            ApprovedAt = DateTime.UtcNow,
            ApprovedByUserId = users[OrganizationalLevel.Division].Id
        };
        context.AllocationDistributions.Add(distribution);
        context.SaveChanges();

        // 检查记录是否被标记为已审批
        var isApproved = workflowService.IsRecordApprovedAsync(
            ApprovalRequestType.ReportModification, 
            distribution.Id).GetAwaiter().GetResult();

        // 已审批的记录应该返回true，表示不能直接修改
        return isApproved == true;
    }


    /// <summary>
    /// 属性5扩展：未审批的上报记录可以直接修改
    /// **验证需求：需求5.1**
    /// </summary>
    [Property(MaxTest = 100)]
    public bool UnapprovedReportCanBeModified(PositiveInt completionValue)
    {
        var dbName = Guid.NewGuid().ToString();
        using var context = CreateInMemoryContext(dbName);
        var (hierarchy, users) = CreateHierarchyWithUsers(context);
        var workflowService = new WorkflowService(context);

        // 创建物资配额
        var allocation = new MaterialAllocation
        {
            Category = "弹药",
            MaterialName = "测试物资",
            Unit = "发",
            TotalQuota = 1000,
            CreatedByUnitId = hierarchy[OrganizationalLevel.Division].Id,
            CreatedAt = DateTime.UtcNow
        };
        context.MaterialAllocations.Add(allocation);
        context.SaveChanges();

        // 创建未审批的分配记录
        var distribution = new AllocationDistribution
        {
            AllocationId = allocation.Id,
            TargetUnitId = hierarchy[OrganizationalLevel.Regiment].Id,
            UnitQuota = 500,
            ActualCompletion = completionValue.Get,
            ReportedAt = DateTime.UtcNow,
            ReportedByUserId = users[OrganizationalLevel.Regiment].Id,
            IsApproved = false  // 未被审批
        };
        context.AllocationDistributions.Add(distribution);
        context.SaveChanges();

        // 检查记录是否被标记为已审批
        var isApproved = workflowService.IsRecordApprovedAsync(
            ApprovalRequestType.ReportModification, 
            distribution.Id).GetAwaiter().GetResult();

        // 未审批的记录应该返回false，表示可以直接修改
        return isApproved == false;
    }

    /// <summary>
    /// 属性5扩展：只有师团级别用户可以审批请求
    /// **验证需求：需求5.3, 5.4**
    /// </summary>
    [Property(MaxTest = 100)]
    public bool OnlyDivisionLevelCanApprove(OrganizationalLevel userLevel)
    {
        var dbName = Guid.NewGuid().ToString();
        using var context = CreateInMemoryContext(dbName);
        var (hierarchy, users) = CreateHierarchyWithUsers(context);
        var workflowService = new WorkflowService(context);

        var user = users[userLevel];
        var canApprove = workflowService.CanUserApproveAsync(user.Id).GetAwaiter().GetResult();

        // 只有师团级别用户可以审批
        var expected = userLevel == OrganizationalLevel.Division;
        return canApprove == expected;
    }

    /// <summary>
    /// 属性5扩展：待处理请求只能被审批一次
    /// **验证需求：需求5.5**
    /// </summary>
    [Property(MaxTest = 100)]
    public bool PendingRequestCanOnlyBeApprovedOnce(PositiveInt completionValue)
    {
        var dbName = Guid.NewGuid().ToString();
        using var context = CreateInMemoryContext(dbName);
        var (hierarchy, users) = CreateHierarchyWithUsers(context);
        var workflowService = new WorkflowService(context);

        // 创建物资配额
        var allocation = new MaterialAllocation
        {
            Category = "弹药",
            MaterialName = "测试物资",
            Unit = "发",
            TotalQuota = 1000,
            CreatedByUnitId = hierarchy[OrganizationalLevel.Division].Id,
            CreatedAt = DateTime.UtcNow
        };
        context.MaterialAllocations.Add(allocation);
        context.SaveChanges();

        // 创建分配记录
        var distribution = new AllocationDistribution
        {
            AllocationId = allocation.Id,
            TargetUnitId = hierarchy[OrganizationalLevel.Regiment].Id,
            UnitQuota = 500,
            ActualCompletion = completionValue.Get,
            ReportedAt = DateTime.UtcNow,
            ReportedByUserId = users[OrganizationalLevel.Regiment].Id,
            IsApproved = false
        };
        context.AllocationDistributions.Add(distribution);
        context.SaveChanges();


        // 创建修改请求
        var request = workflowService.CreateModificationRequestAsync(
            ApprovalRequestType.ReportModification,
            distribution.Id,
            users[OrganizationalLevel.Regiment].Id,
            hierarchy[OrganizationalLevel.Regiment].Id,
            "测试修改原因",
            $"{{\"ActualCompletion\": {completionValue.Get}}}",
            $"{{\"ActualCompletion\": {completionValue.Get + 10}}}"
        ).GetAwaiter().GetResult();

        // 第一次审批应该成功
        var approvedRequest = workflowService.ApproveAsync(
            request.Id,
            users[OrganizationalLevel.Division].Id,
            "同意修改"
        ).GetAwaiter().GetResult();

        // 第二次审批应该失败
        var secondApprovalFailed = false;
        try
        {
            workflowService.ApproveAsync(
                request.Id,
                users[OrganizationalLevel.Division].Id,
                "再次审批"
            ).GetAwaiter().GetResult();
        }
        catch (InvalidOperationException)
        {
            secondApprovalFailed = true;
        }

        return approvedRequest.Status == ApprovalStatus.Approved && secondApprovalFailed;
    }

    /// <summary>
    /// 属性5扩展：同一记录不能有多个待处理的修改请求
    /// **验证需求：需求5.1**
    /// </summary>
    [Property(MaxTest = 100)]
    public bool CannotCreateDuplicatePendingRequests(PositiveInt completionValue)
    {
        var dbName = Guid.NewGuid().ToString();
        using var context = CreateInMemoryContext(dbName);
        var (hierarchy, users) = CreateHierarchyWithUsers(context);
        var workflowService = new WorkflowService(context);

        // 创建物资配额
        var allocation = new MaterialAllocation
        {
            Category = "弹药",
            MaterialName = "测试物资",
            Unit = "发",
            TotalQuota = 1000,
            CreatedByUnitId = hierarchy[OrganizationalLevel.Division].Id,
            CreatedAt = DateTime.UtcNow
        };
        context.MaterialAllocations.Add(allocation);
        context.SaveChanges();

        // 创建分配记录
        var distribution = new AllocationDistribution
        {
            AllocationId = allocation.Id,
            TargetUnitId = hierarchy[OrganizationalLevel.Regiment].Id,
            UnitQuota = 500,
            ActualCompletion = completionValue.Get,
            ReportedAt = DateTime.UtcNow,
            ReportedByUserId = users[OrganizationalLevel.Regiment].Id,
            IsApproved = false
        };
        context.AllocationDistributions.Add(distribution);
        context.SaveChanges();

        // 创建第一个修改请求
        var firstRequest = workflowService.CreateModificationRequestAsync(
            ApprovalRequestType.ReportModification,
            distribution.Id,
            users[OrganizationalLevel.Regiment].Id,
            hierarchy[OrganizationalLevel.Regiment].Id,
            "第一次修改",
            $"{{\"ActualCompletion\": {completionValue.Get}}}",
            $"{{\"ActualCompletion\": {completionValue.Get + 10}}}"
        ).GetAwaiter().GetResult();

        // 创建第二个修改请求应该失败
        var secondRequestFailed = false;
        try
        {
            workflowService.CreateModificationRequestAsync(
                ApprovalRequestType.ReportModification,
                distribution.Id,
                users[OrganizationalLevel.Regiment].Id,
                hierarchy[OrganizationalLevel.Regiment].Id,
                "第二次修改",
                $"{{\"ActualCompletion\": {completionValue.Get}}}",
                $"{{\"ActualCompletion\": {completionValue.Get + 20}}}"
            ).GetAwaiter().GetResult();
        }
        catch (InvalidOperationException)
        {
            secondRequestFailed = true;
        }

        return firstRequest != null && secondRequestFailed;
    }
}
