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

namespace MilitaryTrainingManagement.Tests.Services;

/// <summary>
/// 组织管理服务单元测试
/// 测试组织单位创建和层级验证
/// 测试组织关系管理
/// _需求：1.1, 1.2_
/// </summary>
public class OrganizationServiceTests : IDisposable
{
    private readonly ApplicationDbContext _context;
    private readonly OrganizationService _service;

    public OrganizationServiceTests()
    {
        var options = new DbContextOptionsBuilder<ApplicationDbContext>()
            .UseInMemoryDatabase(databaseName: Guid.NewGuid().ToString())
            .Options;
        _context = new ApplicationDbContext(options);
        _service = new OrganizationService(_context);
    }

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

    #region 创建组织单位测试

    [Fact]
    public async Task CreateAsync_Division_WithoutParent_ShouldSucceed()
    {
        // Arrange & Act
        var unit = await _service.CreateAsync("第一师", OrganizationalLevel.Division, null);

        // Assert
        Assert.NotNull(unit);
        Assert.Equal("第一师", unit.Name);
        Assert.Equal(OrganizationalLevel.Division, unit.Level);
        Assert.Null(unit.ParentId);
    }

    [Fact]
    public async Task CreateAsync_Regiment_WithDivisionParent_ShouldSucceed()
    {
        // Arrange
        var division = await _service.CreateAsync("第一师", OrganizationalLevel.Division, null);

        // Act
        var regiment = await _service.CreateAsync("第一团", OrganizationalLevel.Regiment, division.Id);

        // Assert
        Assert.NotNull(regiment);
        Assert.Equal(OrganizationalLevel.Regiment, regiment.Level);
        Assert.Equal(division.Id, regiment.ParentId);
    }


    [Fact]
    public async Task CreateAsync_NonDivision_WithoutParent_ShouldThrowException()
    {
        // Arrange & Act & Assert
        var exception = await Assert.ThrowsAsync<ArgumentException>(
            () => _service.CreateAsync("第一团", OrganizationalLevel.Regiment, null));
        
        Assert.Contains("非师团级组织必须有父级单位", exception.Message);
    }

    [Fact]
    public async Task CreateAsync_WithInvalidParentId_ShouldThrowException()
    {
        // Arrange & Act & Assert
        var exception = await Assert.ThrowsAsync<ArgumentException>(
            () => _service.CreateAsync("第一团", OrganizationalLevel.Regiment, 999));
        
        Assert.Contains("父级组织单位不存在", exception.Message);
    }

    [Fact]
    public async Task CreateAsync_ChildLevelNotLowerThanParent_ShouldThrowException()
    {
        // Arrange
        var regiment = await _service.CreateAsync("第一师", OrganizationalLevel.Division, null);
        var battalion = await _service.CreateAsync("第一团", OrganizationalLevel.Regiment, regiment.Id);

        // Act & Assert - 尝试在团下创建师级单位
        var exception = await Assert.ThrowsAsync<ArgumentException>(
            () => _service.CreateAsync("错误单位", OrganizationalLevel.Division, battalion.Id));
        
        Assert.Contains("子级组织层级必须低于父级", exception.Message);
    }

    [Fact]
    public async Task CreateAsync_FourLevelHierarchy_ShouldSucceed()
    {
        // Arrange & Act - 创建完整的四级组织结构
        var division = await _service.CreateAsync("第一师", OrganizationalLevel.Division, null);
        var regiment = await _service.CreateAsync("第一团", OrganizationalLevel.Regiment, division.Id);
        var battalion = await _service.CreateAsync("第一营", OrganizationalLevel.Battalion, regiment.Id);
        var company = await _service.CreateAsync("第一连", OrganizationalLevel.Company, battalion.Id);

        // Assert
        Assert.Equal(OrganizationalLevel.Division, division.Level);
        Assert.Equal(OrganizationalLevel.Regiment, regiment.Level);
        Assert.Equal(OrganizationalLevel.Battalion, battalion.Level);
        Assert.Equal(OrganizationalLevel.Company, company.Level);
        
        Assert.Equal(division.Id, regiment.ParentId);
        Assert.Equal(regiment.Id, battalion.ParentId);
        Assert.Equal(battalion.Id, company.ParentId);
    }

    #endregion

    #region 查询组织单位测试

    [Fact]
    public async Task GetByIdAsync_ExistingUnit_ShouldReturnUnit()
    {
        // Arrange
        var division = await _service.CreateAsync("第一师", OrganizationalLevel.Division, null);

        // Act
        var result = await _service.GetByIdAsync(division.Id);

        // Assert
        Assert.NotNull(result);
        Assert.Equal(division.Id, result.Id);
        Assert.Equal("第一师", result.Name);
    }

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

        // Assert
        Assert.Null(result);
    }

    [Fact]
    public async Task GetAllAsync_ShouldReturnAllUnits()
    {
        // Arrange
        var division = await _service.CreateAsync("第一师", OrganizationalLevel.Division, null);
        var regiment = await _service.CreateAsync("第一团", OrganizationalLevel.Regiment, division.Id);

        // Act
        var result = await _service.GetAllAsync();

        // Assert
        Assert.Equal(2, result.Count());
    }

    #endregion


    #region 下级单位查询测试

    [Fact]
    public async Task GetSubordinatesAsync_ShouldReturnAllSubordinates()
    {
        // Arrange
        var division = await _service.CreateAsync("第一师", OrganizationalLevel.Division, null);
        var regiment = await _service.CreateAsync("第一团", OrganizationalLevel.Regiment, division.Id);
        var battalion = await _service.CreateAsync("第一营", OrganizationalLevel.Battalion, regiment.Id);
        var company = await _service.CreateAsync("第一连", OrganizationalLevel.Company, battalion.Id);

        // Act
        var subordinates = await _service.GetSubordinatesAsync(division.Id);

        // Assert - 师下面应该有团、营、连三个下级
        Assert.Equal(3, subordinates.Count());
        Assert.Contains(subordinates, u => u.Id == regiment.Id);
        Assert.Contains(subordinates, u => u.Id == battalion.Id);
        Assert.Contains(subordinates, u => u.Id == company.Id);
    }

    [Fact]
    public async Task GetSubordinatesAsync_NonExistingUnit_ShouldReturnEmpty()
    {
        // Act
        var result = await _service.GetSubordinatesAsync(999);

        // Assert
        Assert.Empty(result);
    }

    [Fact]
    public async Task IsSubordinateOfAsync_DirectChild_ShouldReturnTrue()
    {
        // Arrange
        var division = await _service.CreateAsync("第一师", OrganizationalLevel.Division, null);
        var regiment = await _service.CreateAsync("第一团", OrganizationalLevel.Regiment, division.Id);

        // Act
        var result = await _service.IsSubordinateOfAsync(regiment.Id, division.Id);

        // Assert
        Assert.True(result);
    }

    [Fact]
    public async Task IsSubordinateOfAsync_IndirectChild_ShouldReturnTrue()
    {
        // Arrange
        var division = await _service.CreateAsync("第一师", OrganizationalLevel.Division, null);
        var regiment = await _service.CreateAsync("第一团", OrganizationalLevel.Regiment, division.Id);
        var battalion = await _service.CreateAsync("第一营", OrganizationalLevel.Battalion, regiment.Id);

        // Act
        var result = await _service.IsSubordinateOfAsync(battalion.Id, division.Id);

        // Assert
        Assert.True(result);
    }

    [Fact]
    public async Task IsSubordinateOfAsync_NotSubordinate_ShouldReturnFalse()
    {
        // Arrange
        var division1 = await _service.CreateAsync("第一师", OrganizationalLevel.Division, null);
        var division2 = await _service.CreateAsync("第二师", OrganizationalLevel.Division, null);
        var regiment = await _service.CreateAsync("第一团", OrganizationalLevel.Regiment, division1.Id);

        // Act
        var result = await _service.IsSubordinateOfAsync(regiment.Id, division2.Id);

        // Assert
        Assert.False(result);
    }

    #endregion

    #region 更新和删除测试

    [Fact]
    public async Task UpdateAsync_ExistingUnit_ShouldUpdateName()
    {
        // Arrange
        var division = await _service.CreateAsync("第一师", OrganizationalLevel.Division, null);

        // Act
        var updated = await _service.UpdateAsync(division.Id, "第一师（更新）");

        // Assert
        Assert.Equal("第一师（更新）", updated.Name);
    }

    [Fact]
    public async Task UpdateAsync_NonExistingUnit_ShouldThrowException()
    {
        // Act & Assert
        var exception = await Assert.ThrowsAsync<ArgumentException>(
            () => _service.UpdateAsync(999, "不存在的单位"));
        
        Assert.Contains("组织单位不存在", exception.Message);
    }

    [Fact]
    public async Task DeleteAsync_UnitWithoutChildren_ShouldSucceed()
    {
        // Arrange
        var division = await _service.CreateAsync("第一师", OrganizationalLevel.Division, null);

        // Act
        await _service.DeleteAsync(division.Id);

        // Assert
        var result = await _service.GetByIdAsync(division.Id);
        Assert.Null(result);
    }

    [Fact]
    public async Task DeleteAsync_UnitWithChildren_ShouldThrowException()
    {
        // Arrange
        var division = await _service.CreateAsync("第一师", OrganizationalLevel.Division, null);
        await _service.CreateAsync("第一团", OrganizationalLevel.Regiment, division.Id);

        // Act & Assert
        var exception = await Assert.ThrowsAsync<InvalidOperationException>(
            () => _service.DeleteAsync(division.Id));
        
        Assert.Contains("无法删除有下级单位的组织", exception.Message);
    }

    [Fact]
    public async Task DeleteAsync_NonExistingUnit_ShouldThrowException()
    {
        // Act & Assert
        var exception = await Assert.ThrowsAsync<ArgumentException>(
            () => _service.DeleteAsync(999));
        
        Assert.Contains("组织单位不存在", exception.Message);
    }

    #endregion
}
