# -*- coding: utf-8 -*-
import sys, mysql.connector, re, os, time
from netmiko import ConnectHandler

# --- EXTRACTOR A PRUEBA DE FALLOS Y TILDES ---
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()
def get_db(): return mysql.connector.connect(**DB_CONFIG)
# ---------------------------------------------

def scan_olt(olt_id, ip, user, password, ssh_port):
    print(f"--- Escaneando OLT {ip} ---")
    device = {
        'device_type': 'huawei_smartax',
        'host': ip,
        'username': user,
        'password': password,
        'port': ssh_port,
        'global_delay_factor': 2,
        'timeout': 90 # Aumentado para soportar listas largas
    }

    current_sn_list = []

    try:
        conn = ConnectHandler(**device)
        
        # 1. Preparar terminal para evitar paginacin en lo posible
        conn.write_channel('enable\n')
        time.sleep(0.5)
        conn.read_channel()
        conn.write_channel('undo smart\n')
        time.sleep(0.5)
        conn.read_channel()
        conn.write_channel('scroll 512\n')
        time.sleep(0.5)
        conn.read_channel()
        
        # 2. Lanzar el comando de escaneo masivo
        conn.write_channel('display ont autofind all\n')
        time.sleep(2)

        output = ""
        # 3. BUCLE DE FUERZA BRUTA: Presionar barra espaciadora si Huawei lo pide
        for _ in range(100):
            chunk = conn.read_channel()
            output += chunk
            
            if "---- More" in chunk or "----" in chunk and "More" in chunk:
                conn.write_channel(' ') # Presionar ESPACIO
                time.sleep(0.8)
            elif "#" in chunk or ">" in chunk or "Failure:" in chunk:
                break
            else:
                time.sleep(0.8)

        conn.disconnect()

        # 4. Dividir y analizar la respuesta de Huawei
        bloques_texto = output.split('----------------------------------------------------------------------------')

        db = get_db()
        cursor = db.cursor()
        
        count = 0
        for bloque in bloques_texto:
            # Regex optimizado para asegurar la captura de todo tipo de modelos
            m_fsp = re.search(r'F/S/P\s*:\s*(\d+)/(\d+)/(\d+)', bloque)
            m_sn = re.search(r'Ont SN\s*:\s*([A-Za-z0-9]+)', bloque)
            m_model = re.search(r'Ont EquipmentID\s*:\s*([A-Za-z0-9\-\_]+)', bloque)

            if m_fsp and m_sn:
                f, s, p = m_fsp.groups()
                sn = m_sn.group(1).upper()
                model = m_model.group(1) if m_model else 'Generic'
                
                current_sn_list.append(sn)

                sql = """
                INSERT INTO discovered_onus (olt_id, frame, slot, port, serial_number, model, fecha_deteccion) 
                VALUES (%s, %s, %s, %s, %s, %s, NOW())
                ON DUPLICATE KEY UPDATE fecha_deteccion=NOW(), frame=%s, slot=%s, port=%s, model=%s
                """
                cursor.execute(sql, (olt_id, f, s, p, sn, model, f, s, p, model))
                print(f"    + Procesado: {sn} ({model}) en {f}/{s}/{p}")
                count += 1

        print(f" -> Encontrados {count} equipos pendientes.")

        # 5. LIMPIEZA: Borrar de DB los que ya no estan esperando en la OLT
        if current_sn_list:
            format_strings = ','.join(['%s'] * len(current_sn_list))
            sql_clean = f"DELETE FROM discovered_onus WHERE olt_id = %s AND serial_number NOT IN ({format_strings})"
            params = [olt_id] + current_sn_list
            cursor.execute(sql_clean, tuple(params))
        else:
            print(" -> OLT limpia. Borrando registros antiguos...")
            cursor.execute("DELETE FROM discovered_onus WHERE olt_id = %s", (olt_id,))

        db.commit()
        db.close()

    except Exception as e:
        print(f"Error OLT {ip}: {e}")

def main():
    try:
        db = get_db()
        cur = db.cursor(dictionary=True)
        cur.execute("SELECT * FROM olts WHERE estado=1")
        olts = cur.fetchall()
        db.close()
        
        if not olts: return
        for o in olts:
            scan_olt(o['id'], o['ip_address'], o['ssh_user'], o['ssh_pass'], o['ssh_port'] if o['ssh_port'] else 22)
    except Exception as e:
        print(f"Error general: {e}")

if __name__ == "__main__":
    main()