# src/proxym/api/vscode_api.py
"""
REST endpoints dla VS Code Web (brakujące, wymagane przez voice.jsx):
  GET  /api/v1/vscode/status  → { running, port, url }
  POST /api/v1/vscode/start   → { running, url }
  POST /api/v1/vscode/stop    → { stopped }
  POST /api/v1/vscode/restart → { running, url }
  GET  /api/v1/vscode/logs    → { lines: [...] }
  POST /api/v1/vscode/build   → { building }

Używa docker compose przez subprocess (CLI vscode.py jako wzorzec).
"""

from __future__ import annotations

import subprocess
import time
from pathlib import Path

import httpx
import structlog
from fastapi import APIRouter, HTTPException
from fastapi.responses import JSONResponse

from proxym.config import get_settings

log = structlog.get_logger()
router = APIRouter(prefix="/api/v1/vscode", tags=["vscode"])

# ── Helpers ───────────────────────────────────────────────────────────────────

def _compose_dir() -> Path:
    """Znajdź katalog z docker-compose.yml."""
    for candidate in [
        Path.cwd(),
        Path.cwd().parent,
        Path(__file__).parent.parent.parent.parent,
        Path("/app"),
    ]:
        if (candidate / "docker-compose.yml").exists():
            return candidate
    raise FileNotFoundError("docker-compose.yml nie znaleziony")


def _run_compose(*args, timeout: int = 60) -> tuple[int, str, str]:
    """Uruchom docker compose z podanymi argumentami."""
    try:
        d = _compose_dir()
        result = subprocess.run(
            ["docker", "compose", *args],
            cwd=d,
            capture_output=True,
            text=True,
            timeout=timeout,
        )
        return result.returncode, result.stdout, result.stderr
    except FileNotFoundError:
        return 1, "", "docker compose nie znaleziony"
    except subprocess.TimeoutExpired:
        return 1, "", "timeout"
    except Exception as e:
        return 1, "", str(e)


def _is_vscode_running() -> bool:
    """Sprawdź czy kontener VS Code działa."""
    rc, out, _ = _run_compose("ps", "--services", "--filter", "status=running")
    return rc == 0 and "vscode" in out


def _get_vscode_port() -> int:
    """Pobierz port VS Code z ustawień lub domyślny."""
    try:
        return int(get_settings().vscode_port)
    except Exception:
        return 8080


def _wait_for_vscode(port: int, max_wait: int = 30) -> bool:
    """Czekaj aż VS Code będzie gotowy do obsługi HTTP."""
    deadline = time.monotonic() + max_wait
    while time.monotonic() < deadline:
        try:
            r = httpx.get(f"http://localhost:{port}", timeout=1.0)
            if r.status_code < 500:
                return True
        except Exception:
            pass
        time.sleep(1)
    return False


# ── Endpoints ─────────────────────────────────────────────────────────────────

@router.get("/status")
async def vscode_status():
    """
    Status usługi VS Code Web.

    Returns:
        { running: bool, port: int, url: str | null, container: str }
    """
    running = _is_vscode_running()
    port = _get_vscode_port()
    url = f"http://localhost:{port}" if running else None

    return JSONResponse({
        "running":   running,
        "port":      port,
        "url":       url,
        "container": "proxym-vscode",
    })


@router.post("/start")
async def vscode_start():
    """
    Uruchom usługę VS Code Web przez docker compose.

    Returns:
        { running: true, url: str, message: str }
    """
    if _is_vscode_running():
        port = _get_vscode_port()
        return JSONResponse({
            "running": True,
            "url":     f"http://localhost:{port}",
            "message": "VS Code już działa.",
        })

    log.info("Starting VS Code Web via docker compose")
    rc, out, err = _run_compose("up", "-d", "vscode", timeout=120)

    if rc != 0:
        log.error("vscode start failed", stderr=err)
        raise HTTPException(500, f"docker compose up vscode failed: {err}")

    port = _get_vscode_port()
    ready = _wait_for_vscode(port, max_wait=45)

    return JSONResponse({
        "running": ready,
        "url":     f"http://localhost:{port}" if ready else None,
        "message": "VS Code uruchomiony." if ready else "VS Code startuje (może chwilę potrwać).",
    })


@router.post("/stop")
async def vscode_stop():
    """
    Zatrzymaj usługę VS Code Web.

    Returns:
        { stopped: true, message: str }
    """
    if not _is_vscode_running():
        return JSONResponse({"stopped": True, "message": "VS Code już był zatrzymany."})

    rc, out, err = _run_compose("stop", "vscode", timeout=30)
    if rc != 0:
        raise HTTPException(500, f"docker compose stop vscode failed: {err}")

    return JSONResponse({"stopped": True, "message": "VS Code zatrzymany."})


@router.post("/restart")
async def vscode_restart():
    """Restart VS Code Web."""
    rc, _, err = _run_compose("restart", "vscode", timeout=60)
    if rc != 0:
        raise HTTPException(500, f"restart failed: {err}")

    port = _get_vscode_port()
    ready = _wait_for_vscode(port, max_wait=30)

    return JSONResponse({
        "running": ready,
        "url":     f"http://localhost:{port}" if ready else None,
        "message": "VS Code zrestartowany.",
    })


@router.get("/logs")
async def vscode_logs(lines: int = 50):
    """
    Pobierz ostatnie logi kontenera VS Code.

    Returns:
        { lines: [str], container: str }
    """
    rc, out, err = _run_compose(
        "logs", "--tail", str(lines), "--no-color", "vscode",
        timeout=15,
    )
    if rc != 0:
        return JSONResponse({"lines": [f"Błąd: {err}"], "container": "proxym-vscode"})

    return JSONResponse({
        "lines":     out.splitlines(),
        "container": "proxym-vscode",
    })


@router.post("/build")
async def vscode_build():
    """
    Przebuduj obraz VS Code (po zmianie rozszerzeń/konfiguracji).
    Operacja długotrwała — zwraca natychmiast, build w tle.

    Returns:
        { building: true, message: str }
    """
    import asyncio

    async def _build():
        rc, out, err = _run_compose("build", "--no-cache", "vscode", timeout=600)
        if rc == 0:
            log.info("vscode build completed")
        else:
            log.error("vscode build failed", stderr=err)

    asyncio.create_task(_build())

    return JSONResponse({
        "building": True,
        "message":  "Build VS Code uruchomiony w tle. Sprawdź logi: proxym vscode logs",
    })
