using GestionIntegral.Api.Dtos.Zonas; // Para los DTOs using GestionIntegral.Api.Services.Distribucion; // Para IZonaService using Microsoft.AspNetCore.Authorization; // Para [Authorize] using Microsoft.AspNetCore.Mvc; using System.Security.Claims; namespace GestionIntegral.Api.Controllers.Distribucion { [Route("api/[controller]")] [ApiController] [Authorize] // <-- Protección GENERAL: El usuario debe estar logueado public class ZonasController : ControllerBase { private readonly IZonaService _zonaService; private readonly ILogger _logger; public ZonasController(IZonaService zonaService, ILogger logger) { _zonaService = zonaService; _logger = logger; } // Helper para verificar permisos directamente desde los claims del token private bool TienePermiso(string codAccRequerido) { // SuperAdmin siempre tiene permiso if (User.IsInRole("SuperAdmin")) return true; // Busca si el claim 'permission' con el valor requerido existe return User.HasClaim(c => c.Type == "permission" && c.Value == codAccRequerido); } // Helper para obtener el ID del usuario del token 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 ZonasController."); return null; } // GET: api/zonas [HttpGet] [ProducesResponseType(typeof(IEnumerable), StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status403Forbidden)] public async Task GetAllZonas([FromQuery] string? nombre, [FromQuery] string? descripcion) { // Verificar permiso ZD001 if (!TienePermiso("ZD001")) { _logger.LogWarning("Acceso denegado a GetAllZonas para el usuario {UserId}", GetCurrentUserId() ?? 0); return Forbid(); // Devolver 403 Forbidden } try { var zonas = await _zonaService.ObtenerTodasAsync(nombre, descripcion); return Ok(zonas); } catch (Exception ex) { _logger.LogError(ex, "Error al obtener todas las Zonas."); return StatusCode(StatusCodes.Status500InternalServerError, "Error interno al procesar la solicitud."); } } // GET: api/zonas/{id} [HttpGet("{id:int}", Name = "GetZonaById")] [ProducesResponseType(typeof(ZonaDto), StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status403Forbidden)] [ProducesResponseType(StatusCodes.Status404NotFound)] public async Task GetZonaById(int id) { if (!TienePermiso("ZD001")) return Forbid(); try { var zona = await _zonaService.ObtenerPorIdAsync(id); if (zona == null) { return NotFound(new { message = $"Zona con ID {id} no encontrada o inactiva." }); } return Ok(zona); } catch (Exception ex) { _logger.LogError(ex, "Error al obtener Zona por ID: {Id}", id); return StatusCode(StatusCodes.Status500InternalServerError, "Error interno al procesar la solicitud."); } } // POST: api/zonas [HttpPost] [ProducesResponseType(typeof(ZonaDto), StatusCodes.Status201Created)] [ProducesResponseType(StatusCodes.Status400BadRequest)] [ProducesResponseType(StatusCodes.Status403Forbidden)] public async Task CreateZona([FromBody] CreateZonaDto createDto) { if (!TienePermiso("ZD002")) 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 (zonaCreada, error) = await _zonaService.CrearAsync(createDto, idUsuario.Value); if (error != null) return BadRequest(new { message = error }); if (zonaCreada == null) return StatusCode(StatusCodes.Status500InternalServerError, "Error al crear la zona."); return CreatedAtRoute("GetZonaById", new { id = zonaCreada.IdZona }, zonaCreada); } catch (Exception ex) { _logger.LogError(ex, "Error al crear Zona. Nombre: {Nombre}", createDto.Nombre); return StatusCode(StatusCodes.Status500InternalServerError, "Error interno al procesar la solicitud."); } } // PUT: api/zonas/{id} [HttpPut("{id:int}")] [ProducesResponseType(StatusCodes.Status204NoContent)] [ProducesResponseType(StatusCodes.Status400BadRequest)] [ProducesResponseType(StatusCodes.Status403Forbidden)] [ProducesResponseType(StatusCodes.Status404NotFound)] public async Task UpdateZona(int id, [FromBody] UpdateZonaDto updateDto) { if (!TienePermiso("ZD003")) 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 _zonaService.ActualizarAsync(id, updateDto, idUsuario.Value); if (!exito) { if (error != null && (error.Contains("no encontrada") || error.Contains("eliminada (inactiva)"))) return NotFound(new { message = error }); return BadRequest(new { message = error ?? "Error desconocido al actualizar." }); } return NoContent(); } catch (Exception ex) { _logger.LogError(ex, "Error al actualizar Zona ID: {Id}", id); return StatusCode(StatusCodes.Status500InternalServerError, "Error interno al procesar la solicitud."); } } // DELETE: api/zonas/{id} [HttpDelete("{id:int}")] [ProducesResponseType(StatusCodes.Status204NoContent)] [ProducesResponseType(StatusCodes.Status400BadRequest)] // Si está en uso [ProducesResponseType(StatusCodes.Status403Forbidden)] [ProducesResponseType(StatusCodes.Status404NotFound)] public async Task DeleteZona(int id) { if (!TienePermiso("ZD004")) 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 _zonaService.EliminarAsync(id, idUsuario.Value); if (!exito) { if (error == "Zona no encontrada.") return NotFound(new { message = error }); return BadRequest(new { message = error ?? "Error desconocido al eliminar." }); // Ej: "En uso" } return NoContent(); } catch (Exception ex) { _logger.LogError(ex, "Error al eliminar Zona ID: {Id}", id); return StatusCode(StatusCodes.Status500InternalServerError, "Error interno al procesar la solicitud."); } } } }