using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using MilitaryTrainingManagement.Authorization;
using MilitaryTrainingManagement.Models.DTOs;
using MilitaryTrainingManagement.Models.Enums;
using MilitaryTrainingManagement.Services.Interfaces;

namespace MilitaryTrainingManagement.Controllers;

/// <summary>
/// 物资配额控制器
/// </summary>
[Authorize]
public class AllocationsController : BaseApiController
{
    private readonly IAllocationService _allocationService;
    private readonly IOrganizationalAuthorizationService _authorizationService;
    private readonly IAuditService _auditService;

    public AllocationsController(
        IAllocationService allocationService,
        IOrganizationalAuthorizationService authorizationService,
        IAuditService auditService)
    {
        _allocationService = allocationService;
        _authorizationService = authorizationService;
        _auditService = auditService;
    }
    
    private string? GetClientIpAddress()
    {
        return HttpContext.Connection.RemoteIpAddress?.ToString();
    }

    /// <summary>
    /// 获取当前用户可见的所有物资配额
    /// </summary>
    [HttpGet]
    public async Task<IActionResult> GetAll(
        [FromQuery] int pageNumber = 1,
        [FromQuery] int pageSize = 10)
    {
        var unitId = GetCurrentUnitId();
        var unitLevel = GetCurrentUnitLevel();

        if (unitId == null || unitLevel == null)
            return Unauthorized(new { message = "无法获取用户组织信息" });

        // 师团级可以看到所有配额，其他级别只能看到分配给自己及下级的配额
        IEnumerable<Models.Entities.MaterialAllocation> allAllocations;
        if (unitLevel == OrganizationalLevel.Division)
        {
            allAllocations = await _allocationService.GetAllAsync();
        }
        else
        {
            allAllocations = await _allocationService.GetVisibleToUnitAsync(unitId.Value);
        }

        var totalCount = allAllocations.Count();
        
        // 对于营部及以下级别，需要过滤分配记录并计算可见范围内的上报总和
        List<AllocationResponse> items;
        if (unitLevel == OrganizationalLevel.Battalion || unitLevel == OrganizationalLevel.Company)
        {
            items = new List<AllocationResponse>();
            foreach (var allocation in allAllocations.Skip((pageNumber - 1) * pageSize).Take(pageSize))
            {
                var filteredAllocation = await FilterAllocationDistributions(allocation, unitId.Value, unitLevel.Value);
                var response = MapToResponse(filteredAllocation);
                // 计算可见范围内的上报总和
                response.VisibleActualCompletion = await _allocationService.GetVisibleActualCompletionAsync(
                    allocation.Id, unitId.Value, unitLevel.Value);
                items.Add(response);
            }
        }
        else
        {
            items = allAllocations
                .Skip((pageNumber - 1) * pageSize)
                .Take(pageSize)
                .Select(MapToResponse)
                .ToList();
        }

        return Ok(new
        {
            items,
            totalCount,
            pageNumber,
            pageSize,
            totalPages = (int)Math.Ceiling(totalCount / (double)pageSize)
        });
    }

    /// <summary>
    /// 获取当前单位创建的物资配额
    /// </summary>
    [HttpGet("my")]
    public async Task<IActionResult> GetMyAllocations()
    {
        var unitId = GetCurrentUnitId();
        if (unitId == null)
            return Unauthorized(new { message = "无法获取用户组织信息" });

        var allocations = await _allocationService.GetByUnitAsync(unitId.Value);
        var response = allocations.Select(MapToResponse);
        return Ok(response);
    }

    /// <summary>
    /// 获取分配给当前单位的配额分配记录
    /// </summary>
    [HttpGet("distributions")]
    public async Task<IActionResult> GetMyDistributions()
    {
        var unitId = GetCurrentUnitId();
        if (unitId == null)
            return Unauthorized(new { message = "无法获取用户组织信息" });

        var distributions = await _allocationService.GetDistributionsForUnitAsync(unitId.Value);
        var response = distributions.Select(MapDistributionToResponse);
        return Ok(response);
    }

    /// <summary>
    /// 根据ID获取物资配额
    /// 需求1.1, 1.2, 1.3：营部及以下级别用户只能查看本单位及直接下级的配额
    /// </summary>
    [HttpGet("{id}")]
    public async Task<IActionResult> GetById(int id)
    {
        var unitId = GetCurrentUnitId();
        var unitLevel = GetCurrentUnitLevel();
        if (unitId == null || unitLevel == null)
            return Unauthorized(new { message = "无法获取用户组织信息" });

        var allocation = await _allocationService.GetByIdAsync(id);
        if (allocation == null)
            return NotFound(new { message = "配额不存在" });

        // 检查访问权限：
        // 1. 可以查看自己创建的配额
        // 2. 使用可见性过滤检查是否可以访问配额中的任何一个分配记录
        var canAccess = allocation.CreatedByUnitId == unitId.Value;
        
        if (!canAccess)
        {
            // 检查是否有任何分配记录在用户的可见范围内
            foreach (var dist in allocation.Distributions)
            {
                if (await _allocationService.CanViewDistributionAsync(unitId.Value, unitLevel.Value, dist.TargetUnitId))
                {
                    canAccess = true;
                    break;
                }
            }
        }

        if (!canAccess)
            return Forbid();

        // 过滤分配记录，只返回用户可见范围内的记录
        var filteredAllocation = await FilterAllocationDistributions(allocation, unitId.Value, unitLevel.Value);

        return Ok(MapToResponse(filteredAllocation));
    }

    /// <summary>
    /// 过滤配额的分配记录，只保留用户可见范围内的记录
    /// </summary>
    private async Task<Models.Entities.MaterialAllocation> FilterAllocationDistributions(
        Models.Entities.MaterialAllocation allocation, 
        int userUnitId, 
        OrganizationalLevel userLevel)
    {
        var visibleDistributions = new List<Models.Entities.AllocationDistribution>();
        
        foreach (var dist in allocation.Distributions)
        {
            if (await _allocationService.CanViewDistributionAsync(userUnitId, userLevel, dist.TargetUnitId))
            {
                visibleDistributions.Add(dist);
            }
        }

        // 创建一个新的配额对象，只包含可见的分配记录
        return new Models.Entities.MaterialAllocation
        {
            Id = allocation.Id,
            Category = allocation.Category,
            MaterialName = allocation.MaterialName,
            Unit = allocation.Unit,
            TotalQuota = allocation.TotalQuota,
            CreatedByUnitId = allocation.CreatedByUnitId,
            CreatedByUnit = allocation.CreatedByUnit,
            CreatedAt = allocation.CreatedAt,
            Distributions = visibleDistributions
        };
    }

    /// <summary>
    /// 创建物资配额
    /// 需求2.1：师团管理员可以创建物资类别
    /// 需求2.2：创建配额需要物资名称、单位、总配额和目标单位
    /// 需求2.4：创建后自动分发给目标单位
    /// </summary>
    [HttpPost]
    [Authorize(Policy = "DivisionLevel")]
    public async Task<IActionResult> Create([FromBody] CreateAllocationRequest request)
    {
        var unitId = GetCurrentUnitId();
        var userId = GetCurrentUserId();
        if (unitId == null)
            return Unauthorized(new { message = "无法获取用户组织信息" });

        // 验证必填字段
        if (!ModelState.IsValid)
            return BadRequest(ModelState);

        try
        {
            var allocation = await _allocationService.CreateAsync(
                request.Category,
                request.MaterialName,
                request.Unit,
                request.TotalQuota,
                unitId.Value,
                request.GetDistributionsDictionary());

            // 记录审计日志
            await _auditService.LogApprovalAsync(
                "MaterialAllocation",
                allocation.Id,
                "Create",
                $"创建物资配额：{request.Category} - {request.MaterialName}，总配额：{request.TotalQuota}{request.Unit}",
                userId,
                unitId,
                GetClientIpAddress());

            return CreatedAtAction(nameof(GetById), new { id = allocation.Id }, MapToResponse(allocation));
        }
        catch (ArgumentException ex)
        {
            return BadRequest(new { message = ex.Message });
        }
    }

    /// <summary>
    /// 更新物资配额基本信息
    /// </summary>
    [HttpPut("{id}")]
    [Authorize(Policy = "DivisionLevel")]
    public async Task<IActionResult> Update(int id, [FromBody] UpdateAllocationRequest request)
    {
        var unitId = GetCurrentUnitId();
        var userId = GetCurrentUserId();
        if (unitId == null)
            return Unauthorized(new { message = "无法获取用户组织信息" });

        // 验证必填字段
        if (!ModelState.IsValid)
            return BadRequest(ModelState);

        // 检查配额是否存在
        var existingAllocation = await _allocationService.GetByIdAsync(id);
        if (existingAllocation == null)
            return NotFound(new { message = "配额不存在" });

        // 检查是否有权限修改（只能修改自己创建的配额）
        if (existingAllocation.CreatedByUnitId != unitId.Value)
            return Forbid();

        try
        {
            var allocation = await _allocationService.UpdateAsync(
                id,
                request.Category,
                request.MaterialName,
                request.Unit,
                request.TotalQuota);

            // 记录审计日志
            await _auditService.LogApprovalAsync(
                "MaterialAllocation",
                id,
                "Update",
                $"更新物资配额：{request.Category} - {request.MaterialName}，总配额：{request.TotalQuota}{request.Unit}",
                userId,
                unitId,
                GetClientIpAddress());

            return Ok(MapToResponse(await _allocationService.GetByIdAsync(id) ?? allocation));
        }
        catch (ArgumentException ex)
        {
            return BadRequest(new { message = ex.Message });
        }
    }

    /// <summary>
    /// 更新配额分配记录
    /// </summary>
    [HttpPut("{id}/distributions")]
    [Authorize(Policy = "DivisionLevel")]
    public async Task<IActionResult> UpdateDistributions(int id, [FromBody] Dictionary<int, decimal> distributions)
    {
        var unitId = GetCurrentUnitId();
        var userId = GetCurrentUserId();
        if (unitId == null)
            return Unauthorized(new { message = "无法获取用户组织信息" });

        // 检查配额是否存在
        var existingAllocation = await _allocationService.GetByIdAsync(id);
        if (existingAllocation == null)
            return NotFound(new { message = "配额不存在" });

        // 检查是否有权限修改
        if (existingAllocation.CreatedByUnitId != unitId.Value)
            return Forbid();

        try
        {
            var allocation = await _allocationService.UpdateDistributionsAsync(id, distributions);
            
            // 记录审计日志
            await _auditService.LogApprovalAsync(
                "AllocationDistribution",
                id,
                "Update",
                $"更新配额分配：{existingAllocation.MaterialName}，分配给 {distributions.Count} 个单位",
                userId,
                unitId,
                GetClientIpAddress());
            
            return Ok(MapToResponse(allocation));
        }
        catch (ArgumentException ex)
        {
            return BadRequest(new { message = ex.Message });
        }
    }

    /// <summary>
    /// 上报消耗 - 更新单个分配记录的实际完成数量
    /// 团部及以下单位可以上报自己的消耗数据
    /// </summary>
    [HttpPut("distributions/{distributionId}")]
    public async Task<IActionResult> UpdateDistribution(int distributionId, [FromBody] UpdateDistributionRequest request)
    {
        var unitId = GetCurrentUnitId();
        var userId = GetCurrentUserId();
        
        if (unitId == null || userId == null)
            return Unauthorized(new { message = "无法获取用户信息" });

        try
        {
            var distribution = await _allocationService.UpdateDistributionCompletionAsync(
                distributionId, 
                unitId.Value, 
                userId.Value,
                request.ActualCompletion,
                request.Remarks);

            // 记录审计日志
            var materialName = distribution.Allocation?.MaterialName ?? "未知物资";
            await _auditService.LogApprovalAsync(
                "ConsumptionReport",
                distributionId,
                "Create",
                $"上报消耗：{materialName}，数量：{request.ActualCompletion}，备注：{request.Remarks ?? "无"}",
                userId,
                unitId,
                GetClientIpAddress());

            return Ok(MapDistributionToResponse(distribution));
        }
        catch (UnauthorizedAccessException ex)
        {
            return Forbid();
        }
        catch (ArgumentException ex)
        {
            return BadRequest(new { message = ex.Message });
        }
    }

    /// <summary>
    /// 删除物资配额
    /// </summary>
    [HttpDelete("{id}")]
    [Authorize(Policy = "DivisionLevel")]
    public async Task<IActionResult> Delete(int id)
    {
        var unitId = GetCurrentUnitId();
        var userId = GetCurrentUserId();
        if (unitId == null)
            return Unauthorized(new { message = "无法获取用户组织信息" });

        // 检查配额是否存在
        var existingAllocation = await _allocationService.GetByIdAsync(id);
        if (existingAllocation == null)
            return NotFound(new { message = "配额不存在" });

        // 检查是否有权限删除
        if (existingAllocation.CreatedByUnitId != unitId.Value)
            return Forbid();

        try
        {
            var materialName = existingAllocation.MaterialName;
            var category = existingAllocation.Category;
            
            await _allocationService.DeleteAsync(id);
            
            // 记录审计日志
            await _auditService.LogApprovalAsync(
                "MaterialAllocation",
                id,
                "Delete",
                $"删除物资配额：{category} - {materialName}",
                userId,
                unitId,
                GetClientIpAddress());
            
            return NoContent();
        }
        catch (ArgumentException ex)
        {
            return BadRequest(new { message = ex.Message });
        }
    }

    /// <summary>
    /// 验证配额分配是否有效
    /// </summary>
    [HttpPost("validate")]
    public async Task<IActionResult> ValidateDistributions([FromBody] CreateAllocationRequest request)
    {
        var distributions = request.GetDistributionsDictionary();
        
        var isValid = await _allocationService.ValidateDistributionQuotasAsync(
            request.TotalQuota, 
            distributions);

        var targetUnitsExist = await _allocationService.ValidateTargetUnitsExistAsync(
            distributions.Keys);

        return Ok(new
        {
            quotaValid = isValid,
            targetUnitsExist = targetUnitsExist,
            isValid = isValid && targetUnitsExist,
            message = !isValid ? "有配额未分配，无法提交" :
                      !targetUnitsExist ? "目标单位不存在" : "验证通过"
        });
    }

    /// <summary>
    /// 获取配额分配的上报历史记录
    /// 需求1.1, 1.2, 1.3：营部及以下级别用户只能查看本单位及直接下级的记录
    /// </summary>
    [HttpGet("distributions/{distributionId}/reports")]
    public async Task<IActionResult> GetConsumptionReports(int distributionId)
    {
        var unitId = GetCurrentUnitId();
        var unitLevel = GetCurrentUnitLevel();
        
        if (unitId == null || unitLevel == null)
            return Unauthorized(new { message = "无法获取用户组织信息" });

        // 检查分配记录是否存在
        var distribution = await _allocationService.GetDistributionByIdAsync(distributionId);
        if (distribution == null)
            return NotFound(new { message = "配额分配记录不存在" });

        // 使用可见性过滤检查访问权限
        // 营部及以下级别：只能查看本单位及直接下级的记录
        // 师团/团级：可以查看所有下级的记录
        var canAccess = await _allocationService.CanViewDistributionAsync(
            unitId.Value, 
            unitLevel.Value, 
            distribution.TargetUnitId);
        
        if (!canAccess)
            return Forbid();

        // 获取上报历史记录（带可见性过滤）
        // 只返回用户可见范围内的单位的上报记录
        var reports = await _allocationService.GetConsumptionReportsAsync(distributionId, unitId.Value, unitLevel.Value);
        var response = reports.Select(r => new
        {
            id = r.Id,
            reportedAmount = r.ReportedAmount,
            cumulativeAmount = r.CumulativeAmount,
            remarks = r.Remarks,
            reportedByUserName = r.ReportedByUser?.DisplayName,
            reportedByUnitId = r.ReportedByUnitId,
            reportedAt = r.ReportedAt
        });

        return Ok(response);
    }

    /// <summary>
    /// 获取按单位汇总的上报数据
    /// </summary>
    [HttpGet("distributions/{distributionId}/summary")]
    public async Task<IActionResult> GetReportSummaryByUnit(int distributionId, [FromQuery] string? period = null)
    {
        var unitId = GetCurrentUnitId();
        var unitLevel = GetCurrentUnitLevel();
        
        if (unitId == null || unitLevel == null)
            return Unauthorized(new { message = "无法获取用户组织信息" });

        // 检查分配记录是否存在
        var distribution = await _allocationService.GetDistributionByIdAsync(distributionId);
        if (distribution == null)
            return NotFound(new { message = "配额分配记录不存在" });

        // 计算时间范围
        DateTime? startDate = null;
        DateTime? endDate = null;
        if (!string.IsNullOrEmpty(period) && period != "all")
        {
            endDate = DateTime.Now;
            startDate = period switch
            {
                "week" => endDate.Value.AddDays(-7),
                "month" => endDate.Value.AddMonths(-1),
                "halfYear" => endDate.Value.AddMonths(-6),
                "year" => endDate.Value.AddYears(-1),
                _ => null
            };
        }

        // 获取按单位汇总的上报数据
        var summaries = await _allocationService.GetReportSummaryByUnitAsync(distributionId, unitId.Value, unitLevel.Value, startDate, endDate);
        
        return Ok(summaries);
    }

    /// <summary>
    /// 获取配额的消耗统计（按时间范围）
    /// 师部账号可以按周、月、半年、年度查看所有团的总消耗
    /// </summary>
    [HttpGet("{id}/consumption-stats")]
    [Authorize(Policy = "DivisionLevel")]
    public async Task<IActionResult> GetConsumptionStats(int id, [FromQuery] string period = "month")
    {
        var unitId = GetCurrentUnitId();
        var unitLevel = GetCurrentUnitLevel();
        
        if (unitId == null || unitLevel == null)
            return Unauthorized(new { message = "无法获取用户组织信息" });

        // 检查配额是否存在
        var allocation = await _allocationService.GetByIdAsync(id);
        if (allocation == null)
            return NotFound(new { message = "配额不存在" });

        // 计算时间范围
        var endDate = DateTime.Now;
        var startDate = period switch
        {
            "week" => endDate.AddDays(-7),
            "month" => endDate.AddMonths(-1),
            "halfYear" => endDate.AddMonths(-6),
            "year" => endDate.AddYears(-1),
            _ => endDate.AddMonths(-1)
        };

        // 获取按单位汇总的消耗统计
        var stats = await _allocationService.GetConsumptionStatsByPeriodAsync(id, startDate, endDate);
        
        return Ok(new
        {
            allocationId = id,
            materialName = allocation.MaterialName,
            unit = allocation.Unit,
            totalQuota = allocation.TotalQuota,
            period,
            startDate,
            endDate,
            unitStats = stats
        });
    }

    /// <summary>
    /// 映射实体到响应DTO
    /// </summary>
    private static AllocationResponse MapToResponse(Models.Entities.MaterialAllocation allocation)
    {
        return new AllocationResponse
        {
            Id = allocation.Id,
            Category = allocation.Category,
            MaterialName = allocation.MaterialName,
            Unit = allocation.Unit,
            TotalQuota = allocation.TotalQuota,
            CreatedByUnitId = allocation.CreatedByUnitId,
            CreatedByUnitName = allocation.CreatedByUnit?.Name ?? string.Empty,
            CreatedAt = allocation.CreatedAt,
            Distributions = allocation.Distributions.Select(d => new AllocationDistributionResponse
            {
                Id = d.Id,
                TargetUnitId = d.TargetUnitId,
                TargetUnitName = d.TargetUnit?.Name ?? string.Empty,
                UnitQuota = d.UnitQuota,
                ActualCompletion = d.ActualCompletion,
                CompletionRate = d.CompletionRate,
                ReportedAt = d.ReportedAt,
                ReportedByUserName = d.ReportedByUser?.DisplayName
            }).ToList()
        };
    }

    /// <summary>
    /// 映射分配记录到响应DTO
    /// </summary>
    private static AllocationDistributionResponse MapDistributionToResponse(Models.Entities.AllocationDistribution distribution)
    {
        return new AllocationDistributionResponse
        {
            Id = distribution.Id,
            TargetUnitId = distribution.TargetUnitId,
            TargetUnitName = distribution.TargetUnit?.Name ?? string.Empty,
            UnitQuota = distribution.UnitQuota,
            ActualCompletion = distribution.ActualCompletion,
            CompletionRate = distribution.CompletionRate,
            ReportedAt = distribution.ReportedAt,
            ReportedByUserName = distribution.ReportedByUser?.DisplayName
        };
    }
}
