using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using SIGCM.Application.DTOs;
using SIGCM.Infrastructure.Repositories;
using SIGCM.Domain.Entities; // <-- Faltaba para AuditLog
using System.Security.Claims;
using SIGCM.Infrastructure.Services; // <-- Recomendado para claridad en User.FindFirst

namespace SIGCM.API.Controllers;

[ApiController]
[Route("api/[controller]")]
[Authorize]
public class CashSessionsController : ControllerBase
{
  private readonly CashSessionRepository _repo;
  private readonly AuditRepository _auditRepo; // <-- AGREGADO: Declaración del campo

  // ACTUALIZADO: Inyección de ambos repositorios en el constructor
  public CashSessionsController(CashSessionRepository repo, AuditRepository auditRepo)
  {
    _repo = repo;
    _auditRepo = auditRepo;
  }

  [HttpGet("status")]
  public async Task<IActionResult> GetStatus()
  {
    var userIdClaim = User.FindFirst("Id")?.Value;
    if (string.IsNullOrEmpty(userIdClaim) || !int.TryParse(userIdClaim, out int userId))
      return Unauthorized();

    var session = await _repo.GetActiveSessionAsync(userId);
    return Ok(new { isOpen = session != null, session });
  }

  [HttpPost("open")]
  public async Task<IActionResult> Open([FromBody] CashOpeningDto dto)
  {
    var userIdClaim = User.FindFirst("Id")?.Value;
    if (!int.TryParse(userIdClaim, out int userId)) return Unauthorized();

    var existing = await _repo.GetActiveSessionAsync(userId);
    if (existing != null) return BadRequest("Ya tienes una caja abierta");

    var id = await _repo.OpenSessionAsync(userId, dto.OpeningBalance);

    // Opcional: Auditar la apertura
    await _auditRepo.AddLogAsync(new AuditLog
    {
      UserId = userId,
      Action = "CASH_SESSION_OPENED",
      EntityId = id,
      EntityType = "CashSession",
      Details = $"Caja abierta con fondo: ${dto.OpeningBalance}",
      CreatedAt = DateTime.UtcNow
    });

    return Ok(new { id });
  }

  [HttpPost("close")]
  public async Task<IActionResult> Close(CashClosingDto dto)
  {
    var userIdClaim = User.FindFirst("Id")?.Value;
    if (!int.TryParse(userIdClaim, out int userId)) return Unauthorized();

    var session = await _repo.GetActiveSessionAsync(userId);
    if (session == null) return BadRequest("No hay una sesión activa para cerrar");

    var system = await _repo.GetSystemTotalsAsync(userId, session.OpeningDate, DateTime.UtcNow);

    session.DeclaredCash = dto.DeclaredCash;
    session.DeclaredCards = dto.DeclaredDebit + dto.DeclaredCredit;
    session.DeclaredTransfers = dto.DeclaredTransfer;

    session.SystemExpectedCash = (decimal)(system.Cash ?? 0m);
    session.SystemExpectedCards = (decimal)(system.Cards ?? 0m);
    session.SystemExpectedTransfers = (decimal)(system.Transfers ?? 0m);

    decimal totalExpected = session.SystemExpectedCash.Value + session.OpeningBalance +
                            session.SystemExpectedCards.Value + session.SystemExpectedTransfers.Value;

    decimal totalDeclared = dto.DeclaredCash + dto.DeclaredDebit + dto.DeclaredCredit + dto.DeclaredTransfer;

    session.TotalDifference = totalDeclared - totalExpected;

    await _repo.CloseSessionAsync(session);

    // Auditar el cierre
    await _auditRepo.AddLogAsync(new AuditLog
    {
      UserId = userId,
      Action = "CASH_SESSION_CLOSED",
      EntityId = session.Id,
      EntityType = "CashSession",
      Details = $"Caja cerrada por el usuario. Diferencia detectada: ${session.TotalDifference}",
      CreatedAt = DateTime.UtcNow
    });

    return Ok(new
    {
      message = "Caja cerrada. Pendiente de validación por supervisor.",
      difference = session.TotalDifference,
      sessionId = session.Id
    });
  }

  [HttpGet("summary")]
  public async Task<IActionResult> GetSummary()
  {
    var userIdClaim = User.FindFirst("Id")?.Value;
    if (!int.TryParse(userIdClaim, out int userId)) return Unauthorized();

    var session = await _repo.GetActiveSessionAsync(userId);
    if (session == null) return BadRequest("No hay sesión activa");

    var system = await _repo.GetSystemTotalsAsync(userId, session.OpeningDate, DateTime.UtcNow);

    return Ok(new
    {
      openingBalance = session.OpeningBalance,
      cashSales = (decimal)(system.Cash ?? 0m),
      cardSales = (decimal)(system.Cards ?? 0m),
      transferSales = (decimal)(system.Transfers ?? 0m),
      totalExpected = session.OpeningBalance + (decimal)(system.Cash ?? 0m) + (decimal)(system.Cards ?? 0m) + (decimal)(system.Transfers ?? 0m)
    });
  }

  [HttpGet("pending")]
  [Authorize(Roles = "Admin")]
  public async Task<IActionResult> GetPending()
  {
    var pending = await _repo.GetPendingValidationAsync();
    return Ok(pending);
  }

  [HttpPost("{id}/validate")]
  [Authorize(Roles = "Admin")]
  public async Task<IActionResult> Validate(int id, [FromBody] string notes)
  {
    var adminIdClaim = User.FindFirst("Id")?.Value;
    if (!int.TryParse(adminIdClaim, out int adminId)) return Unauthorized();

    await _repo.ValidateSessionAsync(id, adminId, notes);

    await _auditRepo.AddLogAsync(new AuditLog
    {
      UserId = adminId,
      Action = "CASH_SESSION_VALIDATED",
      EntityId = id,
      EntityType = "CashSession",
      Details = $"Caja #{id} validada y liquidada. Notas: {notes}",
      CreatedAt = DateTime.UtcNow
    });

    return Ok(new { message = "Sesión liquidada correctamente" });
  }

  [HttpGet("{id}/pdf")]
  public async Task<IActionResult> DownloadPdf(int id)
  {
    var session = await _repo.GetSessionDetailAsync(id);
    if (session == null) return NotFound();

    var pdfBytes = ReportGenerator.GenerateCashSessionPdf(session);
    string fileName = $"Acta_Cierre_{id}_{DateTime.Now:yyyyMMdd}.pdf";

    return File(pdfBytes, "application/pdf", fileName);
  }
}