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>
/// 消耗上报可见性过滤属性测试
/// **Feature: consumption-report-visibility-filter**
/// </summary>
public class VisibilityFilterPropertyTests
{
    /// <summary>
    /// 创建内存数据库上下文
    /// </summary>
    private static ApplicationDbContext CreateInMemoryContext(string dbName)
    {
        var options = new DbContextOptionsBuilder<ApplicationDbContext>()
            .UseInMemoryDatabase(databaseName: dbName)
            .Options;
        return new ApplicationDbContext(options);
    }

    /// <summary>
    /// 创建测试用的组织层级结构（包含同级单位）
    /// 结构：
    /// - Division (师团)
    ///   - Regiment (团)
    ///     - Battalion1 (营1) - 测试用户所在单位
    ///       - Company1 (连1)
    ///       - Company2 (连2)
    ///     - Battalion2 (营2) - 同级单位
    ///       - Company3 (连3)
    ///       - Company4 (连4)
    /// </summary>
    private static TestHierarchy CreateHierarchyWithSiblings(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();

        // 营1 - 测试用户所在单位
        var battalion1 = new OrganizationalUnit
        {
            Name = "营1",
            Level = OrganizationalLevel.Battalion,
            ParentId = regiment.Id,
            CreatedAt = DateTime.UtcNow
        };
        context.OrganizationalUnits.Add(battalion1);
        context.SaveChanges();

        // 营2 - 同级单位
        var battalion2 = new OrganizationalUnit
        {
            Name = "营2",
            Level = OrganizationalLevel.Battalion,
            ParentId = regiment.Id,
            CreatedAt = DateTime.UtcNow
        };
        context.OrganizationalUnits.Add(battalion2);
        context.SaveChanges();

        // 连1, 连2 - 营1的下级
        var company1 = new OrganizationalUnit
        {
            Name = "连1",
            Level = OrganizationalLevel.Company,
            ParentId = battalion1.Id,
            CreatedAt = DateTime.UtcNow
        };
        context.OrganizationalUnits.Add(company1);

        var company2 = new OrganizationalUnit
        {
            Name = "连2",
            Level = OrganizationalLevel.Company,
            ParentId = battalion1.Id,
            CreatedAt = DateTime.UtcNow
        };
        context.OrganizationalUnits.Add(company2);
        context.SaveChanges();

        // 连3, 连4 - 营2的下级（同级单位的下级）
        var company3 = new OrganizationalUnit
        {
            Name = "连3",
            Level = OrganizationalLevel.Company,
            ParentId = battalion2.Id,
            CreatedAt = DateTime.UtcNow
        };
        context.OrganizationalUnits.Add(company3);

        var company4 = new OrganizationalUnit
        {
            Name = "连4",
            Level = OrganizationalLevel.Company,
            ParentId = battalion2.Id,
            CreatedAt = DateTime.UtcNow
        };
        context.OrganizationalUnits.Add(company4);
        context.SaveChanges();

        return new TestHierarchy
        {
            Division = division,
            Regiment = regiment,
            Battalion1 = battalion1,
            Battalion2 = battalion2,
            Company1 = company1,
            Company2 = company2,
            Company3 = company3,
            Company4 = company4
        };
    }

    private class TestHierarchy
    {
        public OrganizationalUnit Division { get; set; } = null!;
        public OrganizationalUnit Regiment { get; set; } = null!;
        public OrganizationalUnit Battalion1 { get; set; } = null!;
        public OrganizationalUnit Battalion2 { get; set; } = null!;
        public OrganizationalUnit Company1 { get; set; } = null!;
        public OrganizationalUnit Company2 { get; set; } = null!;
        public OrganizationalUnit Company3 { get; set; } = null!;
        public OrganizationalUnit Company4 { get; set; } = null!;
    }


    /// <summary>
    /// **Feature: consumption-report-visibility-filter, Property 1: Restricted visibility for battalion/company level users**
    /// **Validates: Requirements 1.1, 1.2, 1.3, 3.1, 3.2**
    /// 
    /// *For any* organization hierarchy and any user at Battalion_Level or Company_Level, 
    /// the visible unit IDs returned by GetVisibleUnitIdsAsync SHALL:
    /// - Include the user's own unit ID
    /// - Include only direct subordinate unit IDs (children)
    /// - Exclude all sibling unit IDs (units with the same parent)
    /// - Exclude all subordinates of sibling units
    /// </summary>
    [Property(MaxTest = 100)]
    public bool RestrictedVisibility_BattalionCompanyLevel_OnlyShowsOwnUnitAndDirectChildren()
    {
        var dbName = Guid.NewGuid().ToString();
        using var context = CreateInMemoryContext(dbName);
        var hierarchy = CreateHierarchyWithSiblings(context);
        var organizationService = new OrganizationService(context);

        // Test for Battalion level user (营1)
        var battalionVisibleUnits = organizationService
            .GetVisibleUnitIdsAsync(hierarchy.Battalion1.Id, OrganizationalLevel.Battalion)
            .GetAwaiter().GetResult()
            .ToList();

        // 营级用户应该能看到：本单位 + 直接下级（连1, 连2）
        var expectedBattalionVisible = new HashSet<int>
        {
            hierarchy.Battalion1.Id,
            hierarchy.Company1.Id,
            hierarchy.Company2.Id
        };

        // 验证包含所有预期的单位
        var containsAllExpected = expectedBattalionVisible.All(id => battalionVisibleUnits.Contains(id));
        
        // 验证不包含同级单位（营2）
        var excludesSibling = !battalionVisibleUnits.Contains(hierarchy.Battalion2.Id);
        
        // 验证不包含同级单位的下级（连3, 连4）
        var excludesSiblingSubordinates = !battalionVisibleUnits.Contains(hierarchy.Company3.Id) 
                                        && !battalionVisibleUnits.Contains(hierarchy.Company4.Id);

        // 验证数量正确（只有3个：营1, 连1, 连2）
        var correctCount = battalionVisibleUnits.Count == 3;

        return containsAllExpected && excludesSibling && excludesSiblingSubordinates && correctCount;
    }

    /// <summary>
    /// **Feature: consumption-report-visibility-filter, Property 1: Restricted visibility for battalion/company level users**
    /// **Validates: Requirements 1.1, 1.2, 1.3, 3.1, 3.2**
    /// 
    /// 连级用户只能看到本单位
    /// </summary>
    [Property(MaxTest = 100)]
    public bool RestrictedVisibility_CompanyLevel_OnlyShowsOwnUnit()
    {
        var dbName = Guid.NewGuid().ToString();
        using var context = CreateInMemoryContext(dbName);
        var hierarchy = CreateHierarchyWithSiblings(context);
        var organizationService = new OrganizationService(context);

        // Test for Company level user (连1)
        var companyVisibleUnits = organizationService
            .GetVisibleUnitIdsAsync(hierarchy.Company1.Id, OrganizationalLevel.Company)
            .GetAwaiter().GetResult()
            .ToList();

        // 连级用户应该只能看到本单位（连级没有下级）
        var containsOwnUnit = companyVisibleUnits.Contains(hierarchy.Company1.Id);
        
        // 验证不包含同级单位（连2）
        var excludesSibling = !companyVisibleUnits.Contains(hierarchy.Company2.Id);
        
        // 验证不包含上级单位
        var excludesParent = !companyVisibleUnits.Contains(hierarchy.Battalion1.Id);

        // 验证数量正确（只有1个：连1）
        var correctCount = companyVisibleUnits.Count == 1;

        return containsOwnUnit && excludesSibling && excludesParent && correctCount;
    }


    /// <summary>
    /// **Feature: consumption-report-visibility-filter, Property 1: Restricted visibility for battalion/company level users**
    /// **Validates: Requirements 1.1, 1.2, 1.3, 3.1, 3.2**
    /// 
    /// *For any* user at Battalion or Company level, visible units must include own unit
    /// </summary>
    [Property(MaxTest = 100)]
    public bool RestrictedVisibility_AlwaysIncludesOwnUnit(PositiveInt seed)
    {
        var dbName = $"test_{seed.Get}_{Guid.NewGuid()}";
        using var context = CreateInMemoryContext(dbName);
        var hierarchy = CreateHierarchyWithSiblings(context);
        var organizationService = new OrganizationService(context);

        // Test both Battalion and Company levels
        var restrictedLevels = new[] { OrganizationalLevel.Battalion, OrganizationalLevel.Company };
        var testUnits = new[] { hierarchy.Battalion1, hierarchy.Company1 };

        for (int i = 0; i < restrictedLevels.Length; i++)
        {
            var visibleUnits = organizationService
                .GetVisibleUnitIdsAsync(testUnits[i].Id, restrictedLevels[i])
                .GetAwaiter().GetResult()
                .ToList();

            // 必须包含自己的单位ID
            if (!visibleUnits.Contains(testUnits[i].Id))
                return false;
        }

        return true;
    }

    /// <summary>
    /// **Feature: consumption-report-visibility-filter, Property 1: Restricted visibility for battalion/company level users**
    /// **Validates: Requirements 1.1, 1.2, 1.3, 3.1, 3.2**
    /// 
    /// *For any* user at Battalion or Company level, visible units must exclude sibling units
    /// </summary>
    [Property(MaxTest = 100)]
    public bool RestrictedVisibility_ExcludesSiblingUnits(PositiveInt seed)
    {
        var dbName = $"test_{seed.Get}_{Guid.NewGuid()}";
        using var context = CreateInMemoryContext(dbName);
        var hierarchy = CreateHierarchyWithSiblings(context);
        var organizationService = new OrganizationService(context);

        // 营1用户不应该看到营2（同级单位）
        var battalionVisibleUnits = organizationService
            .GetVisibleUnitIdsAsync(hierarchy.Battalion1.Id, OrganizationalLevel.Battalion)
            .GetAwaiter().GetResult()
            .ToList();

        // 不应包含同级单位
        if (battalionVisibleUnits.Contains(hierarchy.Battalion2.Id))
            return false;

        // 不应包含同级单位的下级
        if (battalionVisibleUnits.Contains(hierarchy.Company3.Id) || 
            battalionVisibleUnits.Contains(hierarchy.Company4.Id))
            return false;

        return true;
    }
}


/// <summary>
/// 师团/团级用户完整可见性属性测试
/// **Feature: consumption-report-visibility-filter, Property 2: Full visibility for division/regiment level users**
/// </summary>
public class FullVisibilityPropertyTests
{
    /// <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 TestHierarchy CreateHierarchyWithSiblings(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();

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

        // 营2 - 同级单位
        var battalion2 = new OrganizationalUnit
        {
            Name = "营2",
            Level = OrganizationalLevel.Battalion,
            ParentId = regiment.Id,
            CreatedAt = DateTime.UtcNow
        };
        context.OrganizationalUnits.Add(battalion2);
        context.SaveChanges();

        // 连1, 连2 - 营1的下级
        var company1 = new OrganizationalUnit
        {
            Name = "连1",
            Level = OrganizationalLevel.Company,
            ParentId = battalion1.Id,
            CreatedAt = DateTime.UtcNow
        };
        context.OrganizationalUnits.Add(company1);

        var company2 = new OrganizationalUnit
        {
            Name = "连2",
            Level = OrganizationalLevel.Company,
            ParentId = battalion1.Id,
            CreatedAt = DateTime.UtcNow
        };
        context.OrganizationalUnits.Add(company2);
        context.SaveChanges();

        // 连3, 连4 - 营2的下级
        var company3 = new OrganizationalUnit
        {
            Name = "连3",
            Level = OrganizationalLevel.Company,
            ParentId = battalion2.Id,
            CreatedAt = DateTime.UtcNow
        };
        context.OrganizationalUnits.Add(company3);

        var company4 = new OrganizationalUnit
        {
            Name = "连4",
            Level = OrganizationalLevel.Company,
            ParentId = battalion2.Id,
            CreatedAt = DateTime.UtcNow
        };
        context.OrganizationalUnits.Add(company4);
        context.SaveChanges();

        return new TestHierarchy
        {
            Division = division,
            Regiment = regiment,
            Battalion1 = battalion1,
            Battalion2 = battalion2,
            Company1 = company1,
            Company2 = company2,
            Company3 = company3,
            Company4 = company4
        };
    }

    private class TestHierarchy
    {
        public OrganizationalUnit Division { get; set; } = null!;
        public OrganizationalUnit Regiment { get; set; } = null!;
        public OrganizationalUnit Battalion1 { get; set; } = null!;
        public OrganizationalUnit Battalion2 { get; set; } = null!;
        public OrganizationalUnit Company1 { get; set; } = null!;
        public OrganizationalUnit Company2 { get; set; } = null!;
        public OrganizationalUnit Company3 { get; set; } = null!;
        public OrganizationalUnit Company4 { get; set; } = null!;
    }

    /// <summary>
    /// **Feature: consumption-report-visibility-filter, Property 2: Full visibility for division/regiment level users**
    /// **Validates: Requirements 1.4, 3.3**
    /// 
    /// *For any* organization hierarchy and any user at Division_Level or Regiment_Level, 
    /// the visible unit IDs returned by GetVisibleUnitIdsAsync SHALL equal the union of 
    /// the user's own unit ID and all subordinate unit IDs (as returned by GetAllSubordinateIdsAsync).
    /// </summary>
    [Property(MaxTest = 100)]
    public bool FullVisibility_DivisionLevel_ShowsAllSubordinates()
    {
        var dbName = Guid.NewGuid().ToString();
        using var context = CreateInMemoryContext(dbName);
        var hierarchy = CreateHierarchyWithSiblings(context);
        var organizationService = new OrganizationService(context);

        // Test for Division level user
        var divisionVisibleUnits = organizationService
            .GetVisibleUnitIdsAsync(hierarchy.Division.Id, OrganizationalLevel.Division)
            .GetAwaiter().GetResult()
            .ToHashSet();

        // 获取所有下级单位ID
        var allSubordinates = organizationService
            .GetAllSubordinateIdsAsync(hierarchy.Division.Id)
            .GetAwaiter().GetResult()
            .ToHashSet();

        // 预期可见单位 = 本单位 + 所有下级
        var expectedVisible = new HashSet<int> { hierarchy.Division.Id };
        expectedVisible.UnionWith(allSubordinates);

        // 验证可见单位集合与预期完全相等
        return divisionVisibleUnits.SetEquals(expectedVisible);
    }

    /// <summary>
    /// **Feature: consumption-report-visibility-filter, Property 2: Full visibility for division/regiment level users**
    /// **Validates: Requirements 1.4, 3.3**
    /// 
    /// 团级用户应该能看到所有下级单位
    /// </summary>
    [Property(MaxTest = 100)]
    public bool FullVisibility_RegimentLevel_ShowsAllSubordinates()
    {
        var dbName = Guid.NewGuid().ToString();
        using var context = CreateInMemoryContext(dbName);
        var hierarchy = CreateHierarchyWithSiblings(context);
        var organizationService = new OrganizationService(context);

        // Test for Regiment level user
        var regimentVisibleUnits = organizationService
            .GetVisibleUnitIdsAsync(hierarchy.Regiment.Id, OrganizationalLevel.Regiment)
            .GetAwaiter().GetResult()
            .ToHashSet();

        // 获取所有下级单位ID
        var allSubordinates = organizationService
            .GetAllSubordinateIdsAsync(hierarchy.Regiment.Id)
            .GetAwaiter().GetResult()
            .ToHashSet();

        // 预期可见单位 = 本单位 + 所有下级
        var expectedVisible = new HashSet<int> { hierarchy.Regiment.Id };
        expectedVisible.UnionWith(allSubordinates);

        // 验证可见单位集合与预期完全相等
        return regimentVisibleUnits.SetEquals(expectedVisible);
    }

    /// <summary>
    /// **Feature: consumption-report-visibility-filter, Property 2: Full visibility for division/regiment level users**
    /// **Validates: Requirements 1.4, 3.3**
    /// 
    /// 师团级用户应该能看到所有营和连级单位（包括同级单位的下级）
    /// </summary>
    [Property(MaxTest = 100)]
    public bool FullVisibility_DivisionLevel_IncludesAllBattalionsAndCompanies()
    {
        var dbName = Guid.NewGuid().ToString();
        using var context = CreateInMemoryContext(dbName);
        var hierarchy = CreateHierarchyWithSiblings(context);
        var organizationService = new OrganizationService(context);

        // Test for Division level user
        var divisionVisibleUnits = organizationService
            .GetVisibleUnitIdsAsync(hierarchy.Division.Id, OrganizationalLevel.Division)
            .GetAwaiter().GetResult()
            .ToList();

        // 师团级用户应该能看到所有单位
        var allUnits = new[]
        {
            hierarchy.Division.Id,
            hierarchy.Regiment.Id,
            hierarchy.Battalion1.Id,
            hierarchy.Battalion2.Id,
            hierarchy.Company1.Id,
            hierarchy.Company2.Id,
            hierarchy.Company3.Id,
            hierarchy.Company4.Id
        };

        // 验证包含所有单位
        return allUnits.All(id => divisionVisibleUnits.Contains(id)) 
               && divisionVisibleUnits.Count == allUnits.Length;
    }

    /// <summary>
    /// **Feature: consumption-report-visibility-filter, Property 2: Full visibility for division/regiment level users**
    /// **Validates: Requirements 1.4, 3.3**
    /// 
    /// 团级用户应该能看到所有营和连级单位
    /// </summary>
    [Property(MaxTest = 100)]
    public bool FullVisibility_RegimentLevel_IncludesAllBattalionsAndCompanies()
    {
        var dbName = Guid.NewGuid().ToString();
        using var context = CreateInMemoryContext(dbName);
        var hierarchy = CreateHierarchyWithSiblings(context);
        var organizationService = new OrganizationService(context);

        // Test for Regiment level user
        var regimentVisibleUnits = organizationService
            .GetVisibleUnitIdsAsync(hierarchy.Regiment.Id, OrganizationalLevel.Regiment)
            .GetAwaiter().GetResult()
            .ToList();

        // 团级用户应该能看到：团 + 营1 + 营2 + 连1 + 连2 + 连3 + 连4
        var expectedUnits = new[]
        {
            hierarchy.Regiment.Id,
            hierarchy.Battalion1.Id,
            hierarchy.Battalion2.Id,
            hierarchy.Company1.Id,
            hierarchy.Company2.Id,
            hierarchy.Company3.Id,
            hierarchy.Company4.Id
        };

        // 验证包含所有预期单位
        return expectedUnits.All(id => regimentVisibleUnits.Contains(id)) 
               && regimentVisibleUnits.Count == expectedUnits.Length;
    }
}


/// <summary>
/// 访问控制属性测试
/// **Feature: consumption-report-visibility-filter, Property 3: Access control respects visibility scope**
/// </summary>
public class AccessControlPropertyTests
{
    /// <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 TestHierarchy CreateHierarchyWithSiblings(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();

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

        // 营2 - 同级单位
        var battalion2 = new OrganizationalUnit
        {
            Name = "营2",
            Level = OrganizationalLevel.Battalion,
            ParentId = regiment.Id,
            CreatedAt = DateTime.UtcNow
        };
        context.OrganizationalUnits.Add(battalion2);
        context.SaveChanges();

        // 连1, 连2 - 营1的下级
        var company1 = new OrganizationalUnit
        {
            Name = "连1",
            Level = OrganizationalLevel.Company,
            ParentId = battalion1.Id,
            CreatedAt = DateTime.UtcNow
        };
        context.OrganizationalUnits.Add(company1);

        var company2 = new OrganizationalUnit
        {
            Name = "连2",
            Level = OrganizationalLevel.Company,
            ParentId = battalion1.Id,
            CreatedAt = DateTime.UtcNow
        };
        context.OrganizationalUnits.Add(company2);
        context.SaveChanges();

        // 连3, 连4 - 营2的下级
        var company3 = new OrganizationalUnit
        {
            Name = "连3",
            Level = OrganizationalLevel.Company,
            ParentId = battalion2.Id,
            CreatedAt = DateTime.UtcNow
        };
        context.OrganizationalUnits.Add(company3);

        var company4 = new OrganizationalUnit
        {
            Name = "连4",
            Level = OrganizationalLevel.Company,
            ParentId = battalion2.Id,
            CreatedAt = DateTime.UtcNow
        };
        context.OrganizationalUnits.Add(company4);
        context.SaveChanges();

        return new TestHierarchy
        {
            Division = division,
            Regiment = regiment,
            Battalion1 = battalion1,
            Battalion2 = battalion2,
            Company1 = company1,
            Company2 = company2,
            Company3 = company3,
            Company4 = company4
        };
    }

    private class TestHierarchy
    {
        public OrganizationalUnit Division { get; set; } = null!;
        public OrganizationalUnit Regiment { get; set; } = null!;
        public OrganizationalUnit Battalion1 { get; set; } = null!;
        public OrganizationalUnit Battalion2 { get; set; } = null!;
        public OrganizationalUnit Company1 { get; set; } = null!;
        public OrganizationalUnit Company2 { get; set; } = null!;
        public OrganizationalUnit Company3 { get; set; } = null!;
        public OrganizationalUnit Company4 { get; set; } = null!;
    }

    /// <summary>
    /// **Feature: consumption-report-visibility-filter, Property 3: Access control respects visibility scope**
    /// **Validates: Requirements 2.3**
    /// 
    /// *For any* user and any target unit ID, the CanViewUnitDataAsync method SHALL return true 
    /// if and only if the target unit ID is contained in the user's visible unit IDs set.
    /// </summary>
    [Property(MaxTest = 100)]
    public bool AccessControl_ReturnsTrue_WhenTargetInVisibleUnits()
    {
        var dbName = Guid.NewGuid().ToString();
        using var context = CreateInMemoryContext(dbName);
        var hierarchy = CreateHierarchyWithSiblings(context);
        var organizationService = new OrganizationService(context);
        var reportingService = new ReportingService(context, organizationService);

        // 测试营级用户访问可见单位
        var battalionVisibleUnits = organizationService
            .GetVisibleUnitIdsAsync(hierarchy.Battalion1.Id, OrganizationalLevel.Battalion)
            .GetAwaiter().GetResult()
            .ToList();

        // 对于每个可见单位，CanViewUnitDataAsync 应该返回 true
        foreach (var visibleUnitId in battalionVisibleUnits)
        {
            var canView = reportingService
                .CanViewUnitDataAsync(hierarchy.Battalion1.Id, visibleUnitId, OrganizationalLevel.Battalion)
                .GetAwaiter().GetResult();

            if (!canView)
                return false;
        }

        return true;
    }

    /// <summary>
    /// **Feature: consumption-report-visibility-filter, Property 3: Access control respects visibility scope**
    /// **Validates: Requirements 2.3**
    /// 
    /// *For any* user and any target unit ID not in visible units, CanViewUnitDataAsync SHALL return false.
    /// </summary>
    [Property(MaxTest = 100)]
    public bool AccessControl_ReturnsFalse_WhenTargetNotInVisibleUnits()
    {
        var dbName = Guid.NewGuid().ToString();
        using var context = CreateInMemoryContext(dbName);
        var hierarchy = CreateHierarchyWithSiblings(context);
        var organizationService = new OrganizationService(context);
        var reportingService = new ReportingService(context, organizationService);

        // 测试营级用户访问不可见单位（同级单位及其下级）
        var invisibleUnits = new[]
        {
            hierarchy.Battalion2.Id,  // 同级单位
            hierarchy.Company3.Id,    // 同级单位的下级
            hierarchy.Company4.Id,    // 同级单位的下级
            hierarchy.Regiment.Id,    // 上级单位
            hierarchy.Division.Id     // 更上级单位
        };

        foreach (var invisibleUnitId in invisibleUnits)
        {
            var canView = reportingService
                .CanViewUnitDataAsync(hierarchy.Battalion1.Id, invisibleUnitId, OrganizationalLevel.Battalion)
                .GetAwaiter().GetResult();

            if (canView)
                return false;
        }

        return true;
    }

    /// <summary>
    /// **Feature: consumption-report-visibility-filter, Property 3: Access control respects visibility scope**
    /// **Validates: Requirements 2.3**
    /// 
    /// *For any* user at Division/Regiment level, CanViewUnitDataAsync SHALL return true for all subordinates.
    /// </summary>
    [Property(MaxTest = 100)]
    public bool AccessControl_DivisionLevel_CanViewAllSubordinates()
    {
        var dbName = Guid.NewGuid().ToString();
        using var context = CreateInMemoryContext(dbName);
        var hierarchy = CreateHierarchyWithSiblings(context);
        var organizationService = new OrganizationService(context);
        var reportingService = new ReportingService(context, organizationService);

        // 师团级用户应该能访问所有下级单位
        var allUnits = new[]
        {
            hierarchy.Division.Id,
            hierarchy.Regiment.Id,
            hierarchy.Battalion1.Id,
            hierarchy.Battalion2.Id,
            hierarchy.Company1.Id,
            hierarchy.Company2.Id,
            hierarchy.Company3.Id,
            hierarchy.Company4.Id
        };

        foreach (var unitId in allUnits)
        {
            var canView = reportingService
                .CanViewUnitDataAsync(hierarchy.Division.Id, unitId, OrganizationalLevel.Division)
                .GetAwaiter().GetResult();

            if (!canView)
                return false;
        }

        return true;
    }

    /// <summary>
    /// **Feature: consumption-report-visibility-filter, Property 3: Access control respects visibility scope**
    /// **Validates: Requirements 2.3**
    /// 
    /// CanViewUnitDataAsync result is consistent with GetVisibleUnitIdsAsync for all user levels.
    /// </summary>
    [Property(MaxTest = 100)]
    public bool AccessControl_ConsistentWithVisibleUnits_AllLevels()
    {
        var dbName = Guid.NewGuid().ToString();
        using var context = CreateInMemoryContext(dbName);
        var hierarchy = CreateHierarchyWithSiblings(context);
        var organizationService = new OrganizationService(context);
        var reportingService = new ReportingService(context, organizationService);

        // 测试所有层级
        var testCases = new[]
        {
            (hierarchy.Division.Id, OrganizationalLevel.Division),
            (hierarchy.Regiment.Id, OrganizationalLevel.Regiment),
            (hierarchy.Battalion1.Id, OrganizationalLevel.Battalion),
            (hierarchy.Company1.Id, OrganizationalLevel.Company)
        };

        var allUnits = new[]
        {
            hierarchy.Division.Id,
            hierarchy.Regiment.Id,
            hierarchy.Battalion1.Id,
            hierarchy.Battalion2.Id,
            hierarchy.Company1.Id,
            hierarchy.Company2.Id,
            hierarchy.Company3.Id,
            hierarchy.Company4.Id
        };

        foreach (var (userUnitId, userLevel) in testCases)
        {
            var visibleUnits = organizationService
                .GetVisibleUnitIdsAsync(userUnitId, userLevel)
                .GetAwaiter().GetResult()
                .ToHashSet();

            foreach (var targetUnitId in allUnits)
            {
                var canView = reportingService
                    .CanViewUnitDataAsync(userUnitId, targetUnitId, userLevel)
                    .GetAwaiter().GetResult();

                var shouldBeVisible = visibleUnits.Contains(targetUnitId);

                // CanViewUnitDataAsync 的结果应该与 GetVisibleUnitIdsAsync 一致
                if (canView != shouldBeVisible)
                    return false;
            }
        }

        return true;
    }
}
