import os
import json
import matplotlib.pyplot as plt
import matplotlib.patches as mpatches
from matplotlib.patches import Rectangle
import seaborn as sns
from fpdf import FPDF
from datetime import datetime
import unicodedata
from collections import Counter, defaultdict
import numpy as np

# Configuración de estilo
plt.style.use('seaborn-v0_8-darkgrid')
sns.set_palette("husl")

# Funcion para limpiar texto
def latin1_safe(text: str) -> str:
    """Limpia el texto para que funcione con FPDF."""
    if not isinstance(text, str):
        text = str(text)
    
    # Quitar emojis y caracteres raros
    emoji_pattern = r'[^\w\s\-.,!?():;/áéíóúñüÁÉÍÓÚÑÜ]'
    import re
    text = re.sub(emoji_pattern, '', text)
    
    # Cambiar caracteres que dan problemas
    replacements = {
        '🎯': '>>',
        '📊': '[GRAFICO]',
        '📋': '[LISTA]',
        '🚨': '[ALERTA]',
        '⚔️': '[ATAQUE]',
        '💰': '[COSTE]',
        '🟢': '[OK]',
        '🟡': '[ATENCION]',
        '🟠': '[REVISION]',
        '🔴': '[CRITICO]',
        '✅': '[SI]',
        '❌': '[NO]',
        '⚠️': '[AVISO]',
        '💡': '[IDEA]',
        '🔒': '[SEGURO]',
        '📈': '[MEJORA]',
        '•': '*',
        '€': 'EUR',
        '"': '"',
        '"': '"',
        ''': "'",
        ''': "'",
        '–': '-',
        '—': '-'
    }
    
    for unicode_char, replacement in replacements.items():
        text = text.replace(unicode_char, replacement)
    
    # Normalizar caracteres
    nf = unicodedata.normalize('NFKD', text)
    result = ''.join(ch for ch in nf if ord(ch) < 256)
    
    # Ultima limpieza
    result = result.encode('latin-1', errors='ignore').decode('latin-1')
    
    return result

# Configuracion de rutas
BASE_DIR = os.path.dirname(__file__)
STATIC_DIR = os.path.normpath(os.path.join(BASE_DIR, '..', 'static'))
IMAGES_DIR = os.path.join(STATIC_DIR, 'imagenes')
REPORTS_DIR = os.path.join(STATIC_DIR, 'informes')

for path in (IMAGES_DIR, REPORTS_DIR):
    os.makedirs(path, exist_ok=True)

# Funciones para cargar datos
def cargar_json_seguro(nombre):
    """Carga los datos JSON."""
    ruta = os.path.join(STATIC_DIR, nombre)
    try:
        if not os.path.exists(ruta) or os.path.getsize(ruta) == 0:
            return None
        with open(ruta, 'r', encoding='utf-8') as f:
            return json.load(f)
    except Exception as e:
        print(f"Error cargando {nombre}: {e}")
        return None

# Analisis de datos
def analizar_script2(datos):
    """Script 2 - diagnostico ENS."""
    if not datos:
        return None
    
    familias = defaultdict(lambda: {'cumple': 0, 'parcial': 0, 'no_cumple': 0})
    controles_criticos = []
    
    for fila in datos:
        codigo = fila.get('Código ENS', '').upper()
        estado = fila.get('Estado', '').strip()
        
        # Sacar la familia del codigo
        if '.' in codigo:
            partes = codigo.split('.')
            # Si el segundo segmento es un número, usar solo el primero (ej: ORG.1 -> ORG)
            if len(partes) >= 2 and partes[1].isdigit():
                familia = partes[0]
            else:
                # Si no es un número, usar los primeros 2 segmentos como antes
                familia = '.'.join(partes[:2])
        else:
            familia = codigo
        
        # Verificar como esta el control
        if estado == 'Cumple':
            familias[familia]['cumple'] += 1
        elif estado.startswith('Parcial'):
            familias[familia]['parcial'] += 1
            # Sacar el porcentaje
            porcentaje = None
            if '(' in estado and '%' in estado:
                try:
                    porcentaje = int(estado.split('(')[1].split('%')[0])
                except:
                    porcentaje = 50
            controles_criticos.append({
                'codigo': codigo, 
                'estado': estado,
                'porcentaje': porcentaje
            })
        else:  # El resto (no cumple)
            familias[familia]['no_cumple'] += 1
            controles_criticos.append({
                'codigo': codigo, 
                'estado': estado,
                'porcentaje': 0
            })
    
    return {
        'familias': dict(familias),
        'controles_criticos': controles_criticos,
        'total_controles': len(datos)
    }

def analizar_script4(datos):
    """Script 4 - auditor de permisos."""
    if not datos:
        return None
    
    por_codigo = Counter(item.get('codigo_ens', 'UNKNOWN') for item in datos)
    por_severidad = {'critica': 0, 'alta': 0, 'media': 0, 'baja': 0}
    
    # Clasificar vulnerabilidades
    vulnerabilidades_por_severidad = {
        'critica': [],
        'alta': [],
        'media': [],
        'baja': []
    }
    
    for item in datos:
        titulo = item.get('titulo', '')
        titulo_lower = titulo.lower()
        
        # Clasificar segun el tipo
        if any(x in titulo_lower for x in ['duplicado', 'privilegios', 'sudo']):
            por_severidad['critica'] += 1
            vulnerabilidades_por_severidad['critica'].append(titulo)
        elif any(x in titulo_lower for x in ['bloqueada', 'expirado']):
            por_severidad['alta'] += 1
            vulnerabilidades_por_severidad['alta'].append(titulo)
        elif any(x in titulo_lower for x in ['shell', 'contraseña']):
            por_severidad['media'] += 1
            vulnerabilidades_por_severidad['media'].append(titulo)
        else:
            por_severidad['baja'] += 1
            vulnerabilidades_por_severidad['baja'].append(titulo)
    
    return {
        'total_vulnerabilidades': len(datos),
        'por_codigo_ens': dict(por_codigo),
        'por_severidad': por_severidad,
        'vulnerabilidades_por_severidad': vulnerabilidades_por_severidad,
        'vulnerabilidades_criticas': [v for v in datos if 'privilegios' in v.get('titulo', '').lower()]
    }

def analizar_script5(datos):
    """Script 5 - detector de incidentes."""
    if not datos:
        return None
    
    por_tipo = Counter()
    timeline = defaultdict(int)
    severidad = {'critica': 0, 'alta': 0, 'media': 0}
    
    for incidente in datos:
        timestamp = incidente.get('timestamp', '')
        titulo = incidente.get('titulo', '')
        
        # Clasificar incidentes
        if 'fuerza bruta' in titulo.lower():
            por_tipo['Fuerza Bruta'] += 1
            severidad['critica'] += 1
        elif 'cuenta' in titulo.lower():
            por_tipo['Gestión Cuentas'] += 1
            severidad['alta'] += 1
        elif 'ssh' in titulo.lower():
            por_tipo['Acceso SSH'] += 1
            severidad['media'] += 1
        else:
            por_tipo['Otros'] += 1
            severidad['media'] += 1
        
        # Contar por fecha
        if timestamp:
            fecha = timestamp.split(' ')[0]
            timeline[fecha] += 1
    
    return {
        'total_incidentes': len(datos),
        'por_tipo': dict(por_tipo),
        'timeline': dict(timeline),
        'por_severidad': severidad,
        'incidentes_criticos': [i for i in datos if 'fuerza bruta' in i.get('titulo', '').lower()]
    }

def analizar_script6(datos):
    """Script 6 - simulador de ataques."""
    if not datos:
        return None
    
    puertos_tcp = datos.get('tcp_abiertos', {}).get('dato', [])
    puertos_udp = datos.get('udp_abiertos', {}).get('dato', [])
    ftp_anonimo = datos.get('ftp_anonimo', {}).get('dato', False)
    telnet_banner = datos.get('telnet_banner', {}).get('dato', None)
    
    vulnerabilidades = []
    if puertos_tcp:
        vulnerabilidades.append(f"{len(puertos_tcp)} puertos TCP abiertos")
    if puertos_udp:
        vulnerabilidades.append(f"{len(puertos_udp)} puertos UDP abiertos/filtrados")
    if ftp_anonimo:
        vulnerabilidades.append("FTP anónimo habilitado")
    if telnet_banner:
        vulnerabilidades.append("Servicio Telnet detectado")
    
    return {
        'target': datos.get('target', {}).get('dato', 'Unknown'),
        'puertos_tcp': puertos_tcp,
        'puertos_udp': puertos_udp,
        'servicios_inseguros': {
            'ftp_anonimo': ftp_anonimo,
            'telnet': telnet_banner is not None
        },
        'total_vulnerabilidades': len(vulnerabilidades),
        'resumen_vulnerabilidades': vulnerabilidades
    }

def analizar_script7(datos):
    """Analiza optimización de recursos (Script 7)."""
    if not datos:
        return None
    
    partidas = datos.get('partidas', {})
    totales = datos.get('totales', {})
    plan = datos.get('plan_prioridades', [])
    
    # Sacar costes por categoria
    costes_por_categoria = {}
    for nombre, info in partidas.items():
        coste = info.get('coste', 0)
        if coste > 0:
            costes_por_categoria[nombre.replace('_', ' ').title()] = coste
    
    return {
        'coste_total_inicial': totales.get('coste_total_inicial', 0),
        'coste_recurrente_anual': totales.get('coste_recurrente_anual', 0),
        'horas_totales': totales.get('horas_totales', 0),
        'costes_por_categoria': costes_por_categoria,
        'plan_prioridades': plan[:5],  # Top 5 
        'roi_estimado': calcular_roi(totales.get('coste_total_inicial', 0))
    }

def calcular_roi(coste_inicial):
    """Calcular ROI aproximado."""
    if coste_inicial == 0:
        return 0
    # Calculo simple: 70% de reduccion de riesgo
    riesgo_inicial_estimado = coste_inicial * 2
    reduccion_riesgo = riesgo_inicial_estimado * 0.7
    return round((reduccion_riesgo / coste_inicial) * 100, 1)

# Funciones para generar graficos
def generar_dashboard_cumplimiento(analisis_s2):
    """Dashboard de cumplimiento ENS."""
    if not analisis_s2:
        return None
    
    # Layout 2x2 
    fig, ((ax1, ax2), (ax3, ax4)) = plt.subplots(2, 2, figsize=(16, 10))
    fig.suptitle('Dashboard de Cumplimiento ENS', fontsize=20, fontweight='bold')
    
    # Grafico de barras
    familias = analisis_s2['familias']
    if familias:
        nombres = list(familias.keys())
        cumple = [familias[f]['cumple'] for f in nombres]
        parcial = [familias[f]['parcial'] for f in nombres]
        no_cumple = [familias[f]['no_cumple'] for f in nombres]
        
        x = np.arange(len(nombres))
        width = 0.6
        
        ax1.bar(x, cumple, width, label='Cumple', color='#2ecc71', alpha=0.8)
        ax1.bar(x, parcial, width, bottom=cumple, label='Parcial', color='#f39c12', alpha=0.8)
        ax1.bar(x, no_cumple, width, bottom=np.array(cumple) + np.array(parcial), 
                label='No Cumple', color='#e74c3c', alpha=0.8)
        
        ax1.set_xlabel('Familias de Controles ENS', fontweight='bold')
        ax1.set_ylabel('Número de Controles', fontweight='bold')
        ax1.set_title('Cumplimiento por Familia de Controles', fontweight='bold')
        ax1.set_xticks(x)
        ax1.set_xticklabels(nombres, rotation=45, ha='right')
        ax1.legend()
        ax1.grid(True, alpha=0.3)
    
    # Grafico circular
    total_cumple = sum(familias[f]['cumple'] for f in familias)
    total_parcial = sum(familias[f]['parcial'] for f in familias)
    total_no_cumple = sum(familias[f]['no_cumple'] for f in familias)
    
    if total_cumple + total_parcial + total_no_cumple > 0:
        sizes = [total_cumple, total_parcial, total_no_cumple]
        labels = ['Cumple', 'Parcial', 'No Cumple']
        colors = ['#2ecc71', '#f39c12', '#e74c3c']
        explode = (0.1, 0, 0)
        
        ax2.pie(sizes, explode=explode, labels=labels, colors=colors, autopct='%1.1f%%',
                shadow=True, startangle=90)
        ax2.set_title('Distribución Global de Cumplimiento', fontweight='bold')
    
    # Metricas 
    ax3.axis('off')
    ax4.axis('off')
    
    total_controles = analisis_s2['total_controles']
    porcentaje_cumplimiento = round((total_cumple / total_controles) * 100, 1) if total_controles > 0 else 0
    
    metrics_text = f"""
    METRICAS CLAVE DE CUMPLIMIENTO ENS
    
    • Total de Controles Evaluados: {total_controles}
    • Porcentaje de Cumplimiento Global: {porcentaje_cumplimiento}%
    • Controles que Cumplen Completamente: {total_cumple}
    • Controles con Cumplimiento Parcial: {total_parcial}
    • Controles No Cumplidos: {total_no_cumple}
    • Familias de Controles Analizadas: {len(familias)}
    
    ESTADO GENERAL DEL CUMPLIMIENTO: {'EXCELENTE' if porcentaje_cumplimiento >= 80 else 'BUENO' if porcentaje_cumplimiento >= 60 else 'MEJORABLE' if porcentaje_cumplimiento >= 40 else 'CRITICO'}
    """
    
    # Poner las metricas
    fig.text(0.1, 0.35, metrics_text, fontsize=16, fontweight='bold',
             bbox=dict(boxstyle='round,pad=1.2', facecolor='lightblue', alpha=0.8),
             verticalalignment='top')
    
    plt.tight_layout()
    plt.subplots_adjust(bottom=0.15)
    ruta = os.path.join(IMAGES_DIR, 'dashboard_cumplimiento.png')
    plt.savefig(ruta, dpi=300, bbox_inches='tight')
    plt.close()
    return ruta

def generar_grafico_vulnerabilidades(analisis_s4, analisis_s5):
    """Grafico de vulnerabilidades e incidentes."""
    fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(15, 6))
    fig.suptitle('Analisis de Vulnerabilidades e Incidentes', fontsize=16, fontweight='bold')
    
    # Vulnerabilidades por tipo
    if analisis_s4:
        severidades = list(analisis_s4['por_severidad'].keys())
        valores = list(analisis_s4['por_severidad'].values())
        colors = ['#e74c3c', '#ff6b35', '#f39c12', '#2ecc71']
        
        wedges, texts, autotexts = ax1.pie(valores, labels=severidades, colors=colors, 
                                          autopct='%1.1f%%', startangle=90)
        ax1.set_title('Vulnerabilidades por Severidad\n(Script 4 - Auditor)', fontweight='bold')
        
        # Leyenda
        legend_labels = [f'{sev.title()}: {val}' for sev, val in zip(severidades, valores)]
        ax1.legend(wedges, legend_labels, loc="center left", bbox_to_anchor=(1, 0, 0.5, 1))
    
    # Script 5 - Incidentes por tipo
    if analisis_s5:
        tipos = list(analisis_s5['por_tipo'].keys())
        valores = list(analisis_s5['por_tipo'].values())
        colors = plt.cm.Set3(np.linspace(0, 1, len(tipos)))
        
        bars = ax2.bar(tipos, valores, color=colors, alpha=0.8)
        ax2.set_title('Incidentes Detectados por Tipo\n(Script 5 - Detector)', fontweight='bold')
        ax2.set_ylabel('Número de Incidentes', fontweight='bold')
        ax2.tick_params(axis='x', rotation=45)
        
        # Añadir valores en las barras
        for bar, valor in zip(bars, valores):
            height = bar.get_height()
            ax2.annotate(f'{valor}', xy=(bar.get_x() + bar.get_width()/2, height),
                        xytext=(0, 3), textcoords="offset points", ha='center', va='bottom')
    
    plt.tight_layout()
    ruta = os.path.join(IMAGES_DIR, 'vulnerabilidades_incidentes.png')
    plt.savefig(ruta, dpi=300, bbox_inches='tight')
    plt.close()
    return ruta

def generar_grafico_simulacion(analisis_s6):
    """Genera gráfico del análisis de simulación de ataques."""
    if not analisis_s6:
        return None
    
    fig, ((ax1, ax2), (ax3, ax4)) = plt.subplots(2, 2, figsize=(14, 10))
    fig.suptitle('Analisis de Simulacion de Ataques', fontsize=16, fontweight='bold')
    
    # 1. Puertos TCP abiertos
    puertos_tcp = analisis_s6['puertos_tcp']
    if puertos_tcp:
        puertos_comunes = {21: 'FTP', 22: 'SSH', 23: 'Telnet', 25: 'SMTP', 53: 'DNS', 
                          80: 'HTTP', 110: 'POP3', 143: 'IMAP', 443: 'HTTPS', 993: 'IMAPS', 995: 'POP3S'}
        
        labels = [f"{p}\n({puertos_comunes.get(p, 'Unknown')})" for p in puertos_tcp]
        values = [1] * len(puertos_tcp)
        colors = ['#e74c3c' if p in [21, 23, 25] else '#f39c12' if p in [22, 80] else '#2ecc71' for p in puertos_tcp]
        
        ax1.bar(range(len(labels)), values, color=colors, alpha=0.7)
        ax1.set_title('Puertos TCP Abiertos', fontweight='bold')
        ax1.set_xticks(range(len(labels)))
        ax1.set_xticklabels(labels, rotation=45, ha='right')
        ax1.set_ylabel('Estado (Abierto)')
    
    # 2. Servicios inseguros
    servicios = analisis_s6['servicios_inseguros']
    labels = ['FTP Anónimo', 'Telnet']
    values = [servicios['ftp_anonimo'], servicios['telnet']]
    colors = ['#e74c3c' if v else '#2ecc71' for v in values]
    labels_display = [f"{label}\n{'INSEGURO' if v else 'SEGURO'}" for label, v in zip(labels, values)]
    
    ax2.bar(labels, values, color=colors, alpha=0.7)
    ax2.set_title('Servicios Inseguros Detectados', fontweight='bold')
    ax2.set_ylabel('Detectado (1) / No Detectado (0)')
    ax2.set_ylim(0, 1.2)
    
    # 3. Resumen de vulnerabilidades
    ax3.axis('off')
    target = analisis_s6['target']
    total_vulns = analisis_s6['total_vulnerabilidades']
    vulns_list = analisis_s6['resumen_vulnerabilidades']
    
    resumen_text = f"""
    TARGET ANALIZADO: {target}
    
    RESUMEN DE HALLAZGOS:
    • Total de Vulnerabilidades: {total_vulns}
    • Puertos TCP Abiertos: {len(puertos_tcp)}
    • Puertos UDP Abiertos: {len(analisis_s6['puertos_udp'])}
    
    VULNERABILIDADES DETECTADAS:
    """ + '\n    '.join(f"• {v}" for v in vulns_list)
    
    ax3.text(0.05, 0.95, resumen_text, transform=ax3.transAxes, fontsize=12, fontweight='bold',
             verticalalignment='top', bbox=dict(boxstyle='round,pad=0.8', facecolor='lightyellow', alpha=0.9))
    
    # 4. Nivel de riesgo general
    nivel_riesgo = 'ALTO' if total_vulns >= 3 else 'MEDIO' if total_vulns >= 1 else 'BAJO'
    color_riesgo = '#e74c3c' if nivel_riesgo == 'ALTO' else '#f39c12' if nivel_riesgo == 'MEDIO' else '#2ecc71'
    
    ax4.text(0.5, 0.5, f'NIVEL DE RIESGO\n\n{nivel_riesgo}', 
             ha='center', va='center', fontsize=20, fontweight='bold',
             bbox=dict(boxstyle='round,pad=0.5', facecolor=color_riesgo, alpha=0.3),
             transform=ax4.transAxes)
    ax4.set_xlim(0, 1)
    ax4.set_ylim(0, 1)
    ax4.axis('off')
    
    plt.tight_layout()
    ruta = os.path.join(IMAGES_DIR, 'simulacion_ataques.png')
    plt.savefig(ruta, dpi=300, bbox_inches='tight')
    plt.close()
    return ruta

def generar_grafico_costes(analisis_s7):
    """Genera gráfico de análisis de costes y ROI."""
    if not analisis_s7:
        return None
    
    fig, ((ax1, ax2), (ax3, ax4)) = plt.subplots(2, 2, figsize=(15, 12))
    fig.suptitle('Analisis Economico - Optimizacion de Recursos', fontsize=16, fontweight='bold')
    
    # 1. Distribución de costes por categoría
    categorias = list(analisis_s7['costes_por_categoria'].keys())
    costes = list(analisis_s7['costes_por_categoria'].values())
    
    if categorias:
        colors = plt.cm.Pastel1(np.linspace(0, 1, len(categorias)))
        wedges, texts, autotexts = ax1.pie(costes, labels=categorias, colors=colors, 
                                          autopct=lambda pct: f'€{pct*sum(costes)/100:.0f}', 
                                          startangle=90)
        ax1.set_title('Distribución de Costes por Categoría', fontweight='bold')
    
    # 2. Comparativa inicial vs recurrente
    coste_inicial = analisis_s7['coste_total_inicial']
    coste_recurrente = analisis_s7['coste_recurrente_anual']
    
    tipos_coste = ['Inversión Inicial', 'Coste Anual Recurrente']
    valores_coste = [coste_inicial, coste_recurrente]
    colors = ['#3498db', '#e67e22']
    
    bars = ax2.bar(tipos_coste, valores_coste, color=colors, alpha=0.7)
    ax2.set_title('Inversión Inicial vs Costes Recurrentes', fontweight='bold')
    ax2.set_ylabel('Coste (€)', fontweight='bold')
    
    # Añadir valores en las barras
    for bar, valor in zip(bars, valores_coste):
        height = bar.get_height()
        ax2.annotate(f'€{valor:,.0f}', xy=(bar.get_x() + bar.get_width()/2, height),
                    xytext=(0, 3), textcoords="offset points", ha='center', va='bottom')
    
    # 3. Plan de prioridades (top 5)
    plan = analisis_s7['plan_prioridades']
    if plan:
        nombres_plan = [item.get('concepto', '').replace('_', ' ').title() for item in plan]
        costes_plan = [item.get('coste', 0) for item in plan]
        
        bars = ax3.barh(nombres_plan, costes_plan, color='lightcoral', alpha=0.7)
        ax3.set_title('Top 5 Prioridades de Inversión', fontweight='bold')
        ax3.set_xlabel('Coste (€)', fontweight='bold')
        
        # Añadir valores
        for bar, valor in zip(bars, costes_plan):
            width = bar.get_width()
            ax3.annotate(f'€{valor:,.0f}', xy=(width, bar.get_y() + bar.get_height()/2),
                        xytext=(3, 0), textcoords="offset points", va='center')
    
    # 4. Métricas financieras
    ax4.axis('off')
    horas_totales = analisis_s7['horas_totales']
    roi_estimado = analisis_s7['roi_estimado']
    
    coste_por_hora = coste_inicial / horas_totales if horas_totales > 0 else 0
    payback_estimado = round(coste_inicial / (coste_inicial * 0.1), 1) if coste_inicial > 0 else 0  # Estimación simplificada
    
    metricas_text = f"""
    METRICAS FINANCIERAS
    
    • Inversion Inicial: EUR {coste_inicial:,.0f}
    • Coste Anual Recurrente: EUR {coste_recurrente:,.0f}
    • Horas Totales Estimadas: {horas_totales:,.0f} h
    • Coste por Hora: EUR {coste_por_hora:.2f}/h
    
    • ROI Estimado: {roi_estimado}%
    • Payback Estimado: {payback_estimado} años
    
    EVALUACION: {'EXCELENTE' if roi_estimado >= 200 else 'BUENA' if roi_estimado >= 100 else 'ACEPTABLE' if roi_estimado >= 50 else 'REVISAR'}
    """
    
    ax4.text(0.05, 0.95, metricas_text, transform=ax4.transAxes, fontsize=13, fontweight='bold',
             verticalalignment='top', bbox=dict(boxstyle='round,pad=0.8', facecolor='lightgreen', alpha=0.8))
    
    plt.tight_layout()
    ruta = os.path.join(IMAGES_DIR, 'analisis_costes.png')
    plt.savefig(ruta, dpi=300, bbox_inches='tight')
    plt.close()
    return ruta

# Clase PDF
class InformeENSProfesional(FPDF):
    def __init__(self, empresa):
        super().__init__()
        self.empresa = empresa
        self.set_auto_page_break(auto=True, margin=15)
    
    def header(self):
        # Logo o header personalizado
        self.set_fill_color(0, 102, 204)  # Azul corporativo
        self.rect(0, 0, 210, 25, 'F')
        
        self.set_font('Arial', 'B', 18)
        self.set_text_color(255, 255, 255)
        self.set_y(8)
        self.cell(0, 10, latin1_safe(f'Informe ENS Profesional - {self.empresa}'), 0, 1, 'C')
        
        self.set_text_color(0, 0, 0)
        self.ln(10)
    
    def footer(self):
        self.set_y(-15)
        self.set_font('Arial', 'I', 8)
        self.set_text_color(128, 128, 128)
        self.cell(0, 10, f'Página {self.page_no()} - Generado el {datetime.now().strftime("%d/%m/%Y %H:%M")}', 0, 0, 'C')
    
    def titulo_seccion(self, titulo, color_rgb=(0, 102, 204)):
        self.ln(5)
        self.set_fill_color(*color_rgb)
        self.set_font('Arial', 'B', 14)
        self.set_text_color(255, 255, 255)
        self.cell(0, 10, latin1_safe(titulo), 0, 1, 'L', True)
        self.set_text_color(0, 0, 0)
        self.ln(3)
    
    def subtitulo(self, texto):
        self.set_font('Arial', 'B', 12)
        self.set_text_color(52, 73, 94)
        self.cell(0, 8, latin1_safe(texto), 0, 1, 'L')
        self.set_text_color(0, 0, 0)
        self.ln(2)
    
    def texto_normal(self, texto):
        self.set_font('Arial', '', 10)
        self.multi_cell(0, 5, latin1_safe(texto))
        self.ln(2)
    
    def caja_destacada(self, texto, color_fondo=(245, 245, 245)):
        self.set_fill_color(*color_fondo)
        self.set_font('Arial', '', 10)
        y_before = self.get_y()
        self.multi_cell(0, 6, latin1_safe(texto), 1, 'L', True)
        self.ln(3)
    
    def metricas_clave(self, metricas_dict):
        """Añade una caja con métricas clave"""
        self.set_fill_color(230, 247, 255)
        self.set_font('Arial', 'B', 11)
        
        # Calcular altura necesaria
        num_metricas = len(metricas_dict)
        altura_total = (num_metricas * 8) + 10
        
        # Dibujar fondo
        self.rect(self.get_x(), self.get_y(), 190, altura_total, 'F')
        
        self.cell(0, 8, latin1_safe('METRICAS CLAVE'), 0, 1, 'C')
        self.set_font('Arial', '', 10)
        
        for clave, valor in metricas_dict.items():
            self.cell(0, 6, latin1_safe(f'• {clave}: {valor}'), 0, 1, 'L')
        
        self.ln(5)
    
    def insertar_imagen_centrada(self, ruta_imagen, ancho=160):
        """Inserta una imagen centrada en la página"""
        if os.path.exists(ruta_imagen):
            x_center = (210 - ancho) / 2  # 210 es el ancho de página A4
            self.image(ruta_imagen, x=x_center, w=ancho)
            self.ln(5)
        else:
            self.texto_normal(f"[Imagen no disponible: {os.path.basename(ruta_imagen)}]")
    
    def portada(self):
        """Genera la portada del informe"""
        self.add_page()
        
        # Espaciado superior
        self.ln(40)
        
        # Título principal
        self.set_font('Arial', 'B', 28)
        self.set_text_color(0, 102, 204)
        self.cell(0, 15, 'INFORME ENS', 0, 1, 'C')
        
        self.set_font('Arial', 'B', 20)
        self.cell(0, 12, 'Esquema Nacional de Seguridad', 0, 1, 'C')
        
        self.ln(20)
        
        # Información de la empresa
        self.set_font('Arial', 'B', 16)
        self.set_text_color(52, 73, 94)
        self.cell(0, 10, latin1_safe(f'Empresa: {self.empresa}'), 0, 1, 'C')
        
        self.ln(10)
        
        # Fecha
        self.set_font('Arial', '', 12)
        self.set_text_color(128, 128, 128)
        fecha_actual = datetime.now().strftime("%d de %B de %Y")
        self.cell(0, 8, f'Fecha del informe: {fecha_actual}', 0, 1, 'C')
        
        self.ln(40)
        
        # Resumen visual
        self.set_fill_color(248, 249, 250)
        self.rect(20, self.get_y(), 170, 80, 'F')
        
        self.set_font('Arial', 'B', 14)
        self.set_text_color(0, 0, 0)
        self.cell(0, 10, latin1_safe('ANÁLISIS INTEGRAL DE CIBERSEGURIDAD'), 0, 1, 'C')
        
        self.set_font('Arial', '', 11)
        resumen_portada = """
Este informe contiene un análisis completo del cumplimiento del
Esquema Nacional de Seguridad (ENS) nivel Alto, incluyendo:

• Evaluación de cumplimiento de controles ENS
• Diagnóstico detallado de vulnerabilidades  
• Análisis de incidentes de seguridad detectados
• Simulación de ataques y pruebas de penetración
• Optimización de recursos y estimación de costes
• Recomendaciones y plan de acción prioritario
        """
        
        self.multi_cell(0, 6, latin1_safe(resumen_portada), 0, 'C')
    
    def indice(self):
        """Genera el índice del informe"""
        self.add_page()
        self.titulo_seccion('INDICE')
        
        self.set_font('Arial', '', 11)
        
        secciones = [
            ('1. RESUMEN EJECUTIVO', '3'),
            ('2. CUMPLIMIENTO ENS POR FAMILIAS', '4'),
            ('3. DIAGNÓSTICO DETALLADO', '5'),
            ('4. ANÁLISIS DE VULNERABILIDADES', '6'),
            ('5. INCIDENTES DE SEGURIDAD', '7'),
            ('6. SIMULACIÓN DE ATAQUES', '8'),
            ('7. OPTIMIZACIÓN DE RECURSOS', '9'),
            ('8. PLAN DE ACCIÓN PRIORITARIO', '10'),
            ('9. CONCLUSIONES Y RECOMENDACIONES', '11'),
            ('10. ANEXOS', '12')
        ]
        
        for seccion, pagina in secciones:
            self.cell(150, 8, latin1_safe(seccion), 0, 0, 'L')
            self.cell(40, 8, pagina, 0, 1, 'R')
        
        self.ln(10)
        
        # Nota sobre el informe
        self.caja_destacada("""
NOTA IMPORTANTE:
Este informe ha sido generado automáticamente mediante el análisis de los resultados
obtenidos de las 8 herramientas especializadas del sistema TFG ENS PYME. Los datos
reflejan el estado actual de cumplimiento y seguridad de la organización en el momento
de la evaluación.
        """)

# Funcion principal
def generar_pdf(company_name: str):
    """
    Genera un informe profesional completo del análisis ENS.
    Recopila datos de todos los scripts y crea gráficos avanzados.
    """
    print("Iniciando generación del informe ENS profesional...")
    
    # 1) Carga de datos de todos los scripts
    print("Cargando datos de los scripts...")
    datos_s2 = cargar_json_seguro('datos_script2.json')
    datos_s4 = cargar_json_seguro('datos_script4.json') 
    datos_s5 = cargar_json_seguro('datos_script5.json')
    datos_s6 = cargar_json_seguro('datos_script6.json')
    datos_s7 = cargar_json_seguro('datos_script7.json')
    
    # 2) Análisis de datos por script
    print("Analizando datos...")
    analisis_s2 = analizar_script2(datos_s2)
    analisis_s4 = analizar_script4(datos_s4)
    analisis_s5 = analizar_script5(datos_s5)
    analisis_s6 = analizar_script6(datos_s6)
    analisis_s7 = analizar_script7(datos_s7)
    
    # 3) Generación de gráficos avanzados
    print("Generando gráficos profesionales...")
    img_dashboard = generar_dashboard_cumplimiento(analisis_s2)
    img_vulnerabilidades = generar_grafico_vulnerabilidades(analisis_s4, analisis_s5)
    img_simulacion = generar_grafico_simulacion(analisis_s6)
    img_costes = generar_grafico_costes(analisis_s7)
    
    # 4) Construcción del PDF profesional
    print("Construyendo PDF profesional...")
    pdf = InformeENSProfesional(company_name)
    
    # Portada e índice
    pdf.portada()
    pdf.indice()
    
    # ══════════════════════════════════════════════════════════════════════
    # 1. RESUMEN EJECUTIVO
    # ══════════════════════════════════════════════════════════════════════
    pdf.add_page()
    pdf.titulo_seccion(">> 1. RESUMEN EJECUTIVO")
    
    # Métricas clave del resumen
    total_controles = analisis_s2['total_controles'] if analisis_s2 else 0
    total_vulnerabilidades = analisis_s4['total_vulnerabilidades'] if analisis_s4 else 0
    total_incidentes = analisis_s5['total_incidentes'] if analisis_s5 else 0
    coste_inicial = analisis_s7['coste_total_inicial'] if analisis_s7 else 0
    
    # Calcular porcentaje de cumplimiento global
    if analisis_s2 and analisis_s2['familias']:
        familias = analisis_s2['familias']
        total_cumple = sum(familias[f]['cumple'] for f in familias)
        porcentaje_cumplimiento = round((total_cumple / total_controles) * 100, 1) if total_controles > 0 else 0
    else:
        porcentaje_cumplimiento = 0
    
    metricas_resumen = {
        'Fecha del Análisis': datetime.now().strftime("%d/%m/%Y"),
        'Controles ENS Evaluados': f'{total_controles} controles',
        'Cumplimiento Global': f'{porcentaje_cumplimiento}%',
        'Vulnerabilidades Detectadas': f'{total_vulnerabilidades} vulnerabilidades',
        'Incidentes de Seguridad': f'{total_incidentes} incidentes',
        'Inversión Estimada': f'€{coste_inicial:,.0f}' if coste_inicial > 0 else 'No calculada'
    }
    
    pdf.metricas_clave(metricas_resumen)
    
    # Estado general
    if porcentaje_cumplimiento >= 80:
        estado_general = "EXCELENTE - La organización muestra un nivel de cumplimiento muy alto."
    elif porcentaje_cumplimiento >= 60:
        estado_general = "BUENO - La organización tiene una base sólida con áreas de mejora identificadas."
    elif porcentaje_cumplimiento >= 40:
        estado_general = "MEJORABLE - Se requieren mejoras significativas en la seguridad."
    else:
        estado_general = "CRITICO - El nivel de cumplimiento requiere atención inmediata."
    
    pdf.subtitulo("Estado General de Cumplimiento")
    pdf.texto_normal(estado_general)
    
    # ══════════════════════════════════════════════════════════════════════
    # 2. CUMPLIMIENTO ENS POR FAMILIAS
    # ══════════════════════════════════════════════════════════════════════
    pdf.add_page()
    pdf.titulo_seccion("2. CUMPLIMIENTO ENS POR FAMILIAS")
    
    if img_dashboard:
        pdf.insertar_imagen_centrada(img_dashboard, ancho=180)
    
    if analisis_s2 and analisis_s2['familias']:
        pdf.subtitulo("Análisis Detallado por Familia")
        for familia, datos in analisis_s2['familias'].items():
            total_familia = datos['cumple'] + datos['parcial'] + datos['no_cumple']
            if total_familia > 0:
                pct_cumple = round((datos['cumple'] / total_familia) * 100, 1)
                pdf.texto_normal(f"• {familia}: {datos['cumple']}/{total_familia} controles ({pct_cumple}% cumplimiento)")
    
    # ══════════════════════════════════════════════════════════════════════
    # 3. ANÁLISIS DE VULNERABILIDADES E INCIDENTES
    # ══════════════════════════════════════════════════════════════════════
    pdf.add_page()
    pdf.titulo_seccion("3. ANALISIS DE VULNERABILIDADES E INCIDENTES")
    
    if img_vulnerabilidades:
        pdf.insertar_imagen_centrada(img_vulnerabilidades, ancho=180)
    
    # Script 4 - Vulnerabilidades
    if analisis_s4:
        pdf.subtitulo("Auditoría de Permisos y Accesos (Script 4)")
        pdf.texto_normal(f"Total de vulnerabilidades detectadas: {analisis_s4['total_vulnerabilidades']}")
        
        # Distribución por severidad con nombres específicos
        severidad = analisis_s4['por_severidad']
        vulnerabilidades_detalladas = analisis_s4['vulnerabilidades_por_severidad']
        
        pdf.texto_normal("Distribución por severidad:")
        for nivel, cantidad in severidad.items():
            if cantidad > 0:
                pdf.texto_normal(f"  • {nivel.title()}: {cantidad} vulnerabilidades")
                # Mostrar nombres específicos de vulnerabilidades
                if vulnerabilidades_detalladas.get(nivel):
                    for vuln_nombre in vulnerabilidades_detalladas[nivel][:3]:  # Máximo 3 por categoría
                        pdf.texto_normal(f"    - {vuln_nombre}")
                    if len(vulnerabilidades_detalladas[nivel]) > 3:
                        pdf.texto_normal(f"    - ... y {len(vulnerabilidades_detalladas[nivel]) - 3} más")
    
    # Script 5 - Incidentes
    if analisis_s5:
        pdf.subtitulo("Detección de Incidentes (Script 5)")
        pdf.texto_normal(f"Total de incidentes detectados: {analisis_s5['total_incidentes']}")
        
        # Distribución por tipo
        if analisis_s5['por_tipo']:
            pdf.texto_normal("Incidentes por tipo:")
            for tipo, cantidad in analisis_s5['por_tipo'].items():
                pdf.texto_normal(f"  • {tipo}: {cantidad} incidentes")
    
    # ══════════════════════════════════════════════════════════════════════
    # 4. SIMULACIÓN DE ATAQUES
    # ══════════════════════════════════════════════════════════════════════
    pdf.add_page()
    pdf.titulo_seccion("4. SIMULACION DE ATAQUES")
    
    if img_simulacion:
        pdf.insertar_imagen_centrada(img_simulacion, ancho=180)
    
    if analisis_s6:
        pdf.subtitulo("Resultados de la Simulación")
        pdf.texto_normal(f"Target analizado: {analisis_s6['target']}")
        pdf.texto_normal(f"Total de vulnerabilidades identificadas: {analisis_s6['total_vulnerabilidades']}")
        
        if analisis_s6['resumen_vulnerabilidades']:
            pdf.subtitulo("Vulnerabilidades Identificadas")
            for vuln in analisis_s6['resumen_vulnerabilidades']:
                pdf.texto_normal(f"• {vuln}")
    
    # ══════════════════════════════════════════════════════════════════════
    # 5. OPTIMIZACIÓN DE RECURSOS Y COSTES
    # ══════════════════════════════════════════════════════════════════════
    pdf.add_page()
    pdf.titulo_seccion("5. OPTIMIZACION DE RECURSOS Y COSTES")
    
    if img_costes:
        pdf.insertar_imagen_centrada(img_costes, ancho=180)
    
    if analisis_s7:
        # Métricas financieras
        metricas_financieras = {
            'Inversión Inicial': f"€{analisis_s7['coste_total_inicial']:,.0f}",
            'Coste Recurrente Anual': f"€{analisis_s7['coste_recurrente_anual']:,.0f}",
            'Horas Totales Estimadas': f"{analisis_s7['horas_totales']:,.0f} h",
            'ROI Estimado': f"{analisis_s7['roi_estimado']}%"
        }
        pdf.metricas_clave(metricas_financieras)
        
        # Plan de prioridades
        if analisis_s7['plan_prioridades']:
            pdf.subtitulo("Plan de Prioridades de Inversión")
            for i, item in enumerate(analisis_s7['plan_prioridades'], 1):
                concepto = item.get('concepto', '').replace('_', ' ').title()
                coste = item.get('coste', 0)
                pdf.texto_normal(f"{i}. {concepto}: €{coste:,.0f}")
    
    # ══════════════════════════════════════════════════════════════════════
    # 6. CONCLUSIONES Y RECOMENDACIONES
    # ══════════════════════════════════════════════════════════════════════
    pdf.add_page()
    pdf.titulo_seccion("6. CONCLUSIONES Y RECOMENDACIONES")
    
    # Conclusiones basadas en los datos
    pdf.subtitulo("Conclusiones Principales")
    
    conclusiones = []
    if porcentaje_cumplimiento >= 70:
        conclusiones.append("La organización muestra un buen nivel de madurez en ciberseguridad.")
    else:
        conclusiones.append("La organización requiere mejoras significativas en ciberseguridad.")
    
    if total_vulnerabilidades > 10:
        conclusiones.append("Se han identificado múltiples vulnerabilidades que requieren atención inmediata.")
    
    if total_incidentes > 5:
        conclusiones.append("La frecuencia de incidentes sugiere la necesidad de mejores controles preventivos.")
    
    if coste_inicial > 0:
        conclusiones.append(f"La inversión estimada de €{coste_inicial:,.0f} es necesaria para alcanzar el cumplimiento ENS.")
    
    for conclusion in conclusiones:
        pdf.texto_normal(f"• {conclusion}")
    
    # Recomendaciones específicas
    pdf.subtitulo("Recomendaciones Específicas")
    recomendaciones = [
        "Priorizar la implementación de controles de seguridad críticos",
        "Establecer un programa de formación continua en ciberseguridad",
        "Implementar monitorización y respuesta a incidentes 24/7",
        "Realizar evaluaciones de seguridad periódicas",
        "Mantener actualizado el plan de continuidad de negocio"
    ]
    
    for recomendacion in recomendaciones:
        pdf.texto_normal(f"• {recomendacion}")
    
    # Nota final
    pdf.ln(10)
    pdf.caja_destacada("""
NOTA FINAL:
Este informe representa una evaluación integral del estado de ciberseguridad de la organización.
Se recomienda revisar este análisis trimestralmente y actualizar las medidas según la evolución
de las amenazas y el crecimiento de la organización.
    """)
    
    # 7) Guardar PDF
    print("Guardando PDF...")
    nombre_pdf = f"Informe_ENS_Profesional_{company_name.replace(' ', '_')}_{datetime.now().strftime('%Y%m%d_%H%M')}.pdf"
    salida = os.path.join(REPORTS_DIR, nombre_pdf)
    pdf.output(salida)
    
    print(f"Informe generado exitosamente: {nombre_pdf}")
    return salida
