"""Levels CRUD through the admin API.

Levels are editable data owned by the app: the owner (and any level carrying the
right permission) can create/adopt/edit/delete them, duplicates and in-use deletes
are refused with stable codes, and the immutable super-admin (the owner) cannot be
re-levelled. A plain member holds none of these powers.
"""

from tests.conftest import as_user


def _code(resp):
    body = resp.json()
    d = body.get("detail")
    return d.get("error_code") if isinstance(d, dict) else body.get("error_code")


def _level_names(client):
    r = client.get("/api/bw/levels")
    assert r.status_code == 200
    return [lvl["name"] for lvl in r.json()["levels"]]


def test_list_levels_shows_seed_levels(client):
    as_user(client, "rian")
    names = _level_names(client)
    assert "admin" in names and "member" in names


def test_owner_creates_a_level(client):
    as_user(client, "rian")
    r = client.post("/api/bw/levels",
                    json={"name": "editor", "permissions": ["accounts.view"],
                          "assignable": []})
    assert r.status_code == 200
    assert r.json()["success"] is True
    assert "editor" in _level_names(client)


def test_duplicate_level_name_conflicts(client):
    as_user(client, "rian")
    r = client.post("/api/bw/levels", json={"name": "admin", "permissions": []})
    assert r.status_code == 409
    assert _code(r) == "EXISTS"


def test_member_cannot_create_a_level(client, kit):
    kit.member("bob", "member")
    as_user(client, "bob")
    r = client.post("/api/bw/levels", json={"name": "sneaky", "permissions": []})
    assert r.status_code == 403
    assert _code(r) == "FORBIDDEN"
    # ...and nothing was created.
    as_user(client, "rian")
    assert "sneaky" not in _level_names(client)


def test_owner_adopts_a_template(client):
    as_user(client, "rian")
    r = client.post("/api/bw/levels/adopt", json={"name": "manager"})
    assert r.status_code == 200
    assert r.json()["success"] is True
    assert "manager" in _level_names(client)


def test_owner_edits_a_level_permissions(client):
    as_user(client, "rian")
    client.post("/api/bw/levels", json={"name": "editor", "permissions": []})
    r = client.patch("/api/bw/levels/editor",
                     json={"permissions": ["accounts.view", "accounts.add"]})
    assert r.status_code == 200
    r = client.get("/api/bw/levels")
    editor = next(lvl for lvl in r.json()["levels"] if lvl["name"] == "editor")
    assert set(editor["permissions"]) == {"accounts.view", "accounts.add"}


def test_owner_deletes_an_unused_level(client):
    as_user(client, "rian")
    client.post("/api/bw/levels", json={"name": "junk", "permissions": []})
    assert "junk" in _level_names(client)
    r = client.delete("/api/bw/levels/junk")
    assert r.status_code == 200
    assert "junk" not in _level_names(client)


def test_in_use_level_cannot_be_deleted(client, kit):
    """A level held by a member is in use — deleting it is refused (EXISTS)."""
    kit.member("carol", "member")
    as_user(client, "rian")
    r = client.delete("/api/bw/levels/member")
    assert r.status_code == 409
    assert _code(r) == "EXISTS"


def test_owner_is_immutable_even_to_the_owner(client):
    """The super admin is code, not a row: even the owner cannot re-level the owner."""
    as_user(client, "rian")
    r = client.post("/api/bw/accounts/rian/level", json={"level": "member"})
    assert r.status_code == 403
    assert _code(r) == "OWNER_IMMUTABLE"
