import os
import yaml
from datetime import datetime

# ────────────────────────────────────────────────────────────────────────────────
# DIRECTORIOS
# ────────────────────────────────────────────────────────────────────────────────

# TEMPLATE_DIR debe apuntar a la carpeta web/templates/politicas
TEMPLATE_DIR = os.path.normpath(os.path.join(
    os.path.dirname(__file__),  # web/scripts/
    '..',                        # web/
    'templates',
    'politicas'
))

# OUTPUT_DIR apuntará a web/static/politicas_generadas
OUTPUT_DIR = os.path.normpath(os.path.join(
    os.path.dirname(__file__),  # web/scripts/
    '..',                        # web/
    'static',
    'politicas_generadas'
))
os.makedirs(OUTPUT_DIR, exist_ok=True)


# ────────────────────────────────────────────────────────────────────────────────
# HELPER: Reemplazo recursivo de placeholders en todo el dict/lista/str
# ────────────────────────────────────────────────────────────────────────────────

def _recursive_replace(obj, replacements):
    """Reemplaza placeholders recursivamente en toda la estructura."""
    if isinstance(obj, dict):
        return { key: _recursive_replace(value, replacements) for key, value in obj.items() }
    elif isinstance(obj, list):
        return [ _recursive_replace(item, replacements) for item in obj ]
    elif isinstance(obj, str):
        texto = obj
        for placeholder, val in replacements.items():
            texto = texto.replace(placeholder, val)
        return texto
    else:
        return obj


# ────────────────────────────────────────────────────────────────────────────────
# HELPER: Volcar un dict Python en un TXT con formato narrativo/viñetas
# ────────────────────────────────────────────────────────────────────────────────

def yaml_to_narrative(yaml_path: str, txt_path: str):
    """
    Lee el YAML en `yaml_path` (como un dict Python) y escribe un texto narrativo
    en `txt_path`, con encabezados y viñetas para cada nivel.
    """
    def write(line=""):
        f.write(line + "\n")

    def procesar_nivel(data: dict, indent: int = 0):
        prefijo = "  " * indent  # 2 espacios por nivel
        for key, val in data.items():
            texto_clave = key.replace('_', ' ').capitalize()
            if isinstance(val, dict):
                write(f"{prefijo}**{texto_clave}**")
                procesar_nivel(val, indent + 1)
            elif isinstance(val, list):
                write(f"{prefijo}- **{texto_clave}:**")
                for item in val:
                    if isinstance(item, dict):
                        procesar_nivel(item, indent + 1)
                    else:
                        write(f"{prefijo}  • {item}")
            else:
                write(f"{prefijo}- **{texto_clave}:** {val}")

    # 1) Cargar el YAML en memoria
    with open(yaml_path, 'r', encoding='utf-8') as yf:
        contenido = yaml.safe_load(yf)

    # 2) Abrir/crear el .txt narrativo
    with open(txt_path, 'w', encoding='utf-8') as f:
        # Título principal: nombre del archivo sin extensión
        titulo = os.path.splitext(os.path.basename(yaml_path))[0]
        write("===============================")
        write(f"  {titulo.replace('_', ' ')}")
        write("===============================\n")
        # Procesar todo el dict para volcarlo en modo narrativo
        procesar_nivel(contenido, indent=0)


# ────────────────────────────────────────────────────────────────────────────────
# FUNCION PRINCIPAL: Generar política a partir de plantilla YAML + params
# ────────────────────────────────────────────────────────────────────────────────

def generate_policy(policy_key: str, params: dict) -> dict:
    """
    Genera un archivo YAML y un TXT narrativo para la política indicada por 'policy_key',
    usando los parámetros 'params' (por ejemplo: company_name, security_officer, pwd_length, etc.).
    Devuelve un dict con las rutas relativas a 'static':
        {
          'yaml': 'static/politicas_generadas/Politica_<key>_<Empresa>.yml',
          'txt':  'static/politicas_generadas/Politica_<key>_<Empresa>.txt'
        }
    """
    # Mapeo de claves a nombres de archivo de plantilla
    mapping = {
        'seguridad':    'politica_seguridad.yml',
        'normativa':    'politica_normativa_seguridad.yml',
        'auth_externa': 'politica_autenticacion_externa.yml',
        'auth_interna': 'politica_autenticacion_interna.yml',
        'criptografia': 'politica_criptografia.yml',
        'backups':      'politica_backups.yml'
    }

    plantilla_filename = mapping.get(policy_key)
    if not plantilla_filename:
        return {
            'yaml': '',
            'txt': ''
        }

    # 1) Cargar la plantilla YAML original
    plantilla_path = os.path.join(TEMPLATE_DIR, plantilla_filename)
    with open(plantilla_path, 'r', encoding='utf-8') as f:
        plantilla = yaml.safe_load(f)

    # 2) Rellenar campos directos básicos
    empresa = params.get('company_name', 'NOMBRE_EMPRESA')
    resp    = params.get('security_officer', 'RESPONSABLE_SEGURIDAD')
    hoy     = datetime.now().strftime("%Y-%m-%d")

    # Estos campos deben existir en casi todas las plantillas
    plantilla['company_name']     = empresa
    plantilla['security_officer'] = resp
    plantilla['approval_date']    = hoy

    # Si existe sección 'review' en la plantilla, fijar next_review a un año después
    if 'review' in plantilla:
        proxima = (datetime.now().replace(year=datetime.now().year + 1)).strftime("%Y-%m-%d")
        plantilla['review']['next_review'] = proxima

    # 3) Rellenar campos específicos según el tipo de política
    if policy_key in ['auth_externa', 'auth_interna']:
        # Por ejemplo: min_length y expiration_days para contraseñas
        plantilla.setdefault('password_requirements', {})
        plantilla['password_requirements']['min_length'] = int(params.get('pwd_length', 12))
        plantilla['password_requirements']['expiration_days'] = int(params.get('pwd_expiry', 90))

    if policy_key == 'criptografia':
        # Ajustar algoritmo simétrico por defecto (primer elemento de la lista)
        plantilla.setdefault('algoritmos_preferidos', {})
        plantilla['algoritmos_preferidos'].setdefault('simetricos', [])
        if len(plantilla['algoritmos_preferidos']['simetricos']) > 0:
            plantilla['algoritmos_preferidos']['simetricos'][0]['name'] = params.get('crypto_symmetric', 'AES-256')

    if policy_key == 'backups':
        # Ajustar frecuencia y retención de backups
        plantilla.setdefault('frequency', {})
        plantilla.setdefault('retention', {})
        plantilla.setdefault('backup_destination', {})
        plantilla['frequency']['critical_data'] = params.get('backup_freq', 'Diaria')
        plantilla['retention']['local'] = f"{params.get('backup_retention', 30)} días"
        plantilla['backup_destination'].setdefault('local', {})
        plantilla['backup_destination']['local']['path'] = params.get('backup_dest', '/mnt/nas/backups/')

    # 4) Preparar diccionario de reemplazos (placeholders)
    # Calcular fechas para pruebas (última prueba hace 3 meses, próxima en 3 meses)
    from datetime import timedelta
    fecha_ultima_prueba = (datetime.now() - timedelta(days=90)).strftime("%Y-%m-%d")
    fecha_proxima_prueba = (datetime.now() + timedelta(days=90)).strftime("%Y-%m-%d")
    
    replacements = {
        '<NOMBRE_EMPRESA>':        empresa,
        '<RESPONSABLE_SEGURIDAD>': resp,
        '<FECHA_APROBACION>':      hoy,
        '<FECHA_PROXIMA_REVISION>': plantilla.get('review', {}).get('next_review', hoy),
        '<FECHA_ULTIMA_REVISION>': params.get('last_review', hoy),
        '<FECHA_ULTIMA_PRUEBA>':   fecha_ultima_prueba,
        '<FECHA_PROXIMA_PRUEBA>':  fecha_proxima_prueba,
        '<NOMBRE_ADMIN_BACKUP>':   params.get('backup_admin', 'Administrador de Backup'),
        '<NOMBRE_AUDITOR>':        params.get('auditor_name', 'Auditor Técnico'),
        '<LONGITUD_MINIMA>':       str(params.get('pwd_length', 12)),
        '<DAYS_ROTATION>':         str(params.get('pwd_expiry', 90))
    }

    # 5) Aplicar el reemplazo recursivo en todo el dict plantilla
    plantilla_limpia = _recursive_replace(plantilla, replacements)

    # 6) Volcar el dict resultante a un archivo YAML en OUTPUT_DIR
    salida_filename = f"Politica_{policy_key}_{empresa.replace(' ', '_')}.yml"
    salida_path     = os.path.join(OUTPUT_DIR, salida_filename)
    with open(salida_path, 'w', encoding='utf-8') as f_out:
        yaml.dump(plantilla_limpia, f_out, sort_keys=False, allow_unicode=True)

    # 7) Generar también un TXT narrativo paralelo
    txt_filename = salida_filename.replace('.yml', '.txt')
    txt_path     = os.path.join(OUTPUT_DIR, txt_filename)
    yaml_to_narrative(salida_path, txt_path)

    # 8) Devolver rutas relativas a 'static'
    return {
        'yaml': f"static/politicas_generadas/{salida_filename}",
        'txt':  f"static/politicas_generadas/{txt_filename}"
    }
