"""Phase 5B: Synthetic probes and ProbeStore (issue #308)."""

from __future__ import annotations

import tempfile
from datetime import datetime, timezone
from pathlib import Path
from unittest.mock import AsyncMock, patch

import pytest

from llmhosts.marketplace.probes import ProbeResult, ProbeStore, run_probe


def _now() -> datetime:
    return datetime.now(timezone.utc)


@pytest.mark.unit
async def test_probe_store_append_and_uptime() -> None:
    """ProbeStore appends results and get_uptime_pct returns success rate over window."""
    with tempfile.TemporaryDirectory() as tmp:
        db_path = Path(tmp) / "probes.db"
        store = ProbeStore(db_path)
        await store.initialize()

        await store.append(ProbeResult(device_id="d1", timestamp=_now(), latency_ms=10.0, success=True))
        await store.append(ProbeResult(device_id="d1", timestamp=_now(), latency_ms=20.0, success=True))
        await store.append(ProbeResult(device_id="d1", timestamp=_now(), latency_ms=30.0, success=False))

        pct = await store.get_uptime_pct("d1", days=30)
        assert pct is not None
        assert abs(pct - 66.67) < 1.0  # 2/3

        uptime_map = await store.get_uptime_map(device_ids=["d1"], days=30)
        assert "d1" in uptime_map
        await store.close()


@pytest.mark.unit
async def test_run_probe_success() -> None:
    """run_probe returns success and latency when GET /health returns 200."""
    node = {"id": "dev-1", "tunnel_url": "https://node.example.com"}
    with patch("llmhosts.marketplace.probes.httpx.AsyncClient") as mock_client_cls:
        mock_resp = AsyncMock()
        mock_resp.status_code = 200
        mock_client = AsyncMock()
        mock_client.get = AsyncMock(return_value=mock_resp)
        mock_client.__aenter__ = AsyncMock(return_value=mock_client)
        mock_client.__aexit__ = AsyncMock(return_value=None)
        mock_client_cls.return_value = mock_client

        result = await run_probe(node)

        assert result.device_id == "dev-1"
        assert result.success is True
        assert result.latency_ms >= 0


@pytest.mark.unit
async def test_run_probe_failure_no_url() -> None:
    """run_probe returns success=False when tunnel_url is missing."""
    result = await run_probe({"id": "x", "tunnel_url": ""})
    assert result.success is False
    assert result.device_id == "x"
