using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using SIGCM.Application.DTOs;
using SIGCM.Domain.Entities;
using SIGCM.Infrastructure.Repositories;

namespace SIGCM.API.Controllers;

[ApiController]
[Route("api/[controller]")]
[Authorize]
public class CashClosingController : ControllerBase
{
    private readonly CashClosingRepository _closingRepo;
    private readonly AuditRepository _auditRepo;

    public CashClosingController(CashClosingRepository closingRepo, AuditRepository auditRepo)
    {
        _closingRepo = closingRepo;
        _auditRepo = auditRepo;
    }

    /// <summary>
    /// Procesar cierre de caja con arqueo ciego
    /// El cajero declara sus totales sin ver primero lo que dice el sistema
    /// </summary>
    [HttpPost("close")]
    [Authorize(Roles = "Cajero,Admin")]
    public async Task<IActionResult> CloseCash(CashClosingDto dto)
    {
        // Obtener usuario actual del JWT
        var userIdClaim = User.FindFirst("Id")?.Value;
        if (!int.TryParse(userIdClaim, out int userId))
        {
            return Unauthorized("Usuario no identificado");
        }

        // Obtener los totales reales del sistema para el día actual
        var today = DateTime.UtcNow.Date;
        var systemTotals = await _closingRepo.GetPaymentTotalsByMethodAsync(userId, today);

        // Calcular diferencias
        var closing = new CashClosing
        {
            UserId = userId,
            ClosingDate = DateTime.UtcNow,
            
            // Valores declarados por el cajero
            DeclaredCash = dto.DeclaredCash,
            DeclaredDebit = dto.DeclaredDebit,
            DeclaredCredit = dto.DeclaredCredit,
            DeclaredTransfer = dto.DeclaredTransfer,
            
            // Valores del sistema
            SystemCash = systemTotals["Cash"],
            SystemDebit = systemTotals["Debit"],
            SystemCredit = systemTotals["Credit"],
            SystemTransfer = systemTotals["Transfer"],
            
            // Cálculo de diferencias
            CashDifference = dto.DeclaredCash - systemTotals["Cash"],
            DebitDifference = dto.DeclaredDebit - systemTotals["Debit"],
            CreditDifference = dto.DeclaredCredit - systemTotals["Credit"],
            TransferDifference = dto.DeclaredTransfer - systemTotals["Transfer"],
            
            // Totales
            TotalDeclared = dto.DeclaredCash + dto.DeclaredDebit + dto.DeclaredCredit + dto.DeclaredTransfer,
            TotalSystem = systemTotals["Cash"] + systemTotals["Debit"] + systemTotals["Credit"] + systemTotals["Transfer"],
            
            Notes = dto.Notes
        };

        // Calcular diferencia total
        closing.TotalDifference = closing.TotalDeclared - closing.TotalSystem;
        
        // Detectar discrepancias (tolerancia de $10 pesos)
        closing.HasDiscrepancies = Math.Abs(closing.TotalDifference) > 10;

        // Guardar el cierre
        var closingId = await _closingRepo.CreateAsync(closing);

        // Registrar en auditoría
        await _auditRepo.AddLogAsync(new AuditLog
        {
            UserId = userId,
            Action = "CASH_CLOSING",
            EntityId = closingId,
            EntityType = "CashClosing",
            Details = $"Cierre de caja. Diferencia: ${closing.TotalDifference}. Discrepancias: {closing.HasDiscrepancies}",
            CreatedAt = DateTime.UtcNow
        });

        // Preparar respuesta
        var result = new CashClosingResultDto
        {
            ClosingId = closingId,
            
            DeclaredCash = closing.DeclaredCash,
            DeclaredDebit = closing.DeclaredDebit,
            DeclaredCredit = closing.DeclaredCredit,
            DeclaredTransfer = closing.DeclaredTransfer,
            TotalDeclared = closing.TotalDeclared,
            
            SystemCash = closing.SystemCash,
            SystemDebit = closing.SystemDebit,
            SystemCredit = closing.SystemCredit,
            SystemTransfer = closing.SystemTransfer,
            TotalSystem = closing.TotalSystem,
            
            CashDifference = closing.CashDifference,
            DebitDifference = closing.DebitDifference,
            CreditDifference = closing.CreditDifference,
            TransferDifference = closing.TransferDifference,
            TotalDifference = closing.TotalDifference,
            
            HasDiscrepancies = closing.HasDiscrepancies,
            Message = closing.HasDiscrepancies 
                ? "⚠️ ATENCIÓN: Se detectaron diferencias en el cierre. Un supervisor revisará tu caja." 
                : "✅ Cierre correcto. No se detectaron diferencias."
        };

        return Ok(result);
    }

    /// <summary>
    /// Obtener cierres con discrepancias pendientes de aprobación (Solo Admin)
    /// </summary>
    [HttpGet("discrepancies")]
    [Authorize(Roles = "Admin")]
    public async Task<IActionResult> GetDiscrepancies()
    {
        var discrepancies = await _closingRepo.GetDiscrepanciesAsync();
        return Ok(discrepancies);
    }

    /// <summary>
    /// Aprobar un cierre de caja con discrepancias (Solo Admin)
    /// </summary>
    [HttpPost("{id}/approve")]
    [Authorize(Roles = "Admin")]
    public async Task<IActionResult> ApproveClosure(int id)
    {
        await _closingRepo.ApproveAsync(id);
        
        // Registrar en auditoría
        var userIdClaim = User.FindFirst("Id")?.Value;
        if (int.TryParse(userIdClaim, out int userId))
        {
            await _auditRepo.AddLogAsync(new AuditLog
            {
                UserId = userId,
                Action = "APPROVE_CASH_CLOSING",
                EntityId = id,
                EntityType = "CashClosing",
                Details = "Cierre de caja aprobado por administrador",
                CreatedAt = DateTime.UtcNow
            });
        }
        
        return Ok(new { message = "Cierre aprobado exitosamente" });
    }

    /// <summary>
    /// Obtener historial de cierres del usuario actual
    /// </summary>
    [HttpGet("history")]
    [Authorize(Roles = "Cajero,Admin")]
    public async Task<IActionResult> GetHistory([FromQuery] DateTime? from, [FromQuery] DateTime? to)
    {
        var userIdClaim = User.FindFirst("Id")?.Value;
        if (!int.TryParse(userIdClaim, out int userId))
        {
            return Unauthorized();
        }

        var startDate = from ?? DateTime.UtcNow.AddMonths(-1);
        var endDate = to ?? DateTime.UtcNow;

        var closings = await _closingRepo.GetByUserAsync(userId, startDate, endDate);
        return Ok(closings);
    }
}
