"""Serve suite — start server, verify health and model discovery."""

from __future__ import annotations

import asyncio
from typing import TYPE_CHECKING

from tests.remote.suites.base import BaseSuite, StepStatus, SuiteResult

if TYPE_CHECKING:
    from tests.remote.runner import BackgroundProcess, RemoteTestRunner

# Default server port
SERVER_PORT = 4000
HEALTH_URL = f"http://localhost:{SERVER_PORT}/health"
MODELS_URL = f"http://localhost:{SERVER_PORT}/v1/models"


class ServeSuite(BaseSuite):
    name = "serve"
    description = "Start llmhosts serve, verify health check and model discovery"

    async def execute(self, runner: RemoteTestRunner, result: SuiteResult) -> None:
        proc: BackgroundProcess | None = None

        try:
            # Step 1: Start server in background
            proc = await runner.run_background("llmhosts serve --no-tui")
            self._add_step(
                result,
                "start_server",
                f"Start llmhosts serve --no-tui (PID={proc.pid})",
                status=StepStatus.PASSED if proc.pid else StepStatus.FAILED,
                error_message="" if proc.pid else "Failed to get server PID",
            )

            if not proc.pid:
                return

            # Step 2: Wait for health check (poll up to 30s)
            healthy = False
            health_output = ""
            polls = 0
            for _ in range(15):
                polls += 1
                await asyncio.sleep(2)
                curl_cmd = self._curl_cmd(runner, HEALTH_URL)
                r = await runner.run_command(curl_cmd, timeout=10.0)
                if r.success and ("ok" in r.stdout.lower() or "healthy" in r.stdout.lower()):
                    healthy = True
                    health_output = r.stdout
                    break

            elapsed = polls * 2
            self._add_step(
                result,
                "health_check",
                "Wait for /health to respond OK",
                status=StepStatus.PASSED if healthy else StepStatus.FAILED,
                stdout=health_output,
                duration_s=float(elapsed),
                error_message="" if healthy else f"Health check failed after {elapsed}s",
            )

            if not healthy:
                return

            # Step 3: Check model discovery
            curl_cmd = self._curl_cmd(runner, MODELS_URL)
            r = await runner.run_command(curl_cmd, timeout=15.0)
            has_models = r.success and ("data" in r.stdout or "models" in r.stdout.lower())

            self._add_step(
                result,
                "model_discovery",
                "Check /v1/models returns model list",
                status=StepStatus.PASSED if has_models else StepStatus.FAILED,
                stdout=r.stdout[:1000],  # Truncate large model lists
                stderr=r.stderr,
                duration_s=r.duration_s,
                error_message="" if has_models else "No models found in /v1/models response",
            )

        finally:
            # Step 4: Stop server
            if proc is not None:
                stop_result = await runner.stop_background(proc)
                self._add_step(
                    result,
                    "stop_server",
                    "Stop llmhosts serve",
                    status=StepStatus.PASSED if stop_result.exit_code >= 0 else StepStatus.FAILED,
                    duration_s=stop_result.duration_s,
                )

    @staticmethod
    def _curl_cmd(runner: RemoteTestRunner, url: str) -> str:
        """Build a curl/Invoke-WebRequest command appropriate for the shell."""
        if runner.device.shell == "powershell":
            return f'(Invoke-WebRequest -Uri "{url}" -UseBasicParsing -TimeoutSec 5).Content'
        return f"curl -sf --connect-timeout 5 {url}"
