import boto3
import logging
import hashlib
from datetime import datetime, timedelta, timezone

logger = logging.getLogger(__name__)

class AgAuditor:
    """
    Antigravity Lite - Glue Cost & FinOps Auditor
    ========================================
    Herramienta de auditoría financiera y operativa para AWS Glue.
    Evalúa si estás pagando sobrecostos masivos en la nube debido a bucles infinitos 
    o configuraciones de RAM infladas para encubrir fallos del Catalyst Optimizer.
    """
    
    @staticmethod
    def get_dpu_price(region: str) -> float:
        # Standard AWS Glue DPU per hour cost
        return 0.44 

    @classmethod
    def run_aws_audit(cls, region="us-east-1", dias_analisis=7, anonimize=False):
        # Paleta de colores ANSI "Premium"
        C_RESET = "\033[0m"
        C_BOLD = "\033[1m"
        C_CYAN = "\033[96m"
        C_GREEN = "\033[92m"
        C_RED = "\033[91m"
        C_YELLOW = "\033[93m"
        C_GRAY = "\033[90m"

        def header():
            print(f"\n{C_CYAN}{C_BOLD}┌────────────────────────────────────────────────────────────────────────────────────────┐")
            print(f"│  🌌 ANTIGRAVITY LITE : AI-POWRED FINOPS AUDITOR                                        │")
            print(f"└────────────────────────────────────────────────────────────────────────────────────────┘{C_RESET}")
            print(f"{C_GRAY}📡 Iniciando diagnóstico en {C_BOLD}{region}{C_RESET}{C_GRAY} (Métricas de los últimos {dias_analisis} días){C_RESET}\n")

        header()
        
        try:
            glue_client = boto3.client('glue', region_name=region)
            cw_client = boto3.client('cloudwatch', region_name=region)
            glue_client.get_jobs(MaxResults=1)
        except Exception as e:
            print("❌ Error de Autenticación AWS. Verifique sus credenciales Boto3.")
            return

        tiempo_limite = datetime.now(timezone.utc) - timedelta(days=dias_analisis)
        
        jobs = []
        paginator = glue_client.get_paginator('get_jobs')
        for page in paginator.paginate():
            for job in page.get('Jobs', []):
                jobs.append(job['Name'])
                
        if not jobs:
            print("No se encontraron Jobs de AWS Glue desplegados.")
            return
            
        print(f" {C_GRAY}🔍 Se descubrieron {len(jobs)} Jobs analizando consumo de DPUs...{C_RESET}\n")
        
        costo_dpu_hora = cls.get_dpu_price(region)
        resultados = []

        for job_name in jobs:
            runs_validos = 0
            total_horas_ejecucion = 0
            dpus_reales_promedio = 0
            ultimo_worker_type = "N/A"
            
            runs_paginator = glue_client.get_paginator('get_job_runs')
            try:
                for page in runs_paginator.paginate(JobName=job_name):
                    for run in page.get('JobRuns', []):
                        if run.get('StartedOn', datetime.min.replace(tzinfo=timezone.utc)) < tiempo_limite:
                            continue
                        
                        runs_validos += 1
                        
                        if 'CompletedOn' in run and 'StartedOn' in run:
                            duracion_segundos = (run['CompletedOn'] - run['StartedOn']).total_seconds()
                            total_horas_ejecucion += (duracion_segundos / 3600.0)
                            
                        worker_type = run.get('WorkerType', 'G.1X')
                        num_workers = run.get('NumberOfWorkers', run.get('MaxCapacity', 2))
                        
                        peso_dpu = {'Standard': 1, 'G.1X': 1, 'G.2X': 2, 'G.4X': 4, 'G.8X': 8, 'Z.2X': 2}
                        dpus_reales = num_workers * peso_dpu.get(worker_type, 1)
                        
                        dpus_reales_promedio = dpus_reales
                        ultimo_worker_type = worker_type
                        
            except Exception:
                continue 
                
            if runs_validos == 0:
                continue
                
            max_memory_percent = 0.0
            try:
                metric_response = cw_client.get_metric_statistics(
                    Namespace='Glue',
                    MetricName='glue.driver.jvm.heap.usage', 
                    Dimensions=[
                        {'Name': 'JobName', 'Value': job_name},
                        {'Name': 'Type', 'Value': 'gauge'}
                    ],
                    StartTime=tiempo_limite,
                    EndTime=datetime.now(timezone.utc),
                    Period=3600,
                    Statistics=['Maximum']
                )
                datapoints = metric_response.get('Datapoints', [])
                if datapoints:
                    max_memory_percent = max([dp['Maximum'] for dp in datapoints]) * 100
            except Exception:
                pass 
                
            gasto_total = total_horas_ejecucion * dpus_reales_promedio * costo_dpu_hora
            
            if gasto_total > 0:
                resultados.append({
                    "nombre": job_name,
                    "runs": runs_validos,
                    "dpus": dpus_reales_promedio,
                    "worker_type": ultimo_worker_type,
                    "memoria": max_memory_percent,
                    "gasto": gasto_total
                })
                
        resultados = sorted(resultados, key=lambda x: x["gasto"], reverse=True)
        
        # Cálculo dinámico de anchos de columna
        top_results = resultados[:10]
        if not top_results:
            print(f" {C_GRAY}No hay gastos significativos detectados en el periodo.{C_RESET}")
            return
            
        name_width = max([len(r['nombre'][:50]) for r in top_results] + [15])
        col_name = f"{'AWS GLUE JOB NAME':<{name_width}}"
        col_type = f"{'TYPE':<8}"
        col_dpus = f"{'DPUs':<6}"
        col_ram = f"{'RAM PEAK':<10}"
        col_cost = f"{'7D COST'}"
        
        # Header de la Tabla
        print(f" {C_BOLD}{C_CYAN}{col_name} │ {col_type} │ {col_dpus} │ {col_ram} │ {col_cost}{C_RESET}")
        print(f" {C_GRAY}" + "─" * (name_width + 45) + f"{C_RESET}")

        total_desperdicio = 0
        for res in top_results:
            name_display = res['nombre']
            
            # Algoritmo de Anonimización si está activo
            if anonimize:
                # Generamos un hash corto determinista basado en el nombre original
                h = hashlib.md5(name_display.encode()).hexdigest()[:4]
                name_display = f"AWS-GLUE-JOB-{h.upper()}"
            
            if len(name_display) > name_width:
                name_display = name_display[:name_width-3] + "..."
            
            mem_val = res['memoria']
            if mem_val > 0:
                mem_str = f"{mem_val:.1f}%"
                mem_color = C_RED if mem_val > 85.0 else C_GREEN
            else:
                mem_str = "N/A"
                mem_color = C_GRAY
            
            # Alerta de desperdicio
            waste_tag = f" {C_RED}⚠️{C_RESET}" if (res['memoria'] > 85.0 or res['worker_type'] in ['G.4X', 'G.8X']) else "  "
            
            if res['memoria'] > 85.0 or res['worker_type'] in ['G.4X', 'G.8X']:
                total_desperdicio += (res['gasto'] * 0.6)
                
            print(f" {name_display:<{name_width}} │ {C_YELLOW}{res['worker_type']:<8}{C_RESET} │ {res['dpus']:<6.1f} │ {mem_color}{mem_str:<10}{C_RESET} │ {C_BOLD}${res['gasto']:,.2f}{C_RESET}{waste_tag}")
            
        print(f" {C_GRAY}" + "─" * (name_width + 45) + f"{C_RESET}")
            
        print("-" * 90)
        print(f"\n {C_BOLD}{C_RED}🚨 REPORTE DE EXTRACCIÓN DE VALOR (ESTIMADO):{C_RESET}")
        print(f" {C_GREEN}Estás perdiendo un estimado de: ${total_desperdicio * 4:,.2f} USD al mes en sobrecostos de Glue.{C_RESET}")
        
        print(f"\n{C_YELLOW}┌────────────────────────────────────────────────────────────────────────────────────────┐")
        print(f"│  🚀 OPTIMIZACIÓN DISPONIBLE CON ANTIGRAVITY PRO                                        │")
        print(f"├────────────────────────────────────────────────────────────────────────────────────────┤")
        print(f"│  • ¿Scripts bloqueados por OOM en el Catalyst?                                        │")
        print(f"│  • ¿Facturas gigantes de AWS Glue por WorkerTypes G.4X redundantes?                   │")
        print(f"│                                                                                        │")
        print(f"│  {C_BOLD}Contacta para demo técnica: https://www.linkedin.com/in/andres-felipe-vega-beltran/   {C_RESET}{C_YELLOW}│")
        print(f"└────────────────────────────────────────────────────────────────────────────────────────┘{C_RESET}\n")
