"""Tests for /api/v1/preferences/dashboard-layout endpoints."""

import pytest

from ledgrab.config import get_config


@pytest.fixture(scope="module")
def client():
    """TestClient with auth header read at fixture-build time.

    The auth API key is resolved here (not at module import) so any
    config-singleton mutation that happens during pytest collection —
    notably ``server/tests/e2e/conftest.py`` reassigning the global
    config to a different test key during collection of e2e tests —
    cannot leave us holding a stale Bearer header that yields 401.
    """
    from fastapi.testclient import TestClient

    from ledgrab.main import app

    api_key = next(iter(get_config().auth.api_keys.values()), "")
    with TestClient(app, raise_server_exceptions=False) as c:
        if api_key:
            c.headers["Authorization"] = f"Bearer {api_key}"
        yield c


def _minimal_layout() -> dict:
    return {
        "version": 1,
        "sections": [
            {
                "key": "perf",
                "visible": True,
                "collapsedDefault": False,
                "density": "comfortable",
                "options": {},
            },
        ],
        "perfCells": [
            {
                "key": "cpu",
                "visible": True,
                "mode": "inherit",
                "span": 1,
                "window": 120,
                "yScale": "auto",
                "precision": 1,
                "showSubtitle": True,
                "showRefLine": True,
            },
        ],
        "global": {
            "width": "full",
            "accent": "target",
            "animations": "full",
            "emptyState": "hide",
            "toolbarPosition": "top",
            "autoCollapseRunningEmpty": False,
            "showTutorial": True,
            "perfMode": "both",
            "pollMs": 1000,
        },
    }


def test_get_dashboard_layout_default_empty(client):
    """When no layout has been saved, GET returns an empty object."""
    # Clear first so this test is order-independent.
    client.delete("/api/v1/preferences/dashboard-layout")
    resp = client.get("/api/v1/preferences/dashboard-layout")
    assert resp.status_code == 200
    assert resp.json() == {}


def test_put_then_get_dashboard_layout(client):
    """PUT a layout, GET it back unchanged."""
    layout = _minimal_layout()
    put = client.put("/api/v1/preferences/dashboard-layout", json=layout)
    assert put.status_code == 200
    assert put.json() == {"ok": True}

    got = client.get("/api/v1/preferences/dashboard-layout")
    assert got.status_code == 200
    body = got.json()
    assert body["version"] == 1
    assert body["sections"][0]["key"] == "perf"
    assert body["perfCells"][0]["key"] == "cpu"
    assert body["global"]["perfMode"] == "both"


def test_put_rejects_missing_version(client):
    """Body without numeric version field is rejected with 422."""
    bad = {"sections": []}
    resp = client.put("/api/v1/preferences/dashboard-layout", json=bad)
    assert resp.status_code == 422


def test_put_rejects_non_object(client):
    """Bare arrays / strings / numbers are rejected by FastAPI body validation."""
    resp = client.put(
        "/api/v1/preferences/dashboard-layout",
        json=["not", "an", "object"],
    )
    assert resp.status_code in (400, 422)


def test_delete_clears_layout(client):
    """DELETE wipes the saved layout so subsequent GET returns empty."""
    client.put("/api/v1/preferences/dashboard-layout", json=_minimal_layout())
    deleted = client.delete("/api/v1/preferences/dashboard-layout")
    assert deleted.status_code == 200
    after = client.get("/api/v1/preferences/dashboard-layout")
    assert after.status_code == 200
    assert after.json() == {}


def test_layout_round_trip_preserves_unknown_fields(client):
    """Frontend may add new keys (e.g. v1.1 sections) — backend must
    pass them through verbatim, not strip them."""
    layout = _minimal_layout()
    layout["futureField"] = {"foo": "bar"}
    layout["sections"].append(
        {
            "key": "audio-meters",
            "visible": True,
            "collapsedDefault": False,
            "density": "comfortable",
            "options": {"sensitivity": 0.7},
        }
    )
    client.put("/api/v1/preferences/dashboard-layout", json=layout)
    got = client.get("/api/v1/preferences/dashboard-layout").json()
    assert got["futureField"] == {"foo": "bar"}
    assert any(s["key"] == "audio-meters" for s in got["sections"])
