"""Diagnóstico completo automático (modo instalación)."""
from __future__ import annotations

import time
from typing import Callable, List, Optional

from .arp_watch import ArpWatcher
from .events import EventLog
from .models import Device, NetInfo, load_config
from .monitor import MonitorEngine
from .netinfo import get_net_info, suspicious_dhcp_notes
from .report import generate_html_report
from .scanner import NetworkScanner


Progress = Callable[[str], None]


def run_full_diagnostic(
    cidr: Optional[str] = None,
    duration_min: int = 15,
    interval_sec: float = 2.0,
    on_progress: Optional[Progress] = None,
    stop_flag: Optional[Callable[[], bool]] = None,
) -> tuple:
    """
    Ejecuta: netinfo → scan → ARP → monitor N minutos → informe.
    duration_min=0 → continuo (hasta stop_flag).
    Retorna (net, devices, report_path, conclusion).
    """
    def prog(msg: str) -> None:
        if on_progress:
            on_progress(msg)

    def stopped() -> bool:
        return bool(stop_flag and stop_flag())

    cfg = load_config()
    log = EventLog()
    arp = ArpWatcher()
    net = get_net_info()
    prog(f"Adaptador: {net.adapter} | IP {net.ip} | GW {net.gateway}")
    log.info(net.ip, "NETINFO", f"cidr={net.cidr} dhcp={net.dhcp_server}")

    target = cidr or net.cidr
    if not target:
        raise RuntimeError("No se pudo detectar la subred. Introduzca CIDR manualmente.")

    prog(f"Escaneando {target}…")
    scanner = NetworkScanner(arp=arp)
    devices = scanner.scan(
        target,
        on_progress=lambda d, t, m: prog(f"Scan {d}/{t}"),
    )
    cams = [d for d in devices if d.device_type == "Camara"]
    prog(f"Encontrados {len(devices)} hosts ({len(cams)} cámaras). Buscando conflictos ARP…")
    arp.refresh()
    for c in arp.conflicts():
        log.critical(c.ip, "IP CONFLICT", f"{c.old_mac} → {c.new_mac}")

    dhcp_notes = suspicious_dhcp_notes(net, [d.ip for d in cams])
    for n in dhcp_notes:
        log.warning("-", "DHCP", n)

    # monitorizar cámaras + NVR + gateway
    targets: List[Device] = []
    seen = set()
    for d in devices:
        if d.device_type in ("Camara", "NVR", "Router/AP") or d.ip == net.gateway:
            targets.append(d)
            seen.add(d.ip)
    if net.gateway and net.gateway not in seen:
        targets.append(Device(ip=net.gateway, device_type="Router/AP", hostname="gateway"))

    if not targets:
        targets = devices[:16]

    monitor = MonitorEngine(event_log=log, arp=arp)
    monitor.set_targets(targets)
    prog(f"Monitorizando {len(targets)} dispositivos durante {duration_min or '∞'} min…")
    monitor.start(interval_sec)

    try:
        if duration_min <= 0:
            while not stopped():
                time.sleep(1)
        else:
            end = time.time() + duration_min * 60
            while time.time() < end and not stopped():
                left = int(end - time.time())
                if left % 30 == 0:
                    prog(f"Monitor… quedan ~{left}s")
                time.sleep(1)
    finally:
        monitor.stop()

    # actualizar lista devices con stats
    for ip, d in monitor.devices.items():
        for i, od in enumerate(devices):
            if od.ip == ip:
                devices[i] = d
                break
        else:
            devices.append(d)

    prog("Generando informe…")
    path = generate_html_report(net, devices, log, monitor=monitor, arp=arp, dhcp_notes=dhcp_notes)
    from .report import build_conclusion

    estado, conclusion = build_conclusion(devices, arp.conflicts(), list(monitor.timeline), dhcp_notes)
    log.info("-", "REPORT", f"{path} | {estado}")
    log.close()
    return net, devices, path, f"{estado}: {conclusion}"
