# -*- coding: utf-8 -*-
import sys, subprocess, re, mysql.connector, os, datetime
import concurrent.futures

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()
if len(sys.argv) < 5: sys.exit(1)
olt_id, frame, slot, port = sys.argv[1:5]

def parse_huawei_time(raw_val):
    import re
    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()
    
    # 1. Intento de lectura estandar
    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}"
    
    # 2. Intento de lectura Hex-STRING (Logica implementada del usuario)
    val_clean = val_str.replace("Hex-STRING:", "").replace("STRING:", "").replace('"', '').strip()
    hex_parts = val_clean.split()
    if len(hex_parts) >= 7:
        try:
            y = int(hex_parts[0]+hex_parts[1], 16)
            m = int(hex_parts[2], 16)
            d = int(hex_parts[3], 16)
            h = int(hex_parts[4], 16)
            min_ = int(hex_parts[5], 16)
            s = int(hex_parts[6], 16)
            return f"{y}-{m:02d}-{d:02d} {h:02d}:{min_:02d}:{s:02d}"
        except: pass
    return None

def get_snmp_bulkwalk_str(ip, port, comm, oid):
    cmd = f"snmpbulkwalk -v2c -c {comm} -Ona -t 5 -r 2 {ip}:{port} {oid}"
    try: return subprocess.check_output(cmd, shell=True).decode('latin-1', errors='ignore').splitlines()
    except: return []

def get_snmp_bulkwalk_hex(ip, port, comm, oid):
    cmd = f"snmpbulkwalk -v2c -c {comm} -Onx -t 5 -r 2 {ip}:{port} {oid}"
    try: return subprocess.check_output(cmd, shell=True).decode('latin-1', errors='ignore').splitlines()
    except: return []

def clean_name_cliente(raw_name):
    val = raw_name.strip()
    if "Hex-STRING:" in val:
        hex_part = val.split("Hex-STRING:")[1]
        hex_clean = re.sub(r'[^0-9A-Fa-f]', '', hex_part)
        if len(hex_clean) % 2 != 0: hex_clean = hex_clean[:-1]
        try: val = bytes.fromhex(hex_clean).decode('latin-1', errors='ignore')
        except: pass
        
    val = val.replace("STRING:", "").replace('"', '').replace('_', ' ').strip()
    for corte in [" zone ", " Zone ", " extid ", " authd ", " ont ", "\x00"]:
        if corte in val: val = val.split(corte)[0]
    return val.strip()

def clean_serial(raw_sn):
    val = raw_sn.replace("Hex-STRING: ", "").replace("STRING: ", "").replace('"', '').strip()
    if " " in val and len(val) > 10:
        try:
            ascii_val = bytes.fromhex(val.replace(" ", "")).decode('utf-8')
            if re.match(r'^[A-Za-z0-9]+$', ascii_val): return ascii_val
        except: pass 
    return val.replace(" ", "")

def main():
    conn = mysql.connector.connect(**DB_CONFIG)
    cursor = conn.cursor()
    cursor.execute("SELECT ip_address, snmp_community, snmp_port FROM olts WHERE id=%s", (olt_id,))
    data = cursor.fetchone()
    if not data: return
    ip, comm, snmp_port = data
    if not snmp_port: snmp_port = 161

    target_name = f"GPON {frame}/{slot}/{port}"
    port_index = None
    
    lines_if = get_snmp_bulkwalk_str(ip, snmp_port, comm, "1.3.6.1.2.1.31.1.1.1.1")
    if not lines_if: return 

    for l in lines_if:
        if target_name in l:
            port_index = l.split(" = ")[0].split(".")[-1]
            break
            
    if not port_index:
        conn.close()
        return

    with concurrent.futures.ThreadPoolExecutor(max_workers=7) as executor:
        f_st = executor.submit(get_snmp_bulkwalk_hex, ip, snmp_port, comm, f"1.3.6.1.4.1.2011.6.128.1.1.2.46.1.15.{port_index}")
        f_cs = executor.submit(get_snmp_bulkwalk_hex, ip, snmp_port, comm, f"1.3.6.1.4.1.2011.6.128.1.1.2.46.1.24.{port_index}")
        f_pw = executor.submit(get_snmp_bulkwalk_hex, ip, snmp_port, comm, f"1.3.6.1.4.1.2011.6.128.1.1.2.51.1.4.{port_index}")
        f_up = executor.submit(get_snmp_bulkwalk_str, ip, snmp_port, comm, f"1.3.6.1.4.1.2011.6.128.1.1.2.46.1.22.{port_index}")
        f_dw = executor.submit(get_snmp_bulkwalk_str, ip, snmp_port, comm, f"1.3.6.1.4.1.2011.6.128.1.1.2.46.1.23.{port_index}")
        f_sn = executor.submit(get_snmp_bulkwalk_hex, ip, snmp_port, comm, f"1.3.6.1.4.1.2011.6.128.1.1.2.43.1.3.{port_index}")
        f_nm = executor.submit(get_snmp_bulkwalk_str, ip, snmp_port, comm, f"1.3.6.1.4.1.2011.6.128.1.1.2.43.1.9.{port_index}")

        l_st, l_cs, l_pw = f_st.result(), f_cs.result(), f_pw.result()
        l_up, l_dw, l_sn, l_nm = f_up.result(), f_dw.result(), f_sn.result(), f_nm.result()

    onus_data = {}
    for l in l_st:
        m = re.search(fr'\.15\.{port_index}\.(\d+)\s*=\s*INTEGER:\s*(\d+)', l)
        if m: onus_data[m.group(1)] = {'st': int(m.group(2)), 'cs': 0, 'pw': -99.99, 'up': None, 'dw': None, 'sn': '', 'nm': 'SIN NOMBRE'}
    for l in l_cs:
        m = re.search(fr'\.24\.{port_index}\.(\d+)\s*=\s*INTEGER:\s*(\d+)', l)
        if m and m.group(1) in onus_data: onus_data[m.group(1)]['cs'] = int(m.group(2))
    for l in l_pw:
        m = re.search(fr'\.4\.{port_index}\.(\d+)\s*=\s*INTEGER:\s*(-?\d+)', l)
        if m and m.group(1) in onus_data:
            raw_p = int(m.group(2))
            if -6000 < raw_p < 1000: onus_data[m.group(1)]['pw'] = float(raw_p) / 100.0
    for l in l_up:
        m = re.search(fr'\.22\.{port_index}\.(\d+)\s*=\s*(.*)', l)
        if m and m.group(1) in onus_data: onus_data[m.group(1)]['up'] = parse_huawei_time(m.group(2))
    for l in l_dw:
        m = re.search(fr'\.23\.{port_index}\.(\d+)\s*=\s*(.*)', l)
        if m and m.group(1) in onus_data: onus_data[m.group(1)]['dw'] = parse_huawei_time(m.group(2))
    for l in l_sn:
        m = re.search(fr'\.3\.{port_index}\.(\d+)\s*=\s*(.*)', l)
        if m and m.group(1) in onus_data: onus_data[m.group(1)]['sn'] = clean_serial(m.group(2))
    for l in l_nm:
        m = re.search(fr'\.9\.{port_index}\.(\d+)\s*=\s*(.*)', l)
        if m and m.group(1) in onus_data: onus_data[m.group(1)]['nm'] = clean_name_cliente(m.group(2))

    cursor.execute("SELECT onu_id, id FROM onus WHERE olt_id=%s AND frame=%s AND slot=%s AND port=%s", (olt_id, frame, slot, port))
    existentes = {str(r[0]): r[1] for r in cursor.fetchall()}

    sql_insert = "INSERT INTO onus (olt_id, frame, slot, port, onu_id, serial_number, nombre_cliente, estado_actual, potencia_rx, fecha_estado) VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s)"
    
    ids_to_keep = set()

    for onu_id, d in onus_data.items():
        st_txt = "OFFLINE"
        if d['st'] == 1: st_txt, real_time = "ONLINE", d.get('up')
        else:
            if d['cs'] in [3, 13]: st_txt = "SIN ENERGIA"
            elif d['cs'] in [1, 2]: st_txt = "LOS (FIBRA)"
            real_time = d.get('dw')

        if onu_id in existentes:
            db_id = existentes[onu_id]
            ids_to_keep.add(db_id)
            if real_time:
                cursor.execute("UPDATE onus SET estado_actual=%s, potencia_rx=%s, fecha_estado=%s, serial_number=%s, nombre_cliente=%s WHERE id=%s", (st_txt, d['pw'], real_time, d['sn'], d['nm'], db_id))
            else:
                cursor.execute("UPDATE onus SET fecha_estado = IF(estado_actual != %s, NOW(), fecha_estado), estado_actual=%s, potencia_rx=%s, serial_number=%s, nombre_cliente=%s WHERE id=%s", (st_txt, st_txt, d['pw'], d['sn'], d['nm'], db_id))
        else:
            fecha_ins = real_time if real_time else datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
            cursor.execute(sql_insert, (olt_id, frame, slot, port, onu_id, d['sn'], d['nm'], st_txt, d['pw'], fecha_ins))

    l_deletes = [(db_id,) for onu, db_id in existentes.items() if db_id not in ids_to_keep]
    if l_deletes:
        cursor.executemany("DELETE FROM onus WHERE id=%s", l_deletes)

    conn.commit()
    conn.close()

if __name__ == "__main__":
    main()