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

namespace MilitaryTrainingManagement.Tests.Services;

/// <summary>
/// 人员管理服务单元测试
/// 测试人员数据验证、审批工作流、等级分配逻辑和文件上传功能
/// _需求：6.1, 6.2, 6.3, 6.4, 7.1, 7.2, 7.3, 7.4, 7.5, 8.1, 8.2, 8.3, 8.4_
/// </summary>
public class PersonnelServiceTests : IDisposable
{
    private readonly ApplicationDbContext _context;
    private readonly PersonnelService _personnelService;

    public PersonnelServiceTests()
    {
        var options = new DbContextOptionsBuilder<ApplicationDbContext>()
            .UseInMemoryDatabase(databaseName: Guid.NewGuid().ToString())
            .Options;

        _context = new ApplicationDbContext(options);
        
        // Create a minimal PersonnelService for testing core functionality
        _personnelService = new PersonnelService(
            _context,
            null!, // IOrganizationService - not needed for basic tests
            null!, // IFileUploadService - not needed for basic tests
            null!, // IWorkflowService - not needed for basic tests
            NullLogger<PersonnelService>.Instance); // Use NullLogger for tests

        SeedTestData();
    }

    private void SeedTestData()
    {
        // 创建测试组织单位 - 四级组织结构
        var division = new OrganizationalUnit
        {
            Id = 1,
            Name = "师团",
            Level = OrganizationalLevel.Division,
            CreatedAt = DateTime.UtcNow
        };

        var regiment = new OrganizationalUnit
        {
            Id = 2,
            Name = "团",
            Level = OrganizationalLevel.Regiment,
            ParentId = 1,
            CreatedAt = DateTime.UtcNow
        };

        var battalion = new OrganizationalUnit
        {
            Id = 3,
            Name = "营",
            Level = OrganizationalLevel.Battalion,
            ParentId = 2,
            CreatedAt = DateTime.UtcNow
        };

        var company = new OrganizationalUnit
        {
            Id = 4,
            Name = "连",
            Level = OrganizationalLevel.Company,
            ParentId = 3,
            CreatedAt = DateTime.UtcNow
        };

        _context.OrganizationalUnits.AddRange(division, regiment, battalion, company);
        _context.SaveChanges();
    }

    private Personnel CreateValidPersonnel(int submittedByUnitId = 2, string idNumber = "123456789012345678")
    {
        return new Personnel
        {
            Name = "测试人员",
            Position = "测试职位",
            Rank = "测试军衔",
            Gender = "男",
            IdNumber = idNumber,
            Age = 25,
            SubmittedByUnitId = submittedByUnitId,
            Status = PersonnelStatus.Pending
        };
    }
    [Fact]
    public async Task CreateAsync_ValidPersonnel_ShouldCreateSuccessfully()
    {
        // Arrange
        var personnel = CreateValidPersonnel();

        // Act
        var result = await _personnelService.CreateAsync(personnel);

        // Assert
        Assert.NotNull(result);
        Assert.Equal(PersonnelStatus.Pending, result.Status);
        Assert.True(result.Id > 0);
        Assert.True(result.SubmittedAt > DateTime.MinValue);
    }

    [Fact]
    public async Task GetByIdAsync_ExistingPersonnel_ShouldReturnPersonnel()
    {
        // Arrange
        var personnel = CreateValidPersonnel();
        _context.Personnel.Add(personnel);
        await _context.SaveChangesAsync();

        // Act
        var result = await _personnelService.GetByIdAsync(personnel.Id);

        // Assert
        Assert.NotNull(result);
        Assert.Equal(personnel.Name, result.Name);
        Assert.Equal(personnel.IdNumber, result.IdNumber);
    }

    [Fact]
    public async Task GetByIdAsync_NonExistentPersonnel_ShouldReturnNull()
    {
        // Act
        var result = await _personnelService.GetByIdAsync(999);

        // Assert
        Assert.Null(result);
    }

    [Fact]
    public async Task ApproveAsync_ValidPersonnel_ShouldApproveSuccessfully()
    {
        // Arrange
        var personnel = CreateValidPersonnel();
        _context.Personnel.Add(personnel);
        await _context.SaveChangesAsync();

        // Act
        var result = await _personnelService.ApproveAsync(personnel.Id, 1, PersonnelLevel.Division);

        // Assert
        Assert.Equal(PersonnelStatus.Approved, result.Status);
        Assert.Equal(PersonnelLevel.Division, result.ApprovedLevel);
        Assert.Equal(1, result.ApprovedByUnitId);
        Assert.NotNull(result.ApprovedAt);
    }

    [Fact]
    public async Task ApproveAsync_InvalidLevel_ShouldThrowException()
    {
        // Arrange
        var personnel = CreateValidPersonnel();
        _context.Personnel.Add(personnel);
        await _context.SaveChangesAsync();

        // Act & Assert
        await Assert.ThrowsAsync<ArgumentException>(() =>
            _personnelService.ApproveAsync(personnel.Id, 1, PersonnelLevel.Regiment));
    }


    #region 人员数据验证测试 (需求6.1)

    /// <summary>
    /// 测试验证人员数据 - 所有必填字段存在时验证通过
    /// </summary>
    [Fact]
    public async Task ValidatePersonnelDataAsync_AllRequiredFields_ShouldReturnValid()
    {
        // Arrange
        var personnel = CreateValidPersonnel();

        // Act
        var result = await _personnelService.ValidatePersonnelDataAsync(personnel);

        // Assert
        Assert.True(result.IsValid);
        Assert.Empty(result.Errors);
    }

    /// <summary>
    /// 测试验证人员数据 - 姓名为空时验证失败
    /// </summary>
    [Fact]
    public async Task ValidatePersonnelDataAsync_EmptyName_ShouldReturnInvalid()
    {
        // Arrange
        var personnel = CreateValidPersonnel();
        personnel.Name = "";

        // Act
        var result = await _personnelService.ValidatePersonnelDataAsync(personnel);

        // Assert
        Assert.False(result.IsValid);
        Assert.Contains("姓名不能为空", result.Errors);
    }

    /// <summary>
    /// 测试验证人员数据 - 职位为空时验证失败
    /// </summary>
    [Fact]
    public async Task ValidatePersonnelDataAsync_EmptyPosition_ShouldReturnInvalid()
    {
        // Arrange
        var personnel = CreateValidPersonnel();
        personnel.Position = "";

        // Act
        var result = await _personnelService.ValidatePersonnelDataAsync(personnel);

        // Assert
        Assert.False(result.IsValid);
        Assert.Contains("职位不能为空", result.Errors);
    }

    /// <summary>
    /// 测试验证人员数据 - 军衔为空时验证失败
    /// </summary>
    [Fact]
    public async Task ValidatePersonnelDataAsync_EmptyRank_ShouldReturnInvalid()
    {
        // Arrange
        var personnel = CreateValidPersonnel();
        personnel.Rank = "";

        // Act
        var result = await _personnelService.ValidatePersonnelDataAsync(personnel);

        // Assert
        Assert.False(result.IsValid);
        Assert.Contains("军衔不能为空", result.Errors);
    }

    /// <summary>
    /// 测试验证人员数据 - 身份证号格式错误时验证失败
    /// </summary>
    [Fact]
    public async Task ValidatePersonnelDataAsync_InvalidIdNumber_ShouldReturnInvalid()
    {
        // Arrange
        var personnel = CreateValidPersonnel();
        personnel.IdNumber = "12345"; // 不是18位

        // Act
        var result = await _personnelService.ValidatePersonnelDataAsync(personnel);

        // Assert
        Assert.False(result.IsValid);
        Assert.Contains("身份证号必须为18位", result.Errors);
    }

    /// <summary>
    /// 测试验证人员数据 - 年龄超出范围时验证失败
    /// </summary>
    [Fact]
    public async Task ValidatePersonnelDataAsync_InvalidAge_ShouldReturnInvalid()
    {
        // Arrange
        var personnel = CreateValidPersonnel();
        personnel.Age = 0;

        // Act
        var result = await _personnelService.ValidatePersonnelDataAsync(personnel);

        // Assert
        Assert.False(result.IsValid);
        Assert.Contains("年龄必须在1-100之间", result.Errors);
    }

    /// <summary>
    /// 测试验证人员数据 - 身份证号重复时验证失败
    /// </summary>
    [Fact]
    public async Task ValidatePersonnelDataAsync_DuplicateIdNumber_ShouldReturnInvalid()
    {
        // Arrange
        var existingPersonnel = CreateValidPersonnel();
        _context.Personnel.Add(existingPersonnel);
        await _context.SaveChangesAsync();

        var newPersonnel = CreateValidPersonnel(idNumber: "123456789012345678");

        // Act
        var result = await _personnelService.ValidatePersonnelDataAsync(newPersonnel);

        // Assert
        Assert.False(result.IsValid);
        Assert.Contains("身份证号已存在", result.Errors);
    }

    /// <summary>
    /// 测试验证人员数据 - 提交单位不存在时验证失败
    /// </summary>
    [Fact]
    public async Task ValidatePersonnelDataAsync_InvalidSubmittedByUnit_ShouldReturnInvalid()
    {
        // Arrange
        var personnel = CreateValidPersonnel(submittedByUnitId: 999);

        // Act
        var result = await _personnelService.ValidatePersonnelDataAsync(personnel);

        // Assert
        Assert.False(result.IsValid);
        Assert.Contains("提交单位不存在", result.Errors);
    }

    #endregion

    #region 审批工作流测试 (需求7.1)

    /// <summary>
    /// 测试拒绝人员 - 成功拒绝
    /// </summary>
    [Fact]
    public async Task RejectAsync_ValidPersonnel_ShouldRejectSuccessfully()
    {
        // Arrange
        var personnel = CreateValidPersonnel();
        _context.Personnel.Add(personnel);
        await _context.SaveChangesAsync();

        // 创建用户
        var user = new UserAccount
        {
            Id = 1,
            Username = "test_user",
            PasswordHash = "hash",
            DisplayName = "测试用户",
            OrganizationalUnitId = 1,
            IsActive = true,
            CreatedAt = DateTime.UtcNow
        };
        _context.UserAccounts.Add(user);
        await _context.SaveChangesAsync();

        // Act
        var result = await _personnelService.RejectAsync(personnel.Id, user.Id);

        // Assert
        Assert.Equal(PersonnelStatus.Rejected, result.Status);
    }

    /// <summary>
    /// 测试拒绝人员 - 人员不存在时抛出异常
    /// </summary>
    [Fact]
    public async Task RejectAsync_NonExistentPersonnel_ShouldThrowException()
    {
        // Act & Assert
        await Assert.ThrowsAsync<ArgumentException>(() =>
            _personnelService.RejectAsync(999, 1));
    }

    /// <summary>
    /// 测试审批人员 - 人员不存在时抛出异常
    /// </summary>
    [Fact]
    public async Task ApproveAsync_NonExistentPersonnel_ShouldThrowException()
    {
        // Act & Assert
        await Assert.ThrowsAsync<ArgumentException>(() =>
            _personnelService.ApproveAsync(999, 1, PersonnelLevel.Division));
    }

    /// <summary>
    /// 测试审批人员 - 审批单位不存在时抛出异常
    /// </summary>
    [Fact]
    public async Task ApproveAsync_NonExistentApprovalUnit_ShouldThrowException()
    {
        // Arrange
        var personnel = CreateValidPersonnel();
        _context.Personnel.Add(personnel);
        await _context.SaveChangesAsync();

        // Act & Assert
        await Assert.ThrowsAsync<ArgumentException>(() =>
            _personnelService.ApproveAsync(personnel.Id, 999, PersonnelLevel.Division));
    }

    /// <summary>
    /// 测试检查人员是否可修改 - 待审批状态可修改
    /// </summary>
    [Fact]
    public async Task CanModifyPersonnelAsync_PendingStatus_ShouldReturnTrue()
    {
        // Arrange
        var personnel = CreateValidPersonnel();
        personnel.Status = PersonnelStatus.Pending;
        _context.Personnel.Add(personnel);
        await _context.SaveChangesAsync();

        // Act
        var result = await _personnelService.CanModifyPersonnelAsync(personnel.Id);

        // Assert
        Assert.True(result);
    }

    /// <summary>
    /// 测试检查人员是否可修改 - 已审批状态不可直接修改
    /// </summary>
    [Fact]
    public async Task CanModifyPersonnelAsync_ApprovedStatus_ShouldReturnFalse()
    {
        // Arrange
        var personnel = CreateValidPersonnel();
        personnel.Status = PersonnelStatus.Approved;
        _context.Personnel.Add(personnel);
        await _context.SaveChangesAsync();

        // Act
        var result = await _personnelService.CanModifyPersonnelAsync(personnel.Id);

        // Assert
        Assert.False(result);
    }

    /// <summary>
    /// 测试检查人员是否可修改 - 人员不存在时返回false
    /// </summary>
    [Fact]
    public async Task CanModifyPersonnelAsync_NonExistentPersonnel_ShouldReturnFalse()
    {
        // Act
        var result = await _personnelService.CanModifyPersonnelAsync(999);

        // Assert
        Assert.False(result);
    }

    #endregion

    #region 等级分配逻辑测试 (需求7.2, 7.3, 7.5)

    /// <summary>
    /// 测试师团级别审批 - 分配师级人才等级
    /// </summary>
    [Fact]
    public async Task ApproveAsync_DivisionLevel_ShouldAssignDivisionPersonnelLevel()
    {
        // Arrange
        var personnel = CreateValidPersonnel();
        _context.Personnel.Add(personnel);
        await _context.SaveChangesAsync();

        // Act
        var result = await _personnelService.ApproveAsync(personnel.Id, 1, PersonnelLevel.Division);

        // Assert
        Assert.Equal(PersonnelLevel.Division, result.ApprovedLevel);
        Assert.Equal(1, result.ApprovedByUnitId);
    }

    /// <summary>
    /// 测试团级别审批 - 分配团级人才等级
    /// </summary>
    [Fact]
    public async Task ApproveAsync_RegimentLevel_ShouldAssignRegimentPersonnelLevel()
    {
        // Arrange
        var personnel = CreateValidPersonnel();
        _context.Personnel.Add(personnel);
        await _context.SaveChangesAsync();

        // Act
        var result = await _personnelService.ApproveAsync(personnel.Id, 2, PersonnelLevel.Regiment);

        // Assert
        Assert.Equal(PersonnelLevel.Regiment, result.ApprovedLevel);
        Assert.Equal(2, result.ApprovedByUnitId);
    }

    /// <summary>
    /// 测试营级别审批 - 分配营级人才等级
    /// </summary>
    [Fact]
    public async Task ApproveAsync_BattalionLevel_ShouldAssignBattalionPersonnelLevel()
    {
        // Arrange
        var personnel = CreateValidPersonnel();
        _context.Personnel.Add(personnel);
        await _context.SaveChangesAsync();

        // Act
        var result = await _personnelService.ApproveAsync(personnel.Id, 3, PersonnelLevel.Battalion);

        // Assert
        Assert.Equal(PersonnelLevel.Battalion, result.ApprovedLevel);
        Assert.Equal(3, result.ApprovedByUnitId);
    }

    /// <summary>
    /// 测试连级别审批 - 分配连级人才等级
    /// </summary>
    [Fact]
    public async Task ApproveAsync_CompanyLevel_ShouldAssignCompanyPersonnelLevel()
    {
        // Arrange
        var personnel = CreateValidPersonnel();
        _context.Personnel.Add(personnel);
        await _context.SaveChangesAsync();

        // Act
        var result = await _personnelService.ApproveAsync(personnel.Id, 4, PersonnelLevel.Company);

        // Assert
        Assert.Equal(PersonnelLevel.Company, result.ApprovedLevel);
        Assert.Equal(4, result.ApprovedByUnitId);
    }

    /// <summary>
    /// 测试等级与审批单位不一致时抛出异常
    /// </summary>
    [Fact]
    public async Task ApproveAsync_LevelMismatch_ShouldThrowException()
    {
        // Arrange
        var personnel = CreateValidPersonnel();
        _context.Personnel.Add(personnel);
        await _context.SaveChangesAsync();

        // Act & Assert - 团级单位尝试分配师级人才
        await Assert.ThrowsAsync<ArgumentException>(() =>
            _personnelService.ApproveAsync(personnel.Id, 2, PersonnelLevel.Division));
    }

    #endregion

    #region 更新和删除测试

    /// <summary>
    /// 测试更新人员信息
    /// </summary>
    [Fact]
    public async Task UpdateAsync_ValidPersonnel_ShouldUpdateSuccessfully()
    {
        // Arrange
        var personnel = CreateValidPersonnel();
        _context.Personnel.Add(personnel);
        await _context.SaveChangesAsync();

        personnel.Name = "更新后的姓名";
        personnel.Position = "更新后的职位";

        // Act
        var result = await _personnelService.UpdateAsync(personnel);

        // Assert
        Assert.Equal("更新后的姓名", result.Name);
        Assert.Equal("更新后的职位", result.Position);
    }

    /// <summary>
    /// 测试删除人员 - 人员不存在时抛出异常
    /// </summary>
    [Fact]
    public async Task DeleteAsync_NonExistentPersonnel_ShouldThrowException()
    {
        // Act & Assert
        await Assert.ThrowsAsync<ArgumentException>(() =>
            _personnelService.DeleteAsync(999));
    }

    #endregion

    #region 审批路由测试 (需求6.3)

    /// <summary>
    /// 测试获取审批目标单位 - 下级单位提交给上级审批
    /// </summary>
    [Fact]
    public async Task GetApprovalTargetUnitAsync_SubordinateUnit_ShouldReturnParentUnit()
    {
        // Arrange - 团级单位提交
        var regimentId = 2;

        // Act
        var result = await _personnelService.GetApprovalTargetUnitAsync(regimentId);

        // Assert - 应该返回师团级别
        Assert.NotNull(result);
        Assert.Equal(OrganizationalLevel.Division, result.Level);
    }

    /// <summary>
    /// 测试获取审批目标单位 - 师团级别自己审批
    /// </summary>
    [Fact]
    public async Task GetApprovalTargetUnitAsync_DivisionUnit_ShouldReturnSelf()
    {
        // Arrange - 师团级单位提交
        var divisionId = 1;

        // Act
        var result = await _personnelService.GetApprovalTargetUnitAsync(divisionId);

        // Assert - 应该返回自己
        Assert.NotNull(result);
        Assert.Equal(1, result.Id);
    }

    /// <summary>
    /// 测试获取审批目标单位 - 单位不存在时抛出异常
    /// </summary>
    [Fact]
    public async Task GetApprovalTargetUnitAsync_NonExistentUnit_ShouldThrowException()
    {
        // Act & Assert
        await Assert.ThrowsAsync<ArgumentException>(() =>
            _personnelService.GetApprovalTargetUnitAsync(999));
    }

    #endregion

    public void Dispose()
    {
        _context.Dispose();
    }
}