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")] [Authorize(Roles = "Admin,GerenteVentas")] 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")] [Authorize(Roles = "Admin,GerenteVentas")] 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")] [Authorize(Roles = "Admin")] public async Task GetAuditLogs([FromQuery] DateTime? from, [FromQuery] DateTime? to, [FromQuery] int? userId) { var start = from ?? DateTime.UtcNow.Date; var end = to ?? DateTime.UtcNow.AddDays(1).Date.AddSeconds(-1); var logs = await _auditRepo.GetFilteredLogsAsync(start, end, userId); 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( [FromQuery] DateTime? from, [FromQuery] DateTime? to, [FromQuery] int? userId) { // 1. Obtener datos del usuario logueado var userIdClaim = User.FindFirst("Id")?.Value; var userRole = User.FindFirst(System.Security.Claims.ClaimTypes.Role)?.Value; if (string.IsNullOrEmpty(userIdClaim)) return Unauthorized(); // 2. Lógica de seguridad para el filtro de usuario: // Si es Admin, puede ver a cualquier cajero (usa el userId que viene por query). // Si es Cajero, SOLO puede verse a sí mismo (forzamos su propio ID). int? targetUserId = (userRole == "Admin") ? userId : int.Parse(userIdClaim); // 3. Manejo de fechas: // Si no vienen, usamos el rango de hoy. // Pero el frontend enviará los valores de los selectores. var startDate = from ?? DateTime.UtcNow.Date; var endDate = to ?? DateTime.UtcNow.Date; // Llamamos al repositorio con las fechas REALES enviadas desde el frontend var transactions = await _listingRepo.GetDetailedReportAsync(startDate, endDate, targetUserId); return Ok(transactions); } [HttpGet("cajeros")] [Authorize(Roles = "Cajero,Admin")] public async Task GetCajeros() { var cajeros = await _listingRepo.GetActiveCashiersAsync(); return Ok(cajeros); } }