from __future__ import annotations

import socket

from autosana_cli.models import Session


def is_port_available(port: int, host: str = "127.0.0.1") -> bool:
    with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock:
        sock.settimeout(0.1)
        return sock.connect_ex((host, port)) != 0


def used_ports(sessions: list[Session]) -> set[int]:
    ports: set[int] = set()
    for session in sessions:
        ports.add(session.appium_port)
        ports.add(session.aux_port)
    return ports


def allocate_port(base_port: int, *, reserved_ports: set[int] | None = None, host: str = "127.0.0.1") -> int:
    reserved = reserved_ports or set()
    port = base_port
    while port < 65535:
        if port not in reserved and is_port_available(port, host=host):
            return port
        port += 1
    raise RuntimeError(f"No free port available from {base_port}")
