RolController.java

package com.licensis.notaire.api;

import com.licensis.notaire.negocio.Rol;
import com.licensis.notaire.negocio.Usuario;
import com.licensis.notaire.repository.RolRepository;
import com.licensis.notaire.repository.UsuarioRepository;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Valid;
import jakarta.validation.constraints.NotBlank;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.Map;
import java.util.Optional;

@RestController
@RequestMapping("/api/v1/roles")
@Tag(name = "Roles", description = "API para gestionar roles y permisos de usuario")
public class RolController {

    private final RolRepository rolRepository;
    private final UsuarioRepository usuarioRepository;

    public RolController(RolRepository rolRepository, UsuarioRepository usuarioRepository) {
        this.rolRepository = rolRepository;
        this.usuarioRepository = usuarioRepository;
    }

    record RolResponse(Integer idRol, String nombre, String descripcion, boolean activo, List<String> modulos) {}

    record RolRequest(@NotBlank String nombre, String descripcion, boolean activo, List<String> modulos) {}

    private RolResponse toResponse(Rol rol) {
        return new RolResponse(rol.getIdRol(), rol.getNombre(), rol.getDescripcion(),
                rol.isActivo(), rol.getModulos());
    }

    @GetMapping
    @Operation(summary = "Obtener todos los roles")
    @Transactional(readOnly = true)
    public ResponseEntity<List<RolResponse>> getAllRoles() {
        return ResponseEntity.ok(rolRepository.findAll().stream().map(this::toResponse).toList());
    }

    @ApiResponses({
    @ApiResponse(responseCode = "200", description = "OK"),
    @ApiResponse(responseCode = "404", description = "No encontrado")
})
    @GetMapping("/{id}")
    @Operation(summary = "Obtener rol por ID")
    @Transactional(readOnly = true)
    public ResponseEntity<RolResponse> getRolById(@PathVariable Integer id) {
        return rolRepository.findById(id)
                .map(this::toResponse)
                .map(ResponseEntity::ok)
                .orElse(ResponseEntity.notFound().build());
    }

    @ApiResponses({
    @ApiResponse(responseCode = "201", description = "Creado"),
    @ApiResponse(responseCode = "400", description = "Solicitud inválida"),
    @ApiResponse(responseCode = "409", description = "Conflicto")
})
    @PostMapping
    @Operation(summary = "Crear nuevo rol")
    public ResponseEntity<Object> createRol(@Valid @RequestBody RolRequest request) {
        if (rolRepository.findByNombre(request.nombre()).isPresent()) {
            return ResponseEntity.status(HttpStatus.CONFLICT)
                    .body(Map.of("error", "Ya existe un rol con el nombre: " + request.nombre()));
        }
        Rol rol = new Rol();
        rol.setNombre(request.nombre());
        rol.setDescripcion(request.descripcion());
        rol.setActivo(request.activo());
        rol.setModulos(request.modulos() != null ? request.modulos() : List.of());
        Rol saved = rolRepository.save(rol);
        return ResponseEntity.status(HttpStatus.CREATED).body(toResponse(saved));
    }

    @ApiResponses({
    @ApiResponse(responseCode = "200", description = "OK"),
    @ApiResponse(responseCode = "404", description = "No encontrado")
})
    @PutMapping("/{id}")
    @Operation(summary = "Actualizar rol")
    public ResponseEntity<RolResponse> updateRol(@PathVariable Integer id, @Valid @RequestBody RolRequest request) {
        Optional<Rol> existing = rolRepository.findById(id);
        if (existing.isEmpty()) {
            return ResponseEntity.notFound().build();
        }
        Rol rol = existing.get();
        rol.setNombre(request.nombre());
        rol.setDescripcion(request.descripcion());
        rol.setActivo(request.activo());
        rol.setModulos(request.modulos() != null ? request.modulos() : List.of());
        return ResponseEntity.ok(toResponse(rolRepository.save(rol)));
    }

    @ApiResponses({
    @ApiResponse(responseCode = "204", description = "Eliminado"),
    @ApiResponse(responseCode = "404", description = "No encontrado")
})
    @DeleteMapping("/{id}")
    @Operation(summary = "Eliminar rol")
    public ResponseEntity<Void> deleteRol(@PathVariable Integer id) {
        if (!rolRepository.existsById(id)) {
            return ResponseEntity.notFound().build();
        }
        rolRepository.deleteById(id);
        return ResponseEntity.noContent().build();
    }

    @PutMapping("/{idRol}/usuarios/{idUsuario}")
    @Operation(summary = "Asignar rol a usuario")
    public ResponseEntity<Object> assignRolToUsuario(@PathVariable Integer idRol,
                                                      @PathVariable Integer idUsuario) {
        Optional<Rol> rol = rolRepository.findById(idRol);
        if (rol.isEmpty()) {
            return ResponseEntity.notFound().build();
        }
        Optional<Usuario> usuario = usuarioRepository.findById(idUsuario);
        if (usuario.isEmpty()) {
            return ResponseEntity.notFound().build();
        }
        usuario.get().setRol(rol.get());
        usuarioRepository.save(usuario.get());
        return ResponseEntity.ok(Map.of("idUsuario", idUsuario, "idRol", idRol));
    }

    @DeleteMapping("/usuarios/{idUsuario}")
    @Operation(summary = "Desasignar rol de usuario")
    public ResponseEntity<Void> unassignRolFromUsuario(@PathVariable Integer idUsuario) {
        Optional<Usuario> usuario = usuarioRepository.findById(idUsuario);
        if (usuario.isEmpty()) {
            return ResponseEntity.notFound().build();
        }
        usuario.get().setRol(null);
        usuarioRepository.save(usuario.get());
        return ResponseEntity.noContent().build();
    }
}