"""The /api/me tenant context, POST /api/tenant switch mechanics, the
NO_TENANT gate, and the view-as tenant-intersection rule (ADR #015)."""

from __future__ import annotations

import pytest

from app.services.authz.view_as import VIEW_AS_COOKIE


@pytest.fixture()
def rian(client_factory):
    return client_factory("rian", is_super_admin=True)


@pytest.fixture()
def bob(client_factory):
    return client_factory("bob")


@pytest.fixture()
def nobody(client_factory):
    return client_factory("nobody")


# ---------------------------------------------------------------- /api/me shape


def test_me_carries_tenants_and_current(rian):
    me = rian.get("/api/me").json()
    assert [t["slug"] for t in me["tenants"]] == ["bowden-works", "plusroi"]
    assert me["tenant"] == {"slug": "bowden-works", "name": "Bowden Works"}


def test_single_tenant_user_me(bob):
    me = bob.get("/api/me").json()
    assert [t["slug"] for t in me["tenants"]] == ["plusroi"]
    assert me["tenant"]["slug"] == "plusroi"


def test_no_tenant_user_me_is_ok_with_empty_list(nobody):
    me = nobody.get("/api/me")
    assert me.status_code == 200  # /api/me is exempt from the NO_TENANT gate
    body = me.json()
    assert body["tenants"] == []
    assert body["tenant"] is None


# ---------------------------------------------------------------- NO_TENANT gate


def test_no_tenant_user_blocked_on_data_route(nobody):
    resp = nobody.get("/api/entries", params={"status": "all"})
    assert resp.status_code == 403
    assert resp.json()["error_code"] == "NO_TENANT"


# ---------------------------------------------------------------- switch cookie


def test_valid_switch_changes_current_tenant(rian):
    resp = rian.post("/api/tenant", json={"slug": "plusroi"})
    assert resp.status_code == 200
    assert resp.json()["tenant"] == {"slug": "plusroi", "name": "PlusROI"}
    assert rian.cookies.get("with_tenant") == "plusroi"
    # the switch is observable on the very next request
    me = rian.get("/api/me").json()
    assert me["tenant"]["slug"] == "plusroi"
    # ...and data now comes from PlusROI
    entries = rian.get("/api/entries", params={"status": "all"}).json()
    assert entries["total_count"] == 3  # PlusROI's 3 rows


def test_forbidden_switch_is_403(bob):
    resp = bob.post("/api/tenant", json={"slug": "bowden-works"})
    assert resp.status_code == 403
    assert resp.json()["error_code"] == "TENANT_FORBIDDEN"
    assert not bob.cookies.get("with_tenant")


def test_stale_cookie_falls_back_safely(client_factory):
    # a cookie pointing at a tenant bob can't see -> falls back to plusroi
    bob = client_factory("bob", tenant_cookie="bowden-works")
    me = bob.get("/api/me").json()
    assert me["tenant"]["slug"] == "plusroi"
    entries = bob.get("/api/entries", params={"status": "all"})
    assert entries.status_code == 200


# --------------------------------------------------- view-as tenant intersection


def test_view_as_target_with_no_shared_tenant_409s(rian):
    # nobody has zero tenants -> real∩target empty -> 409, not a silent enter.
    resp = rian.post("/api/view-as", json={"username": "nobody"})
    assert resp.status_code == 409
    assert resp.json()["error_code"] == "VIEW_AS_TENANT_MISMATCH"
    assert not rian.cookies.get(VIEW_AS_COOKIE)


def test_view_as_follows_target_tenant_not_widening(rian):
    # rian's current tenant is bowden-works; viewing as bob (PlusROI-only)
    # must move the context to PlusROI (the intersection), never widen.
    resp = rian.post("/api/view-as", json={"username": "bob"})
    assert resp.status_code == 200
    me = rian.get("/api/me").json()
    assert me["effective"]["username"] == "bob"
    assert me["tenant"]["slug"] == "plusroi"
    # and every read is now PlusROI-only, even though rian could otherwise
    # see Bowden Works.
    entries = rian.get("/api/entries", params={"status": "all"}).json()
    assert entries["total_count"] == 3


def test_view_as_same_tenant_owner_still_works(rian):
    # alice is an owner on Bowden Works (rian's current tenant) -> shared -> OK.
    resp = rian.post("/api/view-as", json={"username": "alice"})
    assert resp.status_code == 200
    me = rian.get("/api/me").json()
    assert me["effective"]["username"] == "alice"
    assert me["tenant"]["slug"] == "bowden-works"
