using GestionIntegral.Api.Dtos.Distribucion; using GestionIntegral.Api.Services.Distribucion; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Logging; using System; using System.Collections.Generic; using System.Linq; using System.Security.Claims; using System.Threading.Tasks; namespace GestionIntegral.Api.Controllers.Distribucion { [Route("api/novedadescanilla")] // Ruta base más genérica para las novedades [ApiController] [Authorize] // Todas las acciones requieren autenticación public class NovedadesCanillaController : ControllerBase { private readonly INovedadCanillaService _novedadService; private readonly ILogger _logger; public NovedadesCanillaController(INovedadCanillaService novedadService, ILogger logger) { _novedadService = novedadService; _logger = logger; } // --- Helper para verificar permisos --- private bool TienePermiso(string codAccRequerido) { if (User.IsInRole("SuperAdmin")) return true; return User.HasClaim(c => c.Type == "permission" && c.Value == codAccRequerido); } // --- Helper para obtener User ID --- private int? GetCurrentUserId() { var userIdClaim = User.FindFirstValue(ClaimTypes.NameIdentifier) ?? User.FindFirstValue("sub"); if (int.TryParse(userIdClaim, out int userId)) { return userId; } _logger.LogWarning("No se pudo obtener el UserId del token JWT en NovedadesCanillaController."); return null; } // GET: api/novedadescanilla/porcanilla/{idCanilla} // Obtiene todas las novedades para un canillita específico, opcionalmente filtrado por fecha. // Permiso: CG001 (Ver Canillas) o CG006 (Gestionar Novedades). // Si CG006 es "Permite la Carga/Modificación", entonces CG001 podría ser más apropiado solo para ver. // Vamos a usar CG001 para ver. Si se quiere más granularidad, se puede crear un permiso "Ver Novedades". [HttpGet("porcanilla/{idCanilla:int}")] [ProducesResponseType(typeof(IEnumerable), StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status403Forbidden)] [ProducesResponseType(StatusCodes.Status500InternalServerError)] public async Task GetNovedadesPorCanilla(int idCanilla, [FromQuery] DateTime? fechaDesde, [FromQuery] DateTime? fechaHasta) { if (!TienePermiso("CG001") && !TienePermiso("CG006")) // Necesita al menos uno de los dos { _logger.LogWarning("Acceso denegado a GetNovedadesPorCanilla para el usuario {UserId} y canillita {IdCanilla}", GetCurrentUserId() ?? 0, idCanilla); return Forbid(); } try { var novedades = await _novedadService.ObtenerPorCanillaAsync(idCanilla, fechaDesde, fechaHasta); return Ok(novedades); } catch (Exception ex) { _logger.LogError(ex, "Error al obtener novedades para Canillita ID: {IdCanilla}", idCanilla); return StatusCode(StatusCodes.Status500InternalServerError, "Error interno al obtener las novedades."); } } // GET: api/novedadescanilla/{idNovedad} // Obtiene una novedad específica por su ID. // Permiso: CG001 o CG006 [HttpGet("{idNovedad:int}", Name = "GetNovedadCanillaById")] [ProducesResponseType(typeof(NovedadCanillaDto), StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status403Forbidden)] [ProducesResponseType(StatusCodes.Status404NotFound)] [ProducesResponseType(StatusCodes.Status500InternalServerError)] public async Task GetNovedadCanillaById(int idNovedad) { if (!TienePermiso("CG001") && !TienePermiso("CG006")) return Forbid(); try { var novedad = await _novedadService.ObtenerPorIdAsync(idNovedad); if (novedad == null) { return NotFound(new { message = $"Novedad con ID {idNovedad} no encontrada." }); } return Ok(novedad); } catch (Exception ex) { _logger.LogError(ex, "Error al obtener NovedadCanilla por ID: {IdNovedad}", idNovedad); return StatusCode(StatusCodes.Status500InternalServerError, "Error interno al obtener la novedad."); } } // POST: api/novedadescanilla // Crea una nueva novedad. El IdCanilla viene en el DTO. // Permiso: CG006 (Permite la Carga/Modificación de Novedades) [HttpPost] [ProducesResponseType(typeof(NovedadCanillaDto), StatusCodes.Status201Created)] [ProducesResponseType(StatusCodes.Status400BadRequest)] [ProducesResponseType(StatusCodes.Status401Unauthorized)] [ProducesResponseType(StatusCodes.Status403Forbidden)] [ProducesResponseType(StatusCodes.Status500InternalServerError)] public async Task CreateNovedadCanilla([FromBody] CreateNovedadCanillaDto createDto) { if (!TienePermiso("CG006")) return Forbid(); if (!ModelState.IsValid) return BadRequest(ModelState); var idUsuario = GetCurrentUserId(); if (idUsuario == null) return Unauthorized("No se pudo obtener el ID del usuario del token."); try { var (novedadCreada, error) = await _novedadService.CrearAsync(createDto, idUsuario.Value); if (error != null) return BadRequest(new { message = error }); if (novedadCreada == null) return StatusCode(StatusCodes.Status500InternalServerError, "Error al crear la novedad."); // Devuelve la ruta al recurso creado y el recurso mismo return CreatedAtRoute("GetNovedadCanillaById", new { idNovedad = novedadCreada.IdNovedad }, novedadCreada); } catch (Exception ex) { _logger.LogError(ex, "Error al crear NovedadCanilla para Canilla ID: {IdCanilla} por Usuario ID: {UsuarioId}", createDto.IdCanilla, idUsuario); return StatusCode(StatusCodes.Status500InternalServerError, "Error interno al crear la novedad."); } } // PUT: api/novedadescanilla/{idNovedad} // Actualiza una novedad existente. // Permiso: CG006 [HttpPut("{idNovedad:int}")] [ProducesResponseType(StatusCodes.Status204NoContent)] [ProducesResponseType(StatusCodes.Status400BadRequest)] [ProducesResponseType(StatusCodes.Status401Unauthorized)] [ProducesResponseType(StatusCodes.Status403Forbidden)] [ProducesResponseType(StatusCodes.Status404NotFound)] [ProducesResponseType(StatusCodes.Status500InternalServerError)] public async Task UpdateNovedadCanilla(int idNovedad, [FromBody] UpdateNovedadCanillaDto updateDto) { if (!TienePermiso("CG006")) return Forbid(); if (!ModelState.IsValid) return BadRequest(ModelState); var idUsuario = GetCurrentUserId(); if (idUsuario == null) return Unauthorized("No se pudo obtener el ID del usuario del token."); try { var (exito, error) = await _novedadService.ActualizarAsync(idNovedad, updateDto, idUsuario.Value); if (!exito) { if (error == "Novedad no encontrada.") return NotFound(new { message = error }); return BadRequest(new { message = error }); } return NoContent(); } catch (Exception ex) { _logger.LogError(ex, "Error al actualizar NovedadCanilla ID: {IdNovedad} por Usuario ID: {UsuarioId}", idNovedad, idUsuario); return StatusCode(StatusCodes.Status500InternalServerError, "Error interno al actualizar la novedad."); } } // DELETE: api/novedadescanilla/{idNovedad} // Elimina una novedad. // Permiso: CG006 (Asumiendo que el mismo permiso para Carga/Modificación incluye eliminación) // Si la eliminación es un permiso separado (ej: CG00X), ajústalo. [HttpDelete("{idNovedad:int}")] [ProducesResponseType(StatusCodes.Status204NoContent)] [ProducesResponseType(StatusCodes.Status401Unauthorized)] [ProducesResponseType(StatusCodes.Status403Forbidden)] [ProducesResponseType(StatusCodes.Status404NotFound)] [ProducesResponseType(StatusCodes.Status500InternalServerError)] public async Task DeleteNovedadCanilla(int idNovedad) { if (!TienePermiso("CG006")) return Forbid(); var idUsuario = GetCurrentUserId(); if (idUsuario == null) return Unauthorized("No se pudo obtener el ID del usuario del token."); try { var (exito, error) = await _novedadService.EliminarAsync(idNovedad, idUsuario.Value); if (!exito) { if (error == "Novedad no encontrada.") return NotFound(new { message = error }); return BadRequest(new { message = error }); // Podría ser otro error, como "no se pudo eliminar" } return NoContent(); } catch (Exception ex) { _logger.LogError(ex, "Error al eliminar NovedadCanilla ID: {IdNovedad} por Usuario ID: {UsuarioId}", idNovedad, idUsuario); return StatusCode(StatusCodes.Status500InternalServerError, "Error interno al eliminar la novedad."); } } } }