"""Spousteci obal pro LiteLLM proxy.

CLI `cyberbrain service start litellm` spusti tento modul, ktery:
1) Zkontroluje, zda port neni obsazeny (kolize se starym procesem)
2) Najde config.yaml v package
3) Spusti `litellm --config <path> --port <port>` jako subprocess
4) Prepsat pidfile na PID subprocessu
"""
from __future__ import annotations

import os
import socket
import subprocess
import sys
import time
from pathlib import Path

from cyberbrain26.paths import logs_dir


def _pid_file_path() -> Path:
    d = logs_dir() / "services"
    d.mkdir(parents=True, exist_ok=True)
    return d / "litellm.pid"


def _port_pid(port: int) -> int | None:
    """Zjisti PID procesu, ktery drzi dany port (pres ss)."""
    try:
        out = subprocess.check_output(
            ["ss", "-ltnpH"], text=True, timeout=2,
        )
    except Exception:
        return None
    needle = f":{port} "
    for line in out.splitlines():
        if needle in line and "pid=" in line:
            try:
                pid_part = line.split("pid=")[1]
                pid_str = pid_part.split(",")[0]
                return int(pid_str)
            except (IndexError, ValueError):
                continue
    return None


def _port_open(host: str, p: int, timeout: float = 0.3) -> bool:
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s.settimeout(timeout)
    try:
        return s.connect_ex((host, p)) == 0
    finally:
        s.close()


def main() -> None:
    pkg_dir = Path(__file__).resolve().parent
    cfg = pkg_dir / "config.yaml"
    if not cfg.exists():
        print(f"CHYBA: config nenalezen: {cfg}", file=sys.stderr)
        sys.exit(2)

    port = int(os.environ.get("CB26_LITELLM_PORT", "4100"))

    # Detekce kolize: pokud port jiz nekdo drzi, koncime s chybou
    if _port_open("127.0.0.1", port):
        holder = _port_pid(port)
        print(
            f"CHYBA: port {port} jiz obsazen" +
            (f" (PID {holder})" if holder else "") +
            ". Zastavte stary proces (napr. `cyberbrain service stop litellm` "
            "nebo `kill <PID>`) a spustte znovu.",
            file=sys.stderr,
        )
        sys.exit(3)

    log = logs_dir() / "litellm.log"
    log.parent.mkdir(parents=True, exist_ok=True)

    python_bin = Path(sys.executable)
    litellm_cli = python_bin.parent / "litellm"
    if litellm_cli.exists():
        cmd = [str(litellm_cli),
               "--config", str(cfg), "--port", str(port), "--host", "0.0.0.0"]
    else:
        cmd = [str(python_bin), "-m", "litellm",
               "--config", str(cfg), "--port", str(port), "--host", "0.0.0.0"]

    env = os.environ.copy()
    env.pop("DATABASE_URL", None)
    env.pop("LITELLM_DATABASE_URL", None)

    print(f"LiteLLM proxy: config={cfg} port={port}")
    print(f"cmd: {' '.join(cmd)}")
    print(f"log: {log}")

    with open(log, "ab") as lf:
        proc = subprocess.Popen(
            cmd, env=env,
            stdout=lf, stderr=lf,
            start_new_session=True,
        )

    pidf = _pid_file_path()
    pidf.write_text(str(proc.pid))
    print(f"subprocess PID: {proc.pid} -> {pidf}")

    # Pockat na port - ale s kontrolou, ze proces jeste zije
    for _ in range(60):
        if proc.poll() is not None:
            print(
                f"CHYBA: subprocess {proc.pid} se ukoncil (rc={proc.returncode}). "
                f"Viz log: {log}",
                file=sys.stderr,
            )
            sys.exit(4)
        if _port_open("127.0.0.1", port):
            print(f"OK port {port} otevren")
            return
        time.sleep(0.2)

    print(f"CHYBA: port {port} se neotevrel do 12s", file=sys.stderr)
    proc.terminate()
    sys.exit(1)


if __name__ == "__main__":
    main()
