"""/api/entries|summary|projects contract tests over the migrated
fixture graph: DTO money-shaping per capability (T-PRM-05, T-PRJ-023),
pagination/sort plumbing, options cascading, structured errors."""


def test_entries_defaults_and_shape(as_rian):
    """The API default is status=all; the /entries PAGE default of
    'pending' lives in the frontend URL state (vitest suite)."""
    body = as_rian.get("/api/entries", params={"status": "all"}).json()
    assert {"rows", "total_count", "page", "page_size", "total_pages"} <= set(body)
    assert body["total_count"] == 7
    assert body["page_size"] == 100
    row = body["rows"][0]
    assert {"id", "start_at", "worker", "operator", "client", "project",
            "description", "duration_seconds", "cost", "billout", "status",
            "locked", "blocked_reason"} <= set(row)


def test_entries_manager_scoped_and_no_billout(as_adi):
    body = as_adi.get("/api/entries", params={"status": "all"}).json()
    assert body["total_count"] == 4  # only adi's batch
    for row in body["rows"]:
        assert "billout" not in row
        assert "cost" in row


def test_entries_totals_shaping(as_rian, as_adi):
    owner = as_rian.get("/api/entries/totals", params={"status": "all"}).json()
    assert owner["row_count"] == 7
    assert owner["billout"]["currency"] == "CAD"
    manager = as_adi.get("/api/entries/totals", params={"status": "all"}).json()
    assert manager["row_count"] == 4
    assert "billout" not in manager


def test_entries_options_cascade_and_importers(as_rian, as_adi):
    owner = as_rian.get("/api/entries/options", params={"status": "all"}).json()
    assert owner["operators"] == ["Bowden Works", "PlusROI"]
    assert len(owner["batches"]) == 3
    assert {imp["label"] for imp in owner["importers"]} == {"rian", "adi"}
    # cascading: filtering to operator=PlusROI narrows the client list
    narrowed = as_rian.get(
        "/api/entries/options", params={"status": "all", "operator": "PlusROI"}
    ).json()
    assert "PlusROI" not in narrowed["clients"]  # the BW-operated client
    assert "Brentwood" in narrowed["clients"]
    # importer options are owner-only
    manager = as_adi.get("/api/entries/options", params={"status": "all"}).json()
    assert manager["importers"] == []
    assert len(manager["batches"]) == 3  # batch METADATA stays tenant-visible


def test_entries_bad_filter_is_structured_422(as_rian):
    resp = as_rian.get("/api/entries", params={"batch": "not-a-uuid"})
    assert resp.status_code == 422
    body = resp.json()
    assert body["error_code"] == "BAD_FILTER_VALUE"
    assert "summary" in body and "detail" in body


def test_summary_shaping(as_rian, as_adi):
    owner = as_rian.get("/api/summary", params={"month": "2026-3"}).json()
    assert owner["month"]["this"] == {"year": 2026, "month": 3}
    assert owner["month"]["prev"] == {"year": 2026, "month": 2}
    site = next(r for r in owner["rows"] if r["project"] == "Site Rebuild")
    assert site["this_billout_adjusted"]["amount"] == "307.75"
    manager = as_adi.get("/api/summary", params={"month": "2026-3"}).json()
    assert all("this_billout" not in r for r in manager["rows"])
    assert "this_billout" not in manager["totals"]


def test_projects_shaping(as_rian, as_adi):
    owner = as_rian.get("/api/projects", params={"status": "all"}).json()
    site = next(r for r in owner["rows"] if r["project"] == "Site Rebuild")
    assert site["income"]["amount"] == "12000.00"
    assert site["margin"]["amount"] == "11926.50"
    manager = as_adi.get("/api/projects", params={"status": "all"}).json()
    for row in manager["rows"]:
        assert "income" not in row and "margin" not in row and "billout" not in row


def test_projects_descriptions_by_id_and_unassigned(as_rian):
    projects = as_rian.get("/api/projects", params={"status": "all"}).json()["rows"]
    site = next(r for r in projects if r["project"] == "Site Rebuild")
    rows = as_rian.get(
        f"/api/projects/{site['project_id']}/descriptions", params={"status": "all"}
    ).json()["rows"]
    assert sum(r["row_count"] for r in rows) == site["row_count"]

    unassigned = as_rian.get(
        "/api/projects/unassigned/descriptions",
        params={"status": "all", "raw_operator": "PlusROI", "raw_project": "Mystery"},
    ).json()["rows"]
    assert [r["description"] for r in unassigned] == ["who did this"]

    bad = as_rian.get("/api/projects/nonsense/descriptions")
    assert bad.status_code == 422
    assert bad.json()["error_code"] == "BAD_GROUP"


def test_me_capabilities_and_candidates(as_rian, as_adi):
    me = as_rian.get("/api/me").json()
    assert me["username"] == "rian" and me["is_super_admin"] is True
    assert me["capabilities"]["can_transfer"] is True
    assert me["capabilities"]["can_enter_view_as"] is True
    assert me["view_as"] == {"active": False, "label": None}
    assert {c["username"] for c in me["view_as_candidates"]} == {"adi"}
    assert me["effective"]["role"] == "owner"

    adi_me = as_adi.get("/api/me").json()
    assert adi_me["capabilities"] == {
        "can_transfer": False,
        "can_see_income": False,
        "can_manage_imports": True,
        "can_manage_team": False,
        "can_enter_view_as": False,
    }
    assert adi_me["view_as_candidates"] == []
    assert adi_me["effective"]["role"] == "manager"
