# -*- coding: utf-8 -*-
import sys
import os
import re
import subprocess
import json
import mysql.connector

BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
DB_PHP_PATH = '/var/www/html/db.php'

import os
import os
import os
import os
def __get_db_config_dynamic():
    cfg = {'host': '127.0.0.1', 'user': 'saas_admin', 'password': 'AdminSaaS2026!', 'database': 'adminolt_db'}
    for db_path in ['/var/www/html/db.php', '/root/Workspace360_paquete/db.php']:
        try:
            if os.path.exists(db_path):
                with open(db_path, 'r', encoding='utf-8', errors='ignore') as f:
                    for line in f:
                        line = line.strip()
                        if line.startswith('$host') and '=' in line:
                            part = line.split("'")[1] if "'" in line else line.split('"')[1]
                            cfg['host'] = '127.0.0.1' if part == 'localhost' else part
                        elif line.startswith('$user') and '=' in line:
                            cfg['user'] = line.split("'")[1] if "'" in line else line.split('"')[1]
                        elif line.startswith('$pass') and '=' in line:
                            cfg['password'] = line.split("'")[1] if "'" in line else line.split('"')[1]
                        elif line.startswith('$db') and '=' in line:
                            cfg['database'] = line.split("'")[1] if "'" in line else line.split('"')[1]
                break
        except: pass
    return cfg
DB_CONFIG = __get_db_config_dynamic()
    
    try:
        conn = mysql.connector.connect(**db_config)
        cursor = conn.cursor(dictionary=True)
        
        # Buscar NAP
        cursor.execute("SELECT olt_id, slot, port FROM naps WHERE id = %s", (nap_id,))
        nap = cursor.fetchone()
        if not nap:
            print(json.dumps({"status": "error", "message": "Puerto no encontrado en BD"}))
            sys.exit(1)
            
        olt_id, slot, port_num = nap['olt_id'], nap['slot'], nap['port']
        
        # Buscar OLT
        cursor.execute("SELECT ip_address, snmp_port, snmp_community FROM olts WHERE id = %s", (olt_id,))
        olt = cursor.fetchone()
        ip, snmp_port, comm = olt['ip_address'], olt['snmp_port'], olt['snmp_community']
        
        # Buscar Clientes
        cursor.execute("SELECT onu_id FROM onus WHERE olt_id=%s AND slot=%s AND port=%s", (olt_id, slot, port_num))
        db_onus = [r['onu_id'] for r in cursor.fetchall()]
        
    except Exception as e:
        print(json.dumps({"status": "error", "message": f"Error BD: {str(e)}"}))
        sys.exit(1)

    if not db_onus:
        print(json.dumps({"status": "success", "message": "No hay ONUs en este puerto."}))
        sys.exit(0)

    sample_onus = db_onus[:3]
    ifIndex = find_port_ifindex(ip, snmp_port, comm, slot, port_num, sample_onus)

    if not ifIndex:
        # Si realmente el puerto no tiene a nadie vivo, blanqueamos
        cursor.execute("UPDATE onus SET estado_actual='OFFLINE', potencia_rx=-99.99 WHERE olt_id=%s AND slot=%s AND port=%s", (olt_id, slot, port_num))
        conn.commit()
        cursor.close()
        conn.close()
        print(json.dumps({"status": "success", "message": "Sincronizado: Puerto vacio o sin conexion."}))
        sys.exit(0)

    # Lanzamos las 3 consultas clave (Estado, Causa y Potencia)
    cmd_st = f"snmpbulkwalk -v2c -c {comm} -t 2 -r 1 -Cr15 -On {ip}:{snmp_port} 1.3.6.1.4.1.2011.6.128.1.1.2.46.1.15.{ifIndex}"
    cmd_cs = f"snmpbulkwalk -v2c -c {comm} -t 2 -r 1 -Cr15 -On {ip}:{snmp_port} 1.3.6.1.4.1.2011.6.128.1.1.2.46.1.24.{ifIndex}"
    cmd_pw = f"snmpbulkwalk -v2c -c {comm} -t 2 -r 1 -Cr15 -On {ip}:{snmp_port} 1.3.6.1.4.1.2011.6.128.1.1.2.51.1.4.{ifIndex}"

    out_st = run_cmd(cmd_st)
    out_cs = run_cmd(cmd_cs)
    out_pw = run_cmd(cmd_pw)

    # Proteccion anti-borrado si la OLT se traba
    if "Timeout" in out_st or "Timeout" in out_cs:
        print(json.dumps({"status": "error", "message": "Timeout: La OLT esta muy ocupada, intenta de nuevo en 10 segundos."}))
        sys.exit(1)

    states, causes, powers = {}, {}, {}
    
    # LA MAGIA: El [^\d-]* ignora la palabra "online(" o "offline(" y rescata solo el numero.
    reg_st = re.compile(rf'\.46\.1\.15\.{ifIndex}\.(\d+)\s*=\s*INTEGER:\s*[^\d-]*(-?\d+)')
    reg_cs = re.compile(rf'\.46\.1\.24\.{ifIndex}\.(\d+)\s*=\s*INTEGER:\s*[^\d-]*(-?\d+)')
    reg_pw = re.compile(rf'\.51\.1\.4\.{ifIndex}\.(\d+)\s*=\s*INTEGER:\s*[^\d-]*(-?\d+)')

    for line in out_st.splitlines():
        m = reg_st.search(line)
        if m: states[int(m.group(1))] = int(m.group(2))
        
    for line in out_cs.splitlines():
        m = reg_cs.search(line)
        if m: causes[int(m.group(1))] = int(m.group(2))
        
    for line in out_pw.splitlines():
        m = reg_pw.search(line)
        if m: powers[int(m.group(1))] = float(m.group(2)) / 100.0

    if not states:
        print(json.dumps({"status": "error", "message": "Fallo al leer respuestas de Huawei (formato no estandar).", "debug": out_st[:200]}))
        sys.exit(1)

    updates = []
    for onu_id in db_onus:
        run_state = states.get(onu_id, 2)
        cause_code = causes.get(onu_id, 0)
        rx_power = powers.get(onu_id, -99.99)
        
        final_status = "OFFLINE"
        if run_state == 1:
            final_status = "ONLINE"
        else:
            if cause_code in [3, 13]: final_status = "SIN ENERGIA"
            elif cause_code in [1, 2]: final_status = "LOS (FIBRA)"

        updates.append((final_status, rx_power, olt_id, slot, port_num, onu_id))

    try:
        # Actualizamos estado, potencia y fecha
        cursor.executemany("UPDATE onus SET estado_actual=%s, potencia_rx=%s, fecha_estado=NOW() WHERE olt_id=%s AND slot=%s AND port=%s AND onu_id=%s", updates)
        conn.commit()
    except Exception: 
        pass
    finally:
        cursor.close()
        conn.close()

    print(json.dumps({"status": "success", "message": f"Sincronizados {len(updates)} clientes con exito."}))

if __name__ == "__main__":
    main()
