"""Ayudas para las pruebas y para check_lab.py: levantar topologías y correr comandos."""
import os
import subprocess
import time

HERE = os.path.dirname(os.path.abspath(__file__))


def run(args, check=True, timeout=180, stdin=None):
    return subprocess.run(args, check=check, timeout=timeout, text=True, stdin=stdin,
                          stdout=subprocess.PIPE, stderr=subprocess.STDOUT, cwd=HERE)


def deploy(topo):
    run(["containerlab", "deploy", "-t", f"topo/{topo}.clab.yml", "--reconfigure"], timeout=300)


def destroy(topo):
    run(["containerlab", "destroy", "-t", f"topo/{topo}.clab.yml", "--cleanup"], check=False,
        timeout=300)
    run(["docker", "network", "rm", f"redes-w03-{topo}"], check=False)


class Lab:
    """Una topología ya levantada: lab.sh("h1", "ping ...") corre un comando en un nodo."""

    def __init__(self, topo):
        self.prefix = f"clab-w03-{topo}-"

    def sh(self, node, command, check=False, timeout=60):
        return run(["docker", "exec", self.prefix + node, "sh", "-c", command], check=check,
                   timeout=timeout)

    def out(self, node, command):
        return self.sh(node, command).stdout

    def ping(self, node, target, count=1):
        """True si llega al menos una respuesta."""
        return self.sh(node, f"ping -c {count} -W 1 {target}").returncode == 0

    def apply_script(self, node, path):
        """Corre un script del laboratorio en el nodo, como se hace a mano con sh < script."""
        with open(os.path.join(HERE, path), encoding="utf-8") as script:
            done = run(["docker", "exec", "-i", self.prefix + node, "sh", "-e"], stdin=script,
                       check=False)
        if done.returncode != 0:
            raise RuntimeError(f"{path} falló en {node}:\n{done.stdout}")

    def capture(self, node, iface, action, bpf="", wait=0.5):
        """Captura en node:iface mientras corre action(); devuelve las líneas de tcpdump -e."""
        pcap = "/tmp/w03.pcap"
        self.sh(node, f"rm -f {pcap}")
        run(["docker", "exec", "-d", self.prefix + node, "sh", "-c",
             f"tcpdump -U -n -i {iface} -w {pcap} {bpf} 2>/dev/null"])
        for _ in range(50):
            if self.sh(node, f"test -s {pcap}").returncode == 0:
                break
            time.sleep(0.1)
        time.sleep(wait)
        try:
            action()
            time.sleep(wait)
        finally:
            self.sh(node, "pkill tcpdump")
            time.sleep(0.2)
        text = self.out(node, f"tcpdump -e -n -r {pcap} 2>/dev/null")
        return [line for line in text.splitlines() if line.strip()]
