"""Boundary tests for workspace-state routes (Law 11 — test the boundary).

Tests the HTTP contract end-to-end via FastAPI's TestClient. Each test
exercises ONE behavioral invariant.
"""
from __future__ import annotations

import json
from pathlib import Path

import pytest
from fastapi.testclient import TestClient

# Redirect DB to tmp BEFORE importing the app (db.py does init on import).
@pytest.fixture(scope="session", autouse=True)
def _tmp_db(tmp_path_factory: pytest.TempPathFactory) -> Path:
    tmp = tmp_path_factory.mktemp("recoil_db") / "test.db"
    import recoil.api.db as db_mod
    db_mod.DB_PATH = tmp
    db_mod.init_db()
    return tmp


@pytest.fixture
def client() -> TestClient:
    from recoil.api.main import app
    return TestClient(app)


WS_ID = "550e8400-e29b-41d4-a716-446655440000"
PAYLOAD = json.dumps({
    "schemaVersion": 1,
    "columns": {"nav": 240, "chat": 380},
    "parked": [],
    "tweaks": {"density": "normal"},
})


def test_health(client: TestClient) -> None:
    r = client.get("/api/health")
    assert r.status_code == 200
    assert r.json() == {"ok": True}


def test_read_missing_returns_404(client: TestClient) -> None:
    r = client.get(f"/api/workspace-state/{WS_ID}")
    assert r.status_code == 404


def test_write_then_read(client: TestClient) -> None:
    w = client.post(
        f"/api/workspace-state/{WS_ID}",
        json={"schema_version": 2, "payload_json": PAYLOAD},
    )
    assert w.status_code == 200
    body = w.json()
    assert body["workspace_id"] == WS_ID
    assert body["schema_version"] == 2
    assert json.loads(body["payload_json"]) == json.loads(PAYLOAD)

    r = client.get(f"/api/workspace-state/{WS_ID}")
    assert r.status_code == 200
    assert json.loads(r.json()["payload_json"]) == json.loads(PAYLOAD)


def test_write_overwrites(client: TestClient) -> None:
    payload2 = json.dumps({"schemaVersion": 2, "columns": {"nav": 300, "chat": 400}})
    client.post(
        f"/api/workspace-state/{WS_ID}",
        json={"schema_version": 2, "payload_json": payload2},
    )
    r = client.get(f"/api/workspace-state/{WS_ID}")
    assert json.loads(r.json()["payload_json"])["columns"]["nav"] == 300


def test_delete(client: TestClient) -> None:
    client.post(
        f"/api/workspace-state/{WS_ID}",
        json={"schema_version": 2, "payload_json": PAYLOAD},
    )
    d = client.delete(f"/api/workspace-state/{WS_ID}")
    assert d.status_code == 204
    r = client.get(f"/api/workspace-state/{WS_ID}")
    assert r.status_code == 404


def test_delete_missing_returns_404(client: TestClient) -> None:
    r = client.delete(f"/api/workspace-state/{WS_ID}")
    assert r.status_code == 404


def test_invalid_workspace_id_rejected(client: TestClient) -> None:
    r = client.get("/api/workspace-state/not-a-uuid")
    assert r.status_code == 400


def test_invalid_payload_json_rejected(client: TestClient) -> None:
    r = client.post(
        f"/api/workspace-state/{WS_ID}",
        json={"schema_version": 2, "payload_json": "{not json"},
    )
    assert r.status_code == 400


def test_envelope_version_mismatch_rejected(client: TestClient) -> None:
    r = client.post(
        f"/api/workspace-state/{WS_ID}",
        json={"schema_version": 99, "payload_json": "{}"},
    )
    assert r.status_code == 409
