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

namespace MilitaryTrainingManagement.Tests.Properties;

/// <summary>
/// 审计跟踪属性测试
/// **功能：military-training-material-management，属性9：审计跟踪完整性**
/// **验证需求：需求1.4, 5.4, 6.4**
/// </summary>
public class AuditTrailPropertyTests
{
    /// <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 AuditService CreateAuditService(ApplicationDbContext context)
    {
        var loggerFactory = LoggerFactory.Create(builder => builder.AddConsole());
        var logger = loggerFactory.CreateLogger<AuditService>();
        return new AuditService(context, logger);
    }

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

        var user = new UserAccount
        {
            Username = "test_user",
            PasswordHash = "hash",
            DisplayName = "测试用户",
            OrganizationalUnitId = division.Id,
            IsActive = true,
            CreatedAt = DateTime.UtcNow
        };
        context.UserAccounts.Add(user);
        context.SaveChanges();

        return (division, user);
    }


    /// <summary>
    /// 属性9：审计跟踪完整性 - 创建操作必须生成审计日志
    /// *对于任何*修改数据的系统操作，应创建相应的审计日志条目，包含完整的操作详情
    /// **验证需求：需求1.4, 5.4, 6.4**
    /// </summary>
    [Property(MaxTest = 100)]
    public bool CreateOperationGeneratesAuditLog(NonEmptyString entityType, PositiveInt entityId)
    {
        var dbName = Guid.NewGuid().ToString();
        using var context = CreateInMemoryContext(dbName);
        var auditService = CreateAuditService(context);
        var (division, user) = CreateTestData(context);

        // 记录创建操作的审计日志
        auditService.LogAsync(new AuditLogEntry
        {
            EntityType = entityType.Get,
            EntityId = entityId.Get,
            Action = AuditActions.Create,
            Description = "创建测试记录",
            NewValues = "{\"test\": \"value\"}",
            UserId = user.Id,
            OrganizationalUnitId = division.Id,
            IpAddress = "127.0.0.1"
        }).GetAwaiter().GetResult();

        // 验证审计日志已创建
        var logs = auditService.GetEntityHistoryAsync(entityType.Get, entityId.Get).GetAwaiter().GetResult();
        var log = logs.FirstOrDefault();

        return log != null 
            && log.EntityType == entityType.Get 
            && log.EntityId == entityId.Get 
            && log.Action == AuditActions.Create
            && log.UserId == user.Id
            && log.OrganizationalUnitId == division.Id;
    }

    /// <summary>
    /// 属性9：审计跟踪完整性 - 更新操作必须记录新旧值
    /// **验证需求：需求1.4, 5.4, 6.4**
    /// </summary>
    [Property(MaxTest = 100)]
    public bool UpdateOperationRecordsOldAndNewValues(NonEmptyString entityType, PositiveInt entityId, PositiveInt oldValue, PositiveInt newValue)
    {
        var dbName = Guid.NewGuid().ToString();
        using var context = CreateInMemoryContext(dbName);
        var auditService = CreateAuditService(context);
        var (division, user) = CreateTestData(context);

        var oldValues = $"{{\"value\": {oldValue.Get}}}";
        var newValues = $"{{\"value\": {newValue.Get}}}";

        // 记录更新操作的审计日志
        auditService.LogAsync(new AuditLogEntry
        {
            EntityType = entityType.Get,
            EntityId = entityId.Get,
            Action = AuditActions.Update,
            Description = "更新测试记录",
            OldValues = oldValues,
            NewValues = newValues,
            ChangedFields = "[\"value\"]",
            UserId = user.Id,
            OrganizationalUnitId = division.Id
        }).GetAwaiter().GetResult();

        // 验证审计日志包含新旧值
        var logs = auditService.GetEntityHistoryAsync(entityType.Get, entityId.Get).GetAwaiter().GetResult();
        var log = logs.FirstOrDefault();

        return log != null 
            && log.Action == AuditActions.Update
            && log.OldValues == oldValues 
            && log.NewValues == newValues
            && log.ChangedFields != null;
    }

    /// <summary>
    /// 属性9：审计跟踪完整性 - 删除操作必须记录被删除的数据
    /// **验证需求：需求1.4, 5.4, 6.4**
    /// </summary>
    [Property(MaxTest = 100)]
    public bool DeleteOperationRecordsDeletedData(NonEmptyString entityType, PositiveInt entityId)
    {
        var dbName = Guid.NewGuid().ToString();
        using var context = CreateInMemoryContext(dbName);
        var auditService = CreateAuditService(context);
        var (division, user) = CreateTestData(context);

        var deletedData = "{\"id\": 1, \"name\": \"deleted item\"}";

        // 记录删除操作的审计日志
        auditService.LogAsync(new AuditLogEntry
        {
            EntityType = entityType.Get,
            EntityId = entityId.Get,
            Action = AuditActions.Delete,
            Description = "删除测试记录",
            OldValues = deletedData,
            UserId = user.Id,
            OrganizationalUnitId = division.Id
        }).GetAwaiter().GetResult();

        // 验证审计日志包含被删除的数据
        var logs = auditService.GetEntityHistoryAsync(entityType.Get, entityId.Get).GetAwaiter().GetResult();
        var log = logs.FirstOrDefault();

        return log != null 
            && log.Action == AuditActions.Delete
            && log.OldValues == deletedData;
    }


    /// <summary>
    /// 属性9：审计跟踪完整性 - 审批操作必须生成审计日志
    /// **验证需求：需求5.4, 6.4**
    /// </summary>
    [Property(MaxTest = 100)]
    public bool ApprovalOperationGeneratesAuditLog(PositiveInt entityId)
    {
        var dbName = Guid.NewGuid().ToString();
        using var context = CreateInMemoryContext(dbName);
        var auditService = CreateAuditService(context);
        var (division, user) = CreateTestData(context);

        // 记录审批操作的审计日志
        auditService.LogApprovalAsync(
            "Personnel",
            entityId.Get,
            AuditActions.Approve,
            "审批人员记录",
            user.Id,
            division.Id,
            "127.0.0.1"
        ).GetAwaiter().GetResult();

        // 验证审计日志已创建
        var logs = auditService.GetEntityHistoryAsync("Personnel", entityId.Get).GetAwaiter().GetResult();
        var log = logs.FirstOrDefault();

        return log != null 
            && log.Action == AuditActions.Approve
            && log.UserId == user.Id;
    }

    /// <summary>
    /// 属性9：审计跟踪完整性 - 失败操作也必须记录
    /// **验证需求：需求1.4**
    /// </summary>
    [Property(MaxTest = 100)]
    public bool FailedOperationIsRecorded(NonEmptyString entityType, PositiveInt entityId, NonEmptyString errorMessage)
    {
        var dbName = Guid.NewGuid().ToString();
        using var context = CreateInMemoryContext(dbName);
        var auditService = CreateAuditService(context);
        var (division, user) = CreateTestData(context);

        // 记录失败操作的审计日志
        auditService.LogFailureAsync(
            entityType.Get,
            entityId.Get,
            AuditActions.Update,
            errorMessage.Get,
            user.Id,
            division.Id,
            "127.0.0.1"
        ).GetAwaiter().GetResult();

        // 验证失败操作已记录
        var logs = auditService.GetEntityHistoryAsync(entityType.Get, entityId.Get).GetAwaiter().GetResult();
        var log = logs.FirstOrDefault();

        return log != null 
            && log.IsSuccess == false
            && log.ErrorMessage == errorMessage.Get;
    }

    /// <summary>
    /// 属性9：审计跟踪完整性 - 每个操作都有时间戳
    /// **验证需求：需求1.4, 5.4, 6.4**
    /// </summary>
    [Property(MaxTest = 100)]
    public bool EveryOperationHasTimestamp(NonEmptyString entityType, PositiveInt entityId)
    {
        var dbName = Guid.NewGuid().ToString();
        using var context = CreateInMemoryContext(dbName);
        var auditService = CreateAuditService(context);
        var (division, user) = CreateTestData(context);

        var beforeLog = DateTime.UtcNow;

        // 记录操作
        auditService.LogAsync(new AuditLogEntry
        {
            EntityType = entityType.Get,
            EntityId = entityId.Get,
            Action = AuditActions.Create,
            UserId = user.Id,
            OrganizationalUnitId = division.Id
        }).GetAwaiter().GetResult();

        var afterLog = DateTime.UtcNow;

        // 验证时间戳在合理范围内
        var logs = auditService.GetEntityHistoryAsync(entityType.Get, entityId.Get).GetAwaiter().GetResult();
        var log = logs.FirstOrDefault();

        return log != null 
            && log.Timestamp >= beforeLog 
            && log.Timestamp <= afterLog;
    }

    /// <summary>
    /// 属性9：审计跟踪完整性 - 可以按用户查询操作历史
    /// **验证需求：需求1.4**
    /// </summary>
    [Property(MaxTest = 100)]
    public bool CanQueryAuditLogsByUser(PositiveInt operationCount)
    {
        var dbName = Guid.NewGuid().ToString();
        using var context = CreateInMemoryContext(dbName);
        var auditService = CreateAuditService(context);
        var (division, user) = CreateTestData(context);

        // 限制操作数量以避免测试过慢
        var count = Math.Min(operationCount.Get, 10);

        // 记录多个操作
        for (int i = 0; i < count; i++)
        {
            auditService.LogAsync(new AuditLogEntry
            {
                EntityType = "TestEntity",
                EntityId = i + 1,
                Action = AuditActions.Create,
                UserId = user.Id,
                OrganizationalUnitId = division.Id
            }).GetAwaiter().GetResult();
        }

        // 按用户查询
        var logs = auditService.GetUserActivityAsync(user.Id).GetAwaiter().GetResult();

        return logs.Count() == count && logs.All(l => l.UserId == user.Id);
    }

    /// <summary>
    /// 属性9：审计跟踪完整性 - 可以按组织单位查询操作历史
    /// **验证需求：需求1.4**
    /// </summary>
    [Property(MaxTest = 100)]
    public bool CanQueryAuditLogsByOrganizationalUnit(PositiveInt operationCount)
    {
        var dbName = Guid.NewGuid().ToString();
        using var context = CreateInMemoryContext(dbName);
        var auditService = CreateAuditService(context);
        var (division, user) = CreateTestData(context);

        // 限制操作数量
        var count = Math.Min(operationCount.Get, 10);

        // 记录多个操作
        for (int i = 0; i < count; i++)
        {
            auditService.LogAsync(new AuditLogEntry
            {
                EntityType = "TestEntity",
                EntityId = i + 1,
                Action = AuditActions.Create,
                UserId = user.Id,
                OrganizationalUnitId = division.Id
            }).GetAwaiter().GetResult();
        }

        // 按组织单位查询
        var logs = auditService.GetOrganizationalUnitActivityAsync(division.Id).GetAwaiter().GetResult();

        return logs.Count() == count && logs.All(l => l.OrganizationalUnitId == division.Id);
    }


    /// <summary>
    /// 属性9：审计跟踪完整性 - 审计日志统计正确
    /// **验证需求：需求1.4**
    /// </summary>
    [Property(MaxTest = 100)]
    public bool AuditLogStatisticsAreCorrect(PositiveInt createCount, PositiveInt updateCount, PositiveInt deleteCount)
    {
        var dbName = Guid.NewGuid().ToString();
        using var context = CreateInMemoryContext(dbName);
        var auditService = CreateAuditService(context);
        var (division, user) = CreateTestData(context);

        // 限制操作数量
        var creates = Math.Min(createCount.Get, 5);
        var updates = Math.Min(updateCount.Get, 5);
        var deletes = Math.Min(deleteCount.Get, 5);

        // 记录创建操作
        for (int i = 0; i < creates; i++)
        {
            auditService.LogAsync(new AuditLogEntry
            {
                EntityType = "TestEntity",
                EntityId = i + 1,
                Action = AuditActions.Create,
                UserId = user.Id,
                OrganizationalUnitId = division.Id
            }).GetAwaiter().GetResult();
        }

        // 记录更新操作
        for (int i = 0; i < updates; i++)
        {
            auditService.LogAsync(new AuditLogEntry
            {
                EntityType = "TestEntity",
                EntityId = i + 1,
                Action = AuditActions.Update,
                UserId = user.Id,
                OrganizationalUnitId = division.Id
            }).GetAwaiter().GetResult();
        }

        // 记录删除操作
        for (int i = 0; i < deletes; i++)
        {
            auditService.LogAsync(new AuditLogEntry
            {
                EntityType = "TestEntity",
                EntityId = i + 1,
                Action = AuditActions.Delete,
                UserId = user.Id,
                OrganizationalUnitId = division.Id
            }).GetAwaiter().GetResult();
        }

        // 获取统计
        var stats = auditService.GetStatisticsAsync().GetAwaiter().GetResult();

        return stats.TotalLogs == creates + updates + deletes
            && stats.CreateOperations == creates
            && stats.UpdateOperations == updates
            && stats.DeleteOperations == deletes;
    }

    /// <summary>
    /// 属性9：审计跟踪完整性 - 可以按时间范围查询审计日志
    /// **验证需求：需求1.4, 4.3**
    /// </summary>
    [Property(MaxTest = 100)]
    public bool CanQueryAuditLogsByDateRange(PositiveInt entityId)
    {
        var dbName = Guid.NewGuid().ToString();
        using var context = CreateInMemoryContext(dbName);
        var auditService = CreateAuditService(context);
        var (division, user) = CreateTestData(context);

        var now = DateTime.UtcNow;

        // 记录操作
        auditService.LogAsync(new AuditLogEntry
        {
            EntityType = "TestEntity",
            EntityId = entityId.Get,
            Action = AuditActions.Create,
            UserId = user.Id,
            OrganizationalUnitId = division.Id
        }).GetAwaiter().GetResult();

        // 按时间范围查询（应该找到记录）
        var logsInRange = auditService.GetLogsAsync(
            entityType: "TestEntity",
            fromDate: now.AddMinutes(-1),
            toDate: now.AddMinutes(1)
        ).GetAwaiter().GetResult();

        // 按时间范围查询（不应该找到记录）
        var logsOutOfRange = auditService.GetLogsAsync(
            entityType: "TestEntity",
            fromDate: now.AddDays(-2),
            toDate: now.AddDays(-1)
        ).GetAwaiter().GetResult();

        return logsInRange.Any() && !logsOutOfRange.Any();
    }

    /// <summary>
    /// 属性9：审计跟踪完整性 - 使用LogCreateAsync记录创建操作
    /// **验证需求：需求1.4, 6.4**
    /// </summary>
    [Property(MaxTest = 100)]
    public bool LogCreateAsyncRecordsEntityCreation(PositiveInt entityId, PositiveInt age)
    {
        var dbName = Guid.NewGuid().ToString();
        using var context = CreateInMemoryContext(dbName);
        var auditService = CreateAuditService(context);
        var (division, user) = CreateTestData(context);

        // 使用固定的有效名称
        var validName = $"测试人员{entityId.Get}";

        // 创建一个人员实体
        var personnel = new Personnel
        {
            Id = entityId.Get,
            Name = validName,
            Position = "测试职位",
            Rank = "测试军衔",
            Gender = "男",
            IdNumber = "123456789012345678",
            Age = Math.Min(age.Get, 100),
            Height = 175,
            SubmittedByUnitId = division.Id,
            Status = PersonnelStatus.Pending,
            SubmittedAt = DateTime.UtcNow
        };

        // 使用LogCreateAsync记录
        auditService.LogCreateAsync(personnel, user.Id, division.Id, "127.0.0.1").GetAwaiter().GetResult();

        // 验证审计日志 - 直接从数据库查询
        var log = context.AuditLogs.FirstOrDefault(l => l.EntityType == "Personnel" && l.EntityId == entityId.Get);

        // 验证审计日志存在且包含正确的信息
        return log != null 
            && log.EntityType == "Personnel"
            && log.Action == AuditActions.Create
            && log.NewValues != null;
    }
}
