using System.Text; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using SIGCM.Domain.Interfaces; using SIGCM.Infrastructure.Repositories; using SIGCM.Infrastructure.Services; namespace SIGCM.API.Controllers; [ApiController] [Route("api/[controller]")] [Authorize(Roles = "Cajero,Admin")] public class ReportsController : ControllerBase { private readonly IListingRepository _listingRepo; private readonly AuditRepository _auditRepo; public ReportsController(IListingRepository listingRepo, AuditRepository auditRepo) { _listingRepo = listingRepo; _auditRepo = auditRepo; } [HttpGet("dashboard")] public async Task GetDashboard([FromQuery] DateTime? from, [FromQuery] DateTime? to) { var start = from ?? DateTime.UtcNow.Date; var end = to ?? DateTime.UtcNow.Date; var stats = await _listingRepo.GetDashboardStatsAsync(start, end); return Ok(stats); } [HttpGet("sales-by-category")] public async Task GetSalesByCategory([FromQuery] DateTime? from, [FromQuery] DateTime? to) { var start = from ?? DateTime.UtcNow.AddMonths(-1); var end = to ?? DateTime.UtcNow; var data = await _listingRepo.GetSalesByRootCategoryAsync(start, end); var totalAmount = data.Sum(x => x.TotalSales); if (totalAmount > 0) { foreach (var item in data) item.Percentage = Math.Round((item.TotalSales / totalAmount) * 100, 2); } return Ok(data); } [HttpGet("audit")] public async Task GetAuditLogs() { // Obtenemos los últimos 100 eventos var logs = await _auditRepo.GetRecentLogsAsync(100); return Ok(logs); } [HttpGet("cashier")] [Authorize(Roles = "Cajero,Admin")] public async Task GetCashierDashboard([FromQuery] DateTime? from, [FromQuery] DateTime? to) { var userIdClaim = User.FindFirst("Id")?.Value; if (string.IsNullOrEmpty(userIdClaim)) return Unauthorized(); int userId = int.Parse(userIdClaim); // Si no vienen fechas, usamos hoy por defecto var start = from ?? DateTime.UtcNow.Date; var end = to ?? DateTime.UtcNow.Date; var stats = await _listingRepo.GetCashierStatsAsync(userId, start, end); return Ok(stats); } [HttpGet("export-cierre")] [Authorize(Roles = "Admin,Cajero")] public async Task ExportCierre([FromQuery] DateTime from, [FromQuery] DateTime to, [FromQuery] int? userId) // <--- Agregamos userId opcional { var userIdClaim = User.FindFirst("Id")?.Value; var userRole = User.FindFirst(System.Security.Claims.ClaimTypes.Role)?.Value; // SEGURIDAD: // Si es Cajero, ignoramos lo que envíe y forzamos su propio ID. // Si es Admin, usamos el userId que venga en la URL (si viene). int? targetUserId = (userRole == "Cajero") ? int.Parse(userIdClaim!) : userId; // 1. Obtener datos filtrados var data = await _listingRepo.GetDetailedReportAsync(from, to, targetUserId); // 2. Título Dinámico: Si hay un filtro de usuario, no es un cierre global. string title = (targetUserId.HasValue) ? $"REPORTE DE ACTIVIDAD: {data.Items.FirstOrDefault()?.Cashier ?? "Usuario Sin Cargas"}" : "CIERRE GLOBAL DE JORNADA"; // 3. Generar PDF var pdfBytes = ReportGenerator.GenerateSalesPdf(data, title); string fileName = targetUserId.HasValue ? $"Actividad_Caja_{targetUserId}" : "Cierre_Global"; return File(pdfBytes, "application/pdf", $"{fileName}_{from:yyyyMMdd}.pdf"); } [HttpGet("audit/user/{userId}")] [Authorize(Roles = "Admin")] public async Task GetAuditLogsByUser(int userId) { var logs = await _auditRepo.GetLogsByUserAsync(userId); return Ok(logs); } [HttpGet("cashier-transactions")] [Authorize(Roles = "Cajero,Admin")] public async Task GetCashierTransactions() { var userIdClaim = User.FindFirst("Id")?.Value; if (string.IsNullOrEmpty(userIdClaim)) return Unauthorized(); int userId = int.Parse(userIdClaim); // Usamos el repositorio para traer los avisos de hoy de este usuario var transactions = await _listingRepo.GetDetailedReportAsync(DateTime.UtcNow, DateTime.UtcNow, userId); return Ok(transactions); } }