using GestionIntegral.Api.Dtos.Impresion; using GestionIntegral.Api.Services.Impresion; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Logging; using System; using System.Collections.Generic; using System.Security.Claims; using System.Threading.Tasks; namespace GestionIntegral.Api.Controllers.Impresion { [Route("api/[controller]")] // Ruta base: /api/stockbobinas [ApiController] [Authorize] public class StockBobinasController : ControllerBase { private readonly IStockBobinaService _stockBobinaService; private readonly ILogger _logger; // Permisos para Stock de Bobinas (IB001 a IB005) private const string PermisoVerStock = "IB001"; private const string PermisoIngresarBobina = "IB002"; private const string PermisoCambiarEstado = "IB003"; private const string PermisoModificarDatos = "IB004"; // Para bobinas "Disponibles" private const string PermisoEliminarBobina = "IB005"; // Para ingresos erróneos "Disponibles" public StockBobinasController(IStockBobinaService stockBobinaService, ILogger logger) { _stockBobinaService = stockBobinaService; _logger = logger; } private bool TienePermiso(string codAcc) => User.IsInRole("SuperAdmin") || User.HasClaim(c => c.Type == "permission" && c.Value == codAcc); private int? GetCurrentUserId() { if (int.TryParse(User.FindFirstValue(ClaimTypes.NameIdentifier) ?? User.FindFirstValue("sub"), out int userId)) return userId; _logger.LogWarning("No se pudo obtener el UserId del token JWT en StockBobinasController."); return null; } // GET: api/stockbobinas [HttpGet] [ProducesResponseType(typeof(IEnumerable), StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status403Forbidden)] public async Task GetAllStockBobinas( [FromQuery] int? idTipoBobina, [FromQuery] string? nroBobina, [FromQuery] int? idPlanta, [FromQuery] int? idEstadoBobina, [FromQuery] string? remito, [FromQuery] DateTime? fechaDesde, [FromQuery] DateTime? fechaHasta) { if (!TienePermiso(PermisoVerStock)) return Forbid(); try { var bobinas = await _stockBobinaService.ObtenerTodosAsync(idTipoBobina, nroBobina, idPlanta, idEstadoBobina, remito, fechaDesde, fechaHasta); return Ok(bobinas); } catch (Exception ex) { _logger.LogError(ex, "Error al obtener el stock de bobinas."); return StatusCode(StatusCodes.Status500InternalServerError, "Error interno al procesar la solicitud."); } } // GET: api/stockbobinas/{idBobina} [HttpGet("{idBobina:int}", Name = "GetStockBobinaById")] [ProducesResponseType(typeof(StockBobinaDto), StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status403Forbidden)] [ProducesResponseType(StatusCodes.Status404NotFound)] public async Task GetStockBobinaById(int idBobina) { if (!TienePermiso(PermisoVerStock)) return Forbid(); var bobina = await _stockBobinaService.ObtenerPorIdAsync(idBobina); if (bobina == null) return NotFound(new { message = $"Bobina con ID {idBobina} no encontrada." }); return Ok(bobina); } // POST: api/stockbobinas (Ingresar nueva bobina) [HttpPost] [ProducesResponseType(typeof(StockBobinaDto), StatusCodes.Status201Created)] [ProducesResponseType(StatusCodes.Status400BadRequest)] [ProducesResponseType(StatusCodes.Status403Forbidden)] public async Task IngresarBobina([FromBody] CreateStockBobinaDto createDto) { if (!TienePermiso(PermisoIngresarBobina)) return Forbid(); if (!ModelState.IsValid) return BadRequest(ModelState); var userId = GetCurrentUserId(); if (userId == null) return Unauthorized(); var (dto, error) = await _stockBobinaService.IngresarBobinaAsync(createDto, userId.Value); if (error != null) return BadRequest(new { message = error }); if (dto == null) return StatusCode(StatusCodes.Status500InternalServerError, "Error al ingresar la bobina."); return CreatedAtRoute("GetStockBobinaById", new { idBobina = dto.IdBobina }, dto); } // PUT: api/stockbobinas/{idBobina}/datos (Actualizar datos de una bobina DISPONIBLE) [HttpPut("{idBobina:int}/datos")] [ProducesResponseType(StatusCodes.Status204NoContent)] [ProducesResponseType(StatusCodes.Status400BadRequest)] [ProducesResponseType(StatusCodes.Status403Forbidden)] [ProducesResponseType(StatusCodes.Status404NotFound)] public async Task UpdateDatosBobinaDisponible(int idBobina, [FromBody] UpdateStockBobinaDto updateDto) { if (!TienePermiso(PermisoModificarDatos)) return Forbid(); if (!ModelState.IsValid) return BadRequest(ModelState); var userId = GetCurrentUserId(); if (userId == null) return Unauthorized(); var (exito, error) = await _stockBobinaService.ActualizarDatosBobinaDisponibleAsync(idBobina, updateDto, userId.Value); if (!exito) { if (error == "Bobina no encontrada.") return NotFound(new { message = error }); return BadRequest(new { message = error }); } return NoContent(); } // PUT: api/stockbobinas/{idBobina}/cambiar-estado [HttpPut("{idBobina:int}/cambiar-estado")] [ProducesResponseType(StatusCodes.Status204NoContent)] [ProducesResponseType(StatusCodes.Status400BadRequest)] [ProducesResponseType(StatusCodes.Status403Forbidden)] [ProducesResponseType(StatusCodes.Status404NotFound)] public async Task CambiarEstadoBobina(int idBobina, [FromBody] CambiarEstadoBobinaDto cambiarEstadoDto) { if (!TienePermiso(PermisoCambiarEstado)) return Forbid(); if (!ModelState.IsValid) return BadRequest(ModelState); var userId = GetCurrentUserId(); if (userId == null) return Unauthorized(); // Validación adicional en el controlador para el caso "En Uso" if (cambiarEstadoDto.NuevoEstadoId == 2) // Asumiendo 2 = En Uso { if (!cambiarEstadoDto.IdPublicacion.HasValue || cambiarEstadoDto.IdPublicacion.Value <= 0) return BadRequest(new { message = "Se requiere IdPublicacion para el estado 'En Uso'."}); if (!cambiarEstadoDto.IdSeccion.HasValue || cambiarEstadoDto.IdSeccion.Value <=0) return BadRequest(new { message = "Se requiere IdSeccion para el estado 'En Uso'."}); } var (exito, error) = await _stockBobinaService.CambiarEstadoBobinaAsync(idBobina, cambiarEstadoDto, userId.Value); if (!exito) { if (error == "Bobina no encontrada.") return NotFound(new { message = error }); return BadRequest(new { message = error }); } return NoContent(); } // DELETE: api/stockbobinas/{idBobina} (Eliminar un ingreso erróneo, solo si está "Disponible") [HttpDelete("{idBobina:int}")] [ProducesResponseType(StatusCodes.Status204NoContent)] [ProducesResponseType(StatusCodes.Status400BadRequest)] // Si no está disponible o no se puede borrar [ProducesResponseType(StatusCodes.Status403Forbidden)] [ProducesResponseType(StatusCodes.Status404NotFound)] public async Task DeleteIngresoBobina(int idBobina) { if (!TienePermiso(PermisoEliminarBobina)) return Forbid(); var userId = GetCurrentUserId(); if (userId == null) return Unauthorized(); var (exito, error) = await _stockBobinaService.EliminarIngresoErroneoAsync(idBobina, userId.Value); if (!exito) { if (error == "Bobina no encontrada.") return NotFound(new { message = error }); return BadRequest(new { message = error }); // Ej: "No está disponible" } return NoContent(); } } }