"""GPU integration tests — require a live edge agent with real GPU.

These tests are skipped by default. Enable with:
  pytest --run-gpu
  # or
  RADIX_GPU_TESTS=1 pytest

The tests connect to a running edge agent at RADIX_AGENT_URL (default: http://localhost:8080).
"""

import json
import os
import time

import pytest
import requests

pytestmark = pytest.mark.gpu

AGENT_URL = os.environ.get("RADIX_AGENT_URL", "http://localhost:8080")
JOB_TIMEOUT = 120  # seconds


@pytest.fixture(scope="module")
def agent_url():
    """Return the agent base URL and verify it's reachable."""
    try:
        resp = requests.get(f"{AGENT_URL}/healthz", timeout=5)
        resp.raise_for_status()
    except Exception as e:
        pytest.skip(f"Edge agent not reachable at {AGENT_URL}: {e}")
    return AGENT_URL


def test_healthz_returns_200(agent_url):
    resp = requests.get(f"{agent_url}/healthz", timeout=5)
    assert resp.status_code == 200
    data = resp.json()
    assert data.get("status") == "ok"


def test_readyz_returns_200(agent_url):
    resp = requests.get(f"{agent_url}/readyz", timeout=5)
    assert resp.status_code == 200


def test_gpus_detected(agent_url):
    """At least one GPU should be detected."""
    resp = requests.get(f"{agent_url}/v1/gpus", timeout=5)
    assert resp.status_code == 200
    gpus = resp.json()
    assert isinstance(gpus, list)
    assert len(gpus) >= 1, "No GPUs detected"

    gpu = gpus[0]
    assert gpu.get("name"), "GPU name missing"
    assert gpu.get("memory_total_mib", 0) > 0, "GPU memory not reported"


def test_gpu_utilization_values(agent_url):
    """GPU utilization should be numeric between 0-100."""
    # Wait a couple observer cycles
    time.sleep(6)
    resp = requests.get(f"{agent_url}/v1/gpus", timeout=5)
    assert resp.status_code == 200
    gpus = resp.json()
    assert len(gpus) >= 1

    gpu = gpus[0]
    util = gpu.get("utilization_pct")
    assert util is not None, "utilization_pct missing"
    assert 0 <= util <= 100, f"utilization_pct out of range: {util}"


def test_submit_nvidia_smi_job(agent_url):
    """Submit an nvidia-smi job and verify it completes successfully."""
    payload = {
        "image": "nvidia/cuda:12.4.1-runtime-ubuntu22.04",
        "command": ["nvidia-smi"],
        "num_gpus": 1,
        "user_id": "integration-test",
        "job_type": "smoke",
    }

    # Submit
    resp = requests.post(f"{agent_url}/v1/jobs", json=payload, timeout=10)
    assert resp.status_code == 200, f"Submit failed: {resp.text}"
    job_id = resp.json()["job_id"]

    # Poll until terminal
    start = time.time()
    while time.time() - start < JOB_TIMEOUT:
        resp = requests.get(f"{agent_url}/v1/jobs/{job_id}", timeout=5)
        assert resp.status_code == 200
        job = resp.json()
        status = job["status"]
        if status in ("succeeded", "failed", "cancelled"):
            break
        time.sleep(3)
    else:
        pytest.fail(f"Job {job_id} did not complete within {JOB_TIMEOUT}s (status: {status})")

    assert status == "succeeded", f"Job failed: {job.get('error_message')}"
    assert job.get("exit_code") == 0

    # Output should contain GPU info
    stdout_tail = job.get("stdout_tail", "")
    assert any(kw in stdout_tail for kw in ("NVIDIA", "GPU", "CUDA")), \
        f"nvidia-smi output missing GPU info: {stdout_tail[:200]}"


def test_metrics_include_gpu_data(agent_url):
    resp = requests.get(f"{agent_url}/metrics", timeout=5)
    assert resp.status_code == 200
    body = resp.text
    assert "radix_" in body, "No radix_ metrics found"


def test_jobs_list(agent_url):
    """GET /v1/jobs should return a list."""
    resp = requests.get(f"{agent_url}/v1/jobs", timeout=5)
    assert resp.status_code == 200
    jobs = resp.json()
    assert isinstance(jobs, list)
