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，属性8：自动数据分发**
/// **验证需求：需求2.4**
/// </summary>
public class AllocationDistributionPropertyTests
{
    /// <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> CreateHierarchy(
        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();

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

    /// <summary>
    /// 属性8：自动数据分发
    /// *对于任何*创建的配额，应自动为所有指定的目标组织单位创建分配记录
    /// **验证需求：需求2.4**
    /// </summary>
    [Property(MaxTest = 100)]
    public bool CreateAllocation_AutomaticallyCreatesDistributionRecords(
        PositiveInt totalQuotaInt,
        PositiveInt quota1Int,
        PositiveInt quota2Int)
    {
        var dbName = Guid.NewGuid().ToString();
        using var context = CreateInMemoryContext(dbName);
        var hierarchy = CreateHierarchy(context);
        var organizationService = new OrganizationService(context);
        var allocationService = new AllocationService(context, organizationService);

        var totalQuota = (decimal)(totalQuotaInt.Get * 100);
        var quota1 = (decimal)(quota1Int.Get % 30 + 1);
        var quota2 = (decimal)(quota2Int.Get % 30 + 1);

        // 确保配额有效
        if (quota1 + quota2 > totalQuota)
        {
            var scale = totalQuota / (quota1 + quota2) * 0.9m;
            quota1 = Math.Floor(quota1 * scale);
            quota2 = Math.Floor(quota2 * scale);
        }

        var regiment = hierarchy[OrganizationalLevel.Regiment];
        var battalion = hierarchy[OrganizationalLevel.Battalion];
        var division = hierarchy[OrganizationalLevel.Division];

        var distributions = new Dictionary<int, decimal>
        {
            { regiment.Id, quota1 },
            { battalion.Id, quota2 }
        };

        // 创建配额
        var allocation = allocationService.CreateAsync(
            "测试类别",
            "测试物资",
            "件",
            totalQuota,
            division.Id,
            distributions
        ).GetAwaiter().GetResult();

        // 验证：为每个目标单位自动创建了分配记录
        var createdDistributions = context.AllocationDistributions
            .Where(d => d.AllocationId == allocation.Id)
            .ToList();

        // 检查分配记录数量是否正确
        if (createdDistributions.Count != distributions.Count)
            return false;

        // 检查每个目标单位都有对应的分配记录
        foreach (var (targetUnitId, expectedQuota) in distributions)
        {
            var distribution = createdDistributions.FirstOrDefault(d => d.TargetUnitId == targetUnitId);
            if (distribution == null)
                return false;
            if (distribution.UnitQuota != expectedQuota)
                return false;
        }

        return true;
    }


    /// <summary>
    /// 属性8扩展：分配记录与配额正确关联
    /// **验证需求：需求2.4**
    /// </summary>
    [Property(MaxTest = 100)]
    public bool DistributionRecords_AreCorrectlyLinkedToAllocation(
        PositiveInt totalQuotaInt,
        PositiveInt quotaInt)
    {
        var dbName = Guid.NewGuid().ToString();
        using var context = CreateInMemoryContext(dbName);
        var hierarchy = CreateHierarchy(context);
        var organizationService = new OrganizationService(context);
        var allocationService = new AllocationService(context, organizationService);

        var totalQuota = (decimal)(totalQuotaInt.Get * 10);
        var quota = Math.Min((decimal)quotaInt.Get, totalQuota);

        var regiment = hierarchy[OrganizationalLevel.Regiment];
        var division = hierarchy[OrganizationalLevel.Division];

        var distributions = new Dictionary<int, decimal>
        {
            { regiment.Id, quota }
        };

        // 创建配额
        var allocation = allocationService.CreateAsync(
            "测试类别",
            "测试物资",
            "件",
            totalQuota,
            division.Id,
            distributions
        ).GetAwaiter().GetResult();

        // 验证：分配记录正确关联到配额
        var createdDistribution = context.AllocationDistributions
            .FirstOrDefault(d => d.AllocationId == allocation.Id);

        if (createdDistribution == null)
            return false;

        // 验证关联正确
        return createdDistribution.AllocationId == allocation.Id &&
               createdDistribution.TargetUnitId == regiment.Id &&
               createdDistribution.UnitQuota == quota;
    }

    /// <summary>
    /// 属性8扩展：空分配列表不创建分配记录
    /// **验证需求：需求2.4**
    /// </summary>
    [Property(MaxTest = 100)]
    public bool EmptyDistributions_CreatesNoDistributionRecords(PositiveInt totalQuotaInt)
    {
        var dbName = Guid.NewGuid().ToString();
        using var context = CreateInMemoryContext(dbName);
        var hierarchy = CreateHierarchy(context);
        var organizationService = new OrganizationService(context);
        var allocationService = new AllocationService(context, organizationService);

        var totalQuota = (decimal)totalQuotaInt.Get;
        var division = hierarchy[OrganizationalLevel.Division];

        var distributions = new Dictionary<int, decimal>();

        // 创建配额（无分配）
        var allocation = allocationService.CreateAsync(
            "测试类别",
            "测试物资",
            "件",
            totalQuota,
            division.Id,
            distributions
        ).GetAwaiter().GetResult();

        // 验证：没有创建分配记录
        var createdDistributions = context.AllocationDistributions
            .Where(d => d.AllocationId == allocation.Id)
            .ToList();

        return createdDistributions.Count == 0;
    }

    /// <summary>
    /// 属性8扩展：多个目标单位都获得分配记录
    /// **验证需求：需求2.4**
    /// </summary>
    [Property(MaxTest = 100)]
    public bool MultipleTargetUnits_AllReceiveDistributionRecords(
        PositiveInt totalQuotaInt,
        PositiveInt quota1Int,
        PositiveInt quota2Int,
        PositiveInt quota3Int)
    {
        var dbName = Guid.NewGuid().ToString();
        using var context = CreateInMemoryContext(dbName);
        var hierarchy = CreateHierarchy(context);
        var organizationService = new OrganizationService(context);
        var allocationService = new AllocationService(context, organizationService);

        var totalQuota = (decimal)(totalQuotaInt.Get * 1000);
        var quota1 = (decimal)(quota1Int.Get % 100 + 1);
        var quota2 = (decimal)(quota2Int.Get % 100 + 1);
        var quota3 = (decimal)(quota3Int.Get % 100 + 1);

        // 确保配额有效
        var sum = quota1 + quota2 + quota3;
        if (sum > totalQuota)
        {
            var scale = totalQuota / sum * 0.9m;
            quota1 = Math.Floor(quota1 * scale);
            quota2 = Math.Floor(quota2 * scale);
            quota3 = Math.Floor(quota3 * scale);
        }

        var regiment = hierarchy[OrganizationalLevel.Regiment];
        var battalion = hierarchy[OrganizationalLevel.Battalion];
        var company = hierarchy[OrganizationalLevel.Company];
        var division = hierarchy[OrganizationalLevel.Division];

        var distributions = new Dictionary<int, decimal>
        {
            { regiment.Id, quota1 },
            { battalion.Id, quota2 },
            { company.Id, quota3 }
        };

        // 创建配额
        var allocation = allocationService.CreateAsync(
            "测试类别",
            "测试物资",
            "件",
            totalQuota,
            division.Id,
            distributions
        ).GetAwaiter().GetResult();

        // 验证：所有目标单位都获得了分配记录
        var createdDistributions = context.AllocationDistributions
            .Where(d => d.AllocationId == allocation.Id)
            .ToList();

        // 检查每个目标单位都有分配记录
        var targetUnitIds = distributions.Keys.ToHashSet();
        var createdTargetUnitIds = createdDistributions.Select(d => d.TargetUnitId).ToHashSet();

        return targetUnitIds.SetEquals(createdTargetUnitIds);
    }
}
