#!/usr/bin/env python3
"""
verificar_integridad.py - Health check completo del sistema de centralita tarot
Verifica todos los componentes y su correcto funcionamiento
"""

import os
import sys
sys.path.insert(0, '/etc/centralita-tarot/db_wrapper')
from python_helper import get_asterisk_connection, get_panel_connection
import subprocess
import requests
import socket
from datetime import datetime, timedelta
import json

# Configuración
DB_HOST = 'localhost'
DB_USER = 'asteriskuser'
DB_PASSWORD = 'P4nd0r01$'
AMI_HOST = '127.0.0.1'
AMI_PORT = 5038
AMI_USER = 'reportuser'
AMI_SECRET = 'tsadfgas5rSegura'

# Colores para output
class Colors:
    GREEN = '\033[92m'
    YELLOW = '\033[93m'
    RED = '\033[91m'
    BLUE = '\033[94m'
    END = '\033[0m'

def print_status(component, status, details=""):
    """Imprime el estado de un componente con colores"""
    if status == "OK":
        color = Colors.GREEN
        symbol = "✓"
    elif status == "WARNING":
        color = Colors.YELLOW
        symbol = "⚠"
    else:
        color = Colors.RED
        symbol = "✗"
    
    print(f"{color}[{symbol}]{Colors.END} {component:<30} {status:<10} {details}")

def check_mysql_connection():
    """Verifica conexión a MySQL"""
    try:
        # Verificar panel_tarot
        conn = MySQLdb.connect(host=DB_HOST, user=DB_USER, passwd=DB_PASSWORD, db='panel_tarot')
        cursor = conn.cursor()
        cursor.execute("SELECT COUNT(*) FROM tarotistas")
        tarotistas_count = cursor.fetchone()[0]
        cursor.close()
        conn.close()
        
        # Verificar asterisk
        conn = MySQLdb.connect(host=DB_HOST, user=DB_USER, passwd=DB_PASSWORD, db='asterisk')
        cursor = conn.cursor()
        cursor.execute("SELECT COUNT(*) FROM agentes")
        agentes_count = cursor.fetchone()[0]
        cursor.close()
        conn.close()
        
        print_status("MySQL Connection", "OK", f"Tarotistas: {tarotistas_count}, Agentes: {agentes_count}")
        return True
    except Exception as e:
        print_status("MySQL Connection", "ERROR", str(e))
        return False

def check_asterisk_running():
    """Verifica que Asterisk esté ejecutándose"""
    try:
        result = subprocess.run(['asterisk', '-rx', 'core show version'], 
                              capture_output=True, text=True)
        if result.returncode == 0:
            version = result.stdout.strip().split('\n')[0]
            print_status("Asterisk Service", "OK", version)
            return True
        else:
            print_status("Asterisk Service", "ERROR", "No se pudo ejecutar comando")
            return False
    except Exception as e:
        print_status("Asterisk Service", "ERROR", str(e))
        return False

def check_ami_connection():
    """Verifica conexión AMI"""
    try:
        sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        sock.settimeout(5)
        result = sock.connect_ex((AMI_HOST, AMI_PORT))
        sock.close()
        
        if result == 0:
            print_status("AMI Connection", "OK", f"Puerto {AMI_PORT} accesible")
            return True
        else:
            print_status("AMI Connection", "ERROR", f"Puerto {AMI_PORT} no accesible")
            return False
    except Exception as e:
        print_status("AMI Connection", "ERROR", str(e))
        return False

def check_web_services():
    """Verifica servicios web"""
    services = [
        ("Panel Tarot", "http://localhost/panel/api/api_health_check.php"),
        ("PBX Tool", "http://localhost/pbx/api/v1/status.php")
    ]
    
    all_ok = True
    for name, url in services:
        try:
            response = requests.get(url, timeout=5)
            if response.status_code == 200:
                print_status(f"Web Service - {name}", "OK", f"HTTP {response.status_code}")
            else:
                print_status(f"Web Service - {name}", "WARNING", f"HTTP {response.status_code}")
                all_ok = False
        except Exception as e:
            print_status(f"Web Service - {name}", "ERROR", "No responde")
            all_ok = False
    
    return all_ok

def check_active_calls():
    """Verifica llamadas activas y consistencia"""
    try:
        conn = MySQLdb.connect(host=DB_HOST, user=DB_USER, passwd=DB_PASSWORD, db='asterisk')
        cursor = conn.cursor()
        
        # Llamadas activas
        cursor.execute("SELECT COUNT(*) FROM active_calls")
        active_calls = cursor.fetchone()[0]
        
        # Agentes ocupados
        cursor.execute("SELECT COUNT(*) FROM agentes WHERE estado_ocupacion = 1")
        busy_agents = cursor.fetchone()[0]
        
        # Verificar consistencia
        if active_calls == 0 and busy_agents == 0:
            status = "OK"
            details = "Sin llamadas activas"
        elif abs(active_calls - busy_agents) <= 2:  # Tolerar pequeñas diferencias
            status = "OK"
            details = f"Llamadas: {active_calls}, Agentes ocupados: {busy_agents}"
        else:
            status = "WARNING"
            details = f"Inconsistencia - Llamadas: {active_calls}, Agentes: {busy_agents}"
        
        print_status("Active Calls Check", status, details)
        
        cursor.close()
        conn.close()
        return status == "OK"
    except Exception as e:
        print_status("Active Calls Check", "ERROR", str(e))
        return False

def check_disk_space():
    """Verifica espacio en disco"""
    try:
        result = subprocess.run(['df', '-h'], capture_output=True, text=True)
        lines = result.stdout.strip().split('\n')[1:]  # Skip header
        
        warnings = []
        for line in lines:
            parts = line.split()
            if len(parts) >= 5 and parts[0].startswith('/dev/'):
                mount = parts[5]
                usage = int(parts[4].rstrip('%'))
                
                if usage >= 90:
                    warnings.append(f"{mount}: {usage}%")
                elif usage >= 80:
                    print_status(f"Disk Space - {mount}", "WARNING", f"{usage}% usado")
        
        if warnings:
            print_status("Disk Space", "ERROR", f"Crítico: {', '.join(warnings)}")
            return False
        else:
            print_status("Disk Space", "OK", "Suficiente espacio disponible")
            return True
    except Exception as e:
        print_status("Disk Space", "ERROR", str(e))
        return False

def check_agi_scripts():
    """Verifica scripts AGI"""
    agi_path = "/var/lib/asterisk/agi-bin"
    required_files = [
        "main_call_handler.py",
        "call_system/processors/trunk_processor.py",
        "call_system/database/connections.py"
    ]
    
    all_ok = True
    for file in required_files:
        full_path = os.path.join(agi_path, file)
        if os.path.exists(full_path):
            if os.access(full_path, os.X_OK):
                print_status(f"AGI Script - {file}", "OK", "Existe y es ejecutable")
            else:
                print_status(f"AGI Script - {file}", "WARNING", "No es ejecutable")
                all_ok = False
        else:
            print_status(f"AGI Script - {file}", "ERROR", "No existe")
            all_ok = False
    
    return all_ok

def check_logs():
    """Verifica logs recientes y errores"""
    log_files = [
        ("/var/log/asterisk/full", "Asterisk Full Log"),
        ("/var/log/asterisk/python_call_system.log", "Python AGI Log")
    ]
    
    for log_file, name in log_files:
        try:
            if os.path.exists(log_file):
                # Verificar última modificación
                mtime = os.path.getmtime(log_file)
                last_mod = datetime.fromtimestamp(mtime)
                time_diff = datetime.now() - last_mod
                
                if time_diff < timedelta(minutes=5):
                    print_status(f"Log Activity - {name}", "OK", "Activo")
                elif time_diff < timedelta(hours=1):
                    print_status(f"Log Activity - {name}", "WARNING", f"Última actividad hace {int(time_diff.seconds/60)} min")
                else:
                    print_status(f"Log Activity - {name}", "ERROR", "Sin actividad reciente")
            else:
                print_status(f"Log Activity - {name}", "ERROR", "Archivo no existe")
        except Exception as e:
            print_status(f"Log Activity - {name}", "ERROR", str(e))

def check_processes():
    """Verifica procesos críticos"""
    processes = [
        ("asterisk", "Asterisk PBX"),
        ("mysqld", "MySQL Server"),
        ("apache2", "Apache Web Server")
    ]
    
    for process, name in processes:
        try:
            result = subprocess.run(['pgrep', '-x', process], capture_output=True)
            if result.returncode == 0:
                pid_count = len(result.stdout.decode().strip().split('\n'))
                print_status(f"Process - {name}", "OK", f"{pid_count} proceso(s)")
            else:
                print_status(f"Process - {name}", "ERROR", "No está ejecutándose")
        except Exception as e:
            print_status(f"Process - {name}", "ERROR", str(e))

def generate_report():
    """Genera reporte JSON"""
    report = {
        "timestamp": datetime.now().isoformat(),
        "hostname": socket.gethostname(),
        "checks_performed": datetime.now().strftime("%Y-%m-%d %H:%M:%S")
    }
    
    # Guardar reporte
    report_file = f"/var/www/html/docs/health_check_{datetime.now().strftime('%Y%m%d_%H%M%S')}.json"
    with open(report_file, 'w') as f:
        json.dump(report, f, indent=2)
    
    print(f"\n{Colors.BLUE}Reporte guardado en: {report_file}{Colors.END}")

def main():
    """Función principal"""
    print("=" * 60)
    print(f"{Colors.BLUE}HEALTH CHECK - SISTEMA CENTRALITA TAROT{Colors.END}")
    print(f"Fecha: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
    print("=" * 60)
    
    # Ejecutar verificaciones
    checks = [
        ("Base de Datos", check_mysql_connection),
        ("Asterisk", check_asterisk_running),
        ("AMI", check_ami_connection),
        ("Servicios Web", check_web_services),
        ("Llamadas Activas", check_active_calls),
        ("Espacio en Disco", check_disk_space),
        ("Scripts AGI", check_agi_scripts),
        ("Logs", check_logs),
        ("Procesos", check_processes)
    ]
    
    print("\nVERIFICACIONES:\n")
    
    all_ok = True
    for name, check_func in checks:
        try:
            result = check_func()
            if not result:
                all_ok = False
        except Exception as e:
            print_status(name, "ERROR", f"Excepción: {str(e)}")
            all_ok = False
        print()  # Línea en blanco entre secciones
    
    # Resumen final
    print("=" * 60)
    if all_ok:
        print(f"{Colors.GREEN}RESULTADO: SISTEMA FUNCIONANDO CORRECTAMENTE{Colors.END}")
        exit_code = 0
    else:
        print(f"{Colors.RED}RESULTADO: SE DETECTARON PROBLEMAS{Colors.END}")
        exit_code = 1
    
    # Generar reporte
    generate_report()
    
    sys.exit(exit_code)

if __name__ == "__main__":
    main()