import socket
import subprocess
import time

from .models import ProbeResult

TIMEOUT_S = 3


def tcp_ping(host: str, port: int) -> float | None:
    """Measure TCP handshake time in ms. Returns None on failure."""
    try:
        sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        sock.settimeout(TIMEOUT_S)
        start = time.monotonic()
        sock.connect((host, port))
        elapsed_ms = (time.monotonic() - start) * 1000
        sock.close()
        return elapsed_ms
    except OSError:
        return None


def icmp_ping(host: str) -> float | None:
    """Fall back to system ping for a single probe. Returns ms or None."""
    try:
        out = subprocess.check_output(
            ["ping", "-c", "1", "-W", str(TIMEOUT_S), host],
            text=True,
            timeout=TIMEOUT_S + 1,
            stderr=subprocess.DEVNULL,
        )
        for line in out.splitlines():
            if "time=" in line:
                t = line.split("time=")[1].split()[0]
                return float(t)
    except (subprocess.SubprocessError, ValueError, IndexError):
        pass
    return None


def probe(
    host: str, label: str, count: int, *, port: int | None = None, method: str = "tcp"
) -> ProbeResult:
    """Run multiple probes against a host and return results."""
    rtts = []
    for _ in range(count):
        if method == "tcp" and port is not None:
            rtt = tcp_ping(host, port)
        else:
            rtt = icmp_ping(host)
        if rtt is not None:
            rtts.append(rtt)
        time.sleep(0.1)

    return ProbeResult(
        host=host,
        label=label,
        sent=count,
        lost=count - len(rtts),
        rtts=rtts,
    )
