import sys, os, re, subprocess, json
try:
    import mysql.connector
except ImportError:
    print(json.dumps({"status": "error", "message": "Falta mysql.connector"}))
    sys.exit(1)

def get_db_config():
    cfg = {'host': '127.0.0.1', 'user': 'saas_admin', 'password': 'AdminSaaS2026!', 'database': 'adminolt_db'}
    paths = ['/var/www/html/db.php', '/root/Workspace360_paquete/db.php']
    for db_path in paths:
        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: cfg['host'] = '127.0.0.1' if 'localhost' in line else line.split("'")[1] if "'" in line else line.split('"')[1]
                        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

def parse_huawei_time(raw_val):
    if not raw_val or "No Such" in raw_val: return None
    val_str = raw_val.split("=", 1)[-1].strip() if "=" in raw_val else raw_val.strip()
    m_str = re.search(r'(\d{4})[-/](\d{1,2})[-/](\d{1,2})[ ,T]+(\d{1,2}):(\d{1,2}):(\d{1,2})', val_str)
    if m_str: return f"{m_str.group(1)}-{int(m_str.group(2)):02d}-{int(m_str.group(3)):02d} {int(m_str.group(4)):02d}:{int(m_str.group(5)):02d}:{int(m_str.group(6)):02d}"
    val_clean = val_str.replace("Hex-STRING:", "").replace("STRING:", "").replace('"', '').strip()
    hex_parts = val_clean.split()
    if len(hex_parts) >= 7:
        try:
            return f"{int(hex_parts[0]+hex_parts[1], 16)}-{int(hex_parts[2], 16):02d}-{int(hex_parts[3], 16):02d} {int(hex_parts[4], 16):02d}:{int(hex_parts[5], 16):02d}:{int(hex_parts[6], 16):02d}"
        except: pass
    return None

def run_cmd(cmd):
    try: return subprocess.check_output(cmd, shell=True, stderr=subprocess.STDOUT).decode('latin-1', errors='ignore')
    except subprocess.CalledProcessError as e: return e.output.decode('latin-1', errors='ignore')

def main():
    if len(sys.argv) < 2:
        print(json.dumps({"status": "error", "message": "ID ONU requerido"}))
        sys.exit(1)

    onu_db_id = sys.argv[1]
    db_config = get_db_config()
    
    try:
        conn = mysql.connector.connect(**db_config)
        cursor = conn.cursor(dictionary=True)
        cursor.execute("SELECT o.slot, o.port, o.onu_id, t.ip_address, t.snmp_port, t.snmp_community FROM onus o JOIN olts t ON o.olt_id = t.id WHERE o.id = %s", (onu_db_id,))
        onu = cursor.fetchone()
    except Exception as e:
        print(json.dumps({"status": "error", "message": f"Error BD: {e}"}))
        sys.exit(1)

    if not onu:
        print(json.dumps({"status": "error", "message": "ONU no encontrada"}))
        sys.exit(1)

    ip, port, comm, onuId = onu['ip_address'], onu['snmp_port'], onu['snmp_community'], onu['onu_id']
    
    # Encontrar ifIndex aproximado usando walk directo para no fallar
    base_oid = f"1.3.6.1.4.1.2011.6.128.1.1.2.46.1.15"
    cmd_walk = f"snmpbulkwalk -v2c -c {comm} -t 1.5 -r 1 -On {ip}:{port} {base_oid}"
    out_walk = run_cmd(cmd_walk)
    
    ifIndex = None
    for line in out_walk.splitlines():
        m = re.search(r'\.46\.1\.15\.(\d+)\.(\d+)\s*=\s*INTEGER:', line)
        if m and int(m.group(2)) == int(onuId):
            idx = int(m.group(1))
            s = (idx >> 13) & 0x3F if idx > 65535 else (idx >> 8) & 0xFF
            pt = (idx >> 8) & 0x1F if idx > 65535 else idx & 0xFF
            if s == int(onu['slot']) and pt == int(onu['port']):
                ifIndex = idx
                break

    if not ifIndex:
        print(json.dumps({"status": "success", "estado": "OFFLINE", "potencia": "--", "uptime": "Desconocido", "modelo": "---"}))
        sys.exit(0)

    oid_st = f"1.3.6.1.4.1.2011.6.128.1.1.2.46.1.15.{ifIndex}.{onuId}"
    oid_cs = f"1.3.6.1.4.1.2011.6.128.1.1.2.46.1.24.{ifIndex}.{onuId}"
    oid_pw = f"1.3.6.1.4.1.2011.6.128.1.1.2.51.1.4.{ifIndex}.{onuId}"
    oid_up = f"1.3.6.1.4.1.2011.6.128.1.1.2.46.1.22.{ifIndex}.{onuId}"
    oid_dw = f"1.3.6.1.4.1.2011.6.128.1.1.2.46.1.23.{ifIndex}.{onuId}"
    
    # 1. Consulta Numerica
    out_num = run_cmd(f"snmpget -v2c -c {comm} -t 2 -r 1 -On {ip}:{port} {oid_st} {oid_cs} {oid_pw}")
    # 2. Consulta Hexadecimal
    out_hex = run_cmd(f"snmpget -v2c -c {comm} -t 2 -r 1 -Onx {ip}:{port} {oid_up} {oid_dw}")

    run_state, cause_code, power_rx = 2, 0, -99.99
    uptime, downtime = None, None

    # Lectura relajada (sin depender del ifIndex estricto)
    for line in out_num.splitlines():
        if "46.1.15." in line and "INTEGER:" in line:
            m = re.search(r'INTEGER:\s*[^\d-]*(-?\d+)', line)
            if m: run_state = int(m.group(1))
        elif "46.1.24." in line and "INTEGER:" in line:
            m = re.search(r'INTEGER:\s*[^\d-]*(-?\d+)', line)
            if m: cause_code = int(m.group(1))
        elif "51.1.4." in line and "INTEGER:" in line:
            m = re.search(r'INTEGER:\s*[^\d-]*(-?\d+)', line)
            if m: power_rx = float(m.group(1)) / 100.0

    for line in out_hex.splitlines():
        if "46.1.22." in line: uptime = parse_huawei_time(line)
        elif "46.1.23." in line: downtime = parse_huawei_time(line)

    final_status = "ONLINE" if run_state == 1 else "OFFLINE"
    if run_state != 1:
        if cause_code in [3, 13]: final_status = "SIN ENERGIA"
        elif cause_code in [1, 2]: final_status = "LOS (FIBRA)"
        
    real_time = uptime if run_state == 1 else downtime

    try:
        if real_time:
            cursor.execute("UPDATE onus SET estado_actual=%s, potencia_rx=COALESCE(%s, potencia_rx), fecha_estado=%s WHERE id=%s",
                          (final_status, power_rx if power_rx != -99.99 else None, real_time, onu_db_id))
            conn.commit()
    except Exception: pass 
    finally:
        cursor.close()
        conn.close()

    print(json.dumps({
        "status": "success", 
        "estado": final_status, 
        "potencia": f"{power_rx:.2f}" if power_rx != -99.99 else "--", 
        "uptime": real_time if real_time else "Desconocido",
        "modelo": "---"
    }))

if __name__ == "__main__":
    main()