package com.dacrt.SBIABackend.config;

import org.jasypt.util.text.AES256TextEncryptor;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.env.EnvironmentPostProcessor;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.MapPropertySource;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class PropertyAutoEncryptor implements EnvironmentPostProcessor {

    @Override
    public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {
        System.out.println("====== [JASYPT-AUTO] INICIANDO PROCESADOR DE AUTO-ENCRIPTACIÓN ======");

        // 1. Apuntamos a la ruta externa exacta en Windows
     // 1. OBTENER LA RUTA DINÁMICAMENTE desde los argumentos del sistema o entorno
        String configLocation = environment.getProperty("spring.config.location");
        if (configLocation == null) {
            configLocation = System.getProperty("spring.config.location");
        }

        String externalPathStr = null;

        if (configLocation != null) {
            // Spring Boot a veces recibe rutas con prefijos como "file:"; los removemos para Java NIO
            if (configLocation.startsWith("file:")) {
                configLocation = configLocation.substring(5);
            }
            
            // Si pasan múltiples rutas separadas por coma, tomamos la primera
            if (configLocation.contains(",")) {
                configLocation = configLocation.split(",")[0].trim();
            }

            Path configPath = Paths.get(configLocation);
            
            // Si el argumento apunta a una carpeta en vez de a un archivo, asumimos el nombre estándar
            if (Files.isDirectory(configPath)) {
                String activeProfile = environment.getProperty("spring.profiles.active", "dev");
                externalPathStr = configPath.resolve("application-" + activeProfile + ".properties").toString();
            } else {
                externalPathStr = configLocation;
            }
            System.out.println("[JASYPT-AUTO] Ruta detectada dinámicamente: " + externalPathStr);
        } else {
            // Plan de respaldo (Fallback) si ejecutas el proyecto sin argumentos (ej. desde el IDE)
            System.out.println("[JASYPT-AUTO] ADVERTENCIA: No se detectó -Dspring.config.location. Usando ruta fija de respaldo.");
            externalPathStr = "C:\\Users\\Public\\config\\application-dev.properties";
        }

        Path path = Paths.get(externalPathStr); 
        
        if (!Files.exists(path)) {
            System.out.println("[JASYPT-AUTO] ADVERTENCIA: No se encontró el archivo externo en: " + externalPathStr);
            return; 
        }

        // 2. Configurar el encriptador manual con prioridades de contraseña
        AES256TextEncryptor encryptor = new AES256TextEncryptor();
        
        String password = environment.getProperty("jasypt.encryptor.password");
        if (password == null) {
            password = System.getProperty("jasypt.password");
        }
        if (password == null) {
            password = System.getenv("JASYPT_PASSWORD");
        }
        if (password == null) {
            System.out.println("[JASYPT-AUTO] ADVERTENCIA: No se detectó ninguna contraseña externa. Usando la por defecto.");
            password = "TuClaveSecretaPorDefecto"; 
        }
        encryptor.setPassword(password);

        Map<String, Object> springInMemoryProperties = new HashMap<>();
        boolean modified = false;

        // 3. Procesamos el archivo línea por línea como texto puro para mantener los formatos originales e inyectar a Spring
        try {
            List<String> lines = Files.readAllLines(path);
            List<String> newLines = new ArrayList<>();

            for (String line : lines) {
                // Ignoramos comentarios o líneas vacías sin alterarlas
                if (!line.contains("=") || line.trim().startsWith("#")) {
                    newLines.add(line);
                    continue;
                }

                String[] parts = line.split("=", 2);
                String key = parts[0].trim();
                String value = parts[1].trim();
                String keyLowerCase = key.toLowerCase();

                // CASO A: Propiedad sensible en Texto Plano (Primer Arranque)
                if ((keyLowerCase.contains("password") || keyLowerCase.contains("username") || keyLowerCase.contains("client-id") || keyLowerCase.contains("client-secret") ||
                		 keyLowerCase.contains("token") || keyLowerCase.contains("secret") || keyLowerCase.contains("url")) 
                     && !value.startsWith("ENC(")) {
                    
                    System.out.println("[JASYPT-AUTO] Encriptando propiedad sensible: " + key);
                    String encryptedValue = "ENC(" + encryptor.encrypt(value) + ")";
                    newLines.add(key + "=" + encryptedValue);
                    
                    // Inyectamos el valor limpio directamente a la memoria de Spring para este arranque
                    springInMemoryProperties.put(key, value);
                    modified = true;
                } 
                // CASO B: Propiedad sensible YA ENCRIPTADA (Segundo Arranque en adelante)
                else if (value.startsWith("ENC(")) {
                    newLines.add(line); // Dejamos la línea intacta en el archivo .properties del disco
                    
                    try {
                        // Extraemos el Hash de adentro de ENC(...) y lo desencriptamos manualmente en caliente
                        String cipherText = value.substring(4, value.length() - 1);
                        String decryptedValue = encryptor.decrypt(cipherText);
                        
                        // Le pasamos el valor real desencriptado a la memoria interna de Spring
                        springInMemoryProperties.put(key, decryptedValue);
                    } catch (Exception e) {
                        System.out.println("[JASYPT-AUTO] ERROR crítico al desencriptar la llave '" + key + "'. ¿La contraseña maestra cambió?");
                        springInMemoryProperties.put(key, value); 
                    }
                } 
                // CASO C: Propiedades normales y corrientes (como var.ambiente)
                else {
                    newLines.add(line); // La mantenemos intacta
                    springInMemoryProperties.put(key, value); // Va directo y limpio a la memoria de Spring
                }
            }

            // 4. Si hubo encriptaciones nuevas, sobreescribimos el archivo en el disco de manera limpia
            if (modified) {
                Files.write(path, newLines);
                System.out.println("==========================================================");
                System.out.println("[JASYPT-AUTO] ¡Valores confidenciales encriptados en disco con éxito!");
                System.out.println("==========================================================");
            } else {
                System.out.println("[JASYPT-AUTO] Todo verificado. No se requirieron encriptaciones nuevas.");
            }

            // 5. ¡EL PASO VITAL!: Registramos todas las propiedades en el entorno de Spring con máxima prioridad
            if (!springInMemoryProperties.isEmpty()) {
                MapPropertySource externalPropertySource = new MapPropertySource("externalCustomProperties", springInMemoryProperties);
                environment.getPropertySources().addFirst(externalPropertySource);
                System.out.println("[JASYPT-AUTO] Propiedades mapeadas en el contexto de Spring correctamente.");
            }

        } catch (IOException e) {
            System.out.println("[JASYPT-AUTO] ERROR CRÍTICO procesando el archivo externo: " + e.getMessage());
            throw new RuntimeException(e);
        }
        
        System.out.println("====== [JASYPT-AUTO] FINALIZÓ EL PROCESAMIENTO ======");
    }
}