package com.sigem.gis.security; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.web.bind.annotation.*; import com.sigem.gis.service.FdwService; import java.util.Base64; import java.util.List; import java.util.Map; @RestController @RequestMapping("/api/auth") public class AuthController { @Autowired private JwtUtil jwtUtil; @Autowired @Qualifier("masterJdbcTemplate") private JdbcTemplate masterJdbcTemplate; @Autowired @Qualifier("gisJdbcTemplate") private JdbcTemplate gisJdbcTemplate; @Autowired private FdwService fdwService; @GetMapping("/entidades") public ResponseEntity getEntidadesActivas() { try { String sql = "select entidad, nombre, entidad_logo, responsable, eslogan from public.entidades WHERE activo = TRUE ORDER BY entidad ASC"; List> entidades = masterJdbcTemplate.queryForList(sql); return ResponseEntity.ok(entidades); } catch (Exception e) { e.printStackTrace(); return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("Error al cargar entidades"); } } @PostMapping("/login") public ResponseEntity login(@RequestBody AuthRequest request) { try { // 1. Validar existencia de entidad en directorio maestro (en el .254) String sqlEntidades = "SELECT sigem_site, sigem_dbname, lat, lng, zoom, minzoom, maxzoom, mapa_base, boundno, boundse, nombre, eslogan, entidad_logo, responsable FROM public.entidades WHERE activo= TRUE AND entidad = ?"; List> entidades = masterJdbcTemplate.queryForList(sqlEntidades, Integer.parseInt(request.getEntidad())); if (entidades.isEmpty()) { return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body(new AuthResponse(null, null, "La MUNICIPALIDAD con código " + request.getEntidad() + " no existe o está inactiva.")); } Map entidadData = entidades.get(0); String nombreEntidad = convertObjectToString(entidadData.get("nombre")); String eslogan = convertObjectToString(entidadData.get("eslogan")); // Tratamiento especial para el logo (Binario -> Base64) Object logoObj = entidadData.get("entidad_logo"); String logo = (logoObj instanceof byte[]) ? Base64.getEncoder().encodeToString((byte[]) logoObj) : convertObjectToString(logoObj); String responsable = convertObjectToString(entidadData.get("responsable")); // 2. Asegurar Infraestructura FDW (Regla 16: Solo crea si no existe) fdwService.setupFdw(request.getEntidad(), false); String schemaName = "fdw_" + request.getEntidad(); System.out.println("Validando usuario vía FDW local para entidad: " + request.getEntidad()); // 3. Buscar Usuario en el esquema FDW local (en el .123) String sqlUser = "SELECT usu_nom, usu_ape, activo, pgp_sym_decrypt(usu_clave_a::bytea, '510580', 'compress-algo=0, cipher-algo=aes256')::text as clave_desencriptada " + "FROM " + schemaName + ".usuarios " + "WHERE usu_alias = ? AND ejer_fisca = date_part('year', now())"; List> usuarios = gisJdbcTemplate.queryForList(sqlUser, request.getUsername()); if (!usuarios.isEmpty()) { Map userData = usuarios.get(0); boolean isActivo = (boolean) userData.get("activo"); String claveDesencriptada = convertObjectToString(userData.get("clave_desencriptada")); // 4. Validación Final y Generación de Token if (isActivo && request.getPassword().equals(claveDesencriptada)) { String token = jwtUtil.generateToken(request.getUsername(), request.getEntidad()); String nombreCompleto = convertObjectToString(userData.get("usu_nom")) + " " + convertObjectToString(userData.get("usu_ape")); // Metadatos georreferenciados de la entidad Double lat = parseDouble(entidadData.get("lat"), -25.456443); Double lng = parseDouble(entidadData.get("lng"), -56.446949); Integer zoom = parseInteger(entidadData.get("zoom"), 14); Integer minZoom = parseInteger(entidadData.get("minzoom"), 5); Integer maxZoom = parseInteger(entidadData.get("maxzoom"), 20); String mapaBase = convertObjectToString(entidadData.getOrDefault("mapa_base", "osm")); String bounds = convertObjectToString(entidadData.getOrDefault("boundno", "")) + "|" + convertObjectToString(entidadData.getOrDefault("boundse", "")); return ResponseEntity.ok(new AuthResponse(token, nombreCompleto, "Login Exitoso", lat, lng, zoom, minZoom, maxZoom, mapaBase, bounds, nombreEntidad, eslogan, logo, responsable)); } } return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body(new AuthResponse(null, null, "Credenciales Inválidas o Cuenta de Baja")); } catch (Exception e) { e.printStackTrace(); return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(new AuthResponse(null, null, "Fallo interno en el Microservicio SaaS: " + e.toString())); } } private String convertObjectToString(Object val) { if (val == null) return null; if (val instanceof byte[]) { return new String((byte[]) val); } return String.valueOf(val); } private Double parseDouble(Object val, Double def) { if (val == null) return def; try { String str = convertObjectToString(val); return Double.parseDouble(str.trim()); } catch (Exception e) { return def; } } private Integer parseInteger(Object val, Integer def) { if (val == null) return def; try { String str = convertObjectToString(val); return Integer.parseInt(str.trim()); } catch (Exception e) { return def; } } }