"""§22.9/§22.5 — GET /api/deployment + GET /api/projects/:id with visibility."""
from __future__ import annotations

from fastapi.testclient import TestClient

from test_propose_vertical import (  # noqa: F401
    app_with_fake_gitea, tmp_env, provision_user_row, sign_in_as,
)


def _add_project(pid, name, vis, typ="document"):
    # §22 three-tier: a project (grouping tier) + its default collection (the
    # per-corpus type/initial_state moved down in migration 029). The default
    # collection keys by the project id so it is globally unique in tests.
    from app import db
    db.conn().execute(
        "INSERT OR REPLACE INTO projects (id, name, content_repo, visibility) VALUES (?, ?, ?, ?)",
        (pid, name, pid, vis),
    )
    db.conn().execute(
        "INSERT OR REPLACE INTO collections (id, project_id, type, subfolder, initial_state, visibility, name) "
        "VALUES (?, ?, ?, '', 'super-draft', ?, ?)",
        (pid, pid, typ, vis, name),
    )


def test_deployment_lists_public_omits_gated_and_unlisted_for_anon(app_with_fake_gitea):
    app, _ = app_with_fake_gitea
    with TestClient(app) as client:
        _add_project("pub", "Public", "public")
        _add_project("gat", "Gated", "gated")
        _add_project("unl", "Unlisted", "unlisted")
        r = client.get("/api/deployment")
        assert r.status_code == 200
        body = r.json()
        assert body["name"] == "Test Deployment"
        ids = {p["id"] for p in body["projects"]}
        assert "pub" in ids and "default" in ids  # both public
        assert "gat" not in ids                    # gated, anon not a member
        assert "unl" not in ids                    # unlisted never enumerated


def test_projects_id_404_for_gated_non_member(app_with_fake_gitea):
    app, _ = app_with_fake_gitea
    with TestClient(app) as client:
        _add_project("gat", "Gated", "gated")
        assert client.get("/api/projects/gat").status_code == 404


def test_projects_id_returns_config_for_public(app_with_fake_gitea):
    app, _ = app_with_fake_gitea
    with TestClient(app) as client:
        from app import db
        db.conn().execute(
            "UPDATE projects SET config_json = ? WHERE id = 'default'",
            ('{"theme": {"accent": "#5b5bd6"}}',),
        )
        r = client.get("/api/projects/default")
        assert r.status_code == 200
        body = r.json()
        assert body["id"] == "default"
        assert body["type"] == "document"
        assert body["visibility"] == "public"
        assert body["theme"] == {"accent": "#5b5bd6"}


def test_projects_id_unlisted_readable_by_direct_id(app_with_fake_gitea):
    app, _ = app_with_fake_gitea
    with TestClient(app) as client:
        _add_project("unl", "Unlisted", "unlisted")
        assert client.get("/api/projects/unl").status_code == 200


def test_projects_id_unknown_returns_404_even_for_superuser(app_with_fake_gitea):
    app, _ = app_with_fake_gitea
    with TestClient(app) as client:
        provision_user_row(user_id=1, login="ben", role="owner")
        sign_in_as(client, user_id=1, gitea_login="ben", display_name="Ben", role="owner")
        assert client.get("/api/projects/does-not-exist").status_code == 404


def test_projects_id_unknown_returns_404_for_anon(app_with_fake_gitea):
    app, _ = app_with_fake_gitea
    with TestClient(app) as client:
        assert client.get("/api/projects/nope").status_code == 404


def test_deployment_includes_default_project_id(app_with_fake_gitea):
    # §22.10 / M3-frontend guard contract: the frontend learns which project
    # is the corpus-served (default) one from the deployment payload.
    app, _ = app_with_fake_gitea
    with TestClient(app) as client:
        body = client.get("/api/deployment").json()
        assert body["default_project_id"] == "default"


def test_rfc_root_url_redirects_308_to_project_scoped(app_with_fake_gitea):
    # §22.10 / §5: old corpus-root /rfc/<slug> → 308 /p/<default>/e/<slug>.
    app, _ = app_with_fake_gitea
    with TestClient(app) as client:
        r = client.get("/rfc/human", follow_redirects=False)
        assert r.status_code == 308
        assert r.headers["location"] == "/p/default/c/default/e/human"


def test_rfc_pr_url_redirects_308_to_project_scoped(app_with_fake_gitea):
    # The old per-RFC PR deep link is preserved too.
    app, _ = app_with_fake_gitea
    with TestClient(app) as client:
        r = client.get("/rfc/human/pr/7", follow_redirects=False)
        assert r.status_code == 308
        assert r.headers["location"] == "/p/default/c/default/e/human/pr/7"


def test_proposals_root_url_redirects_308_to_project_scoped(app_with_fake_gitea):
    app, _ = app_with_fake_gitea
    with TestClient(app) as client:
        r = client.get("/proposals/42", follow_redirects=False)
        assert r.status_code == 308
        assert r.headers["location"] == "/p/default/c/default/proposals/42"


def test_gated_project_visible_and_readable_to_member(app_with_fake_gitea):
    from app import db
    app, _ = app_with_fake_gitea
    with TestClient(app) as client:
        _add_project("teamx", "Team X", "gated")
        provision_user_row(user_id=5, login="mia", role="contributor")
        db.conn().execute(
            "INSERT INTO memberships (scope_type, scope_id, user_id, role) VALUES ('collection', 'teamx', 5, 'contributor')"
        )
        sign_in_as(client, user_id=5, gitea_login="mia", display_name="Mia", role="contributor")
        # member sees the gated project in the deployment directory
        ids = {p["id"] for p in client.get("/api/deployment").json()["projects"]}
        assert "teamx" in ids
        # member can read it directly
        r = client.get("/api/projects/teamx")
        assert r.status_code == 200
        assert r.json()["id"] == "teamx"
