"""INDL-59 (follow-up) — Plan-based feature gating for the Memorials,
Reports, News, and Pages admin-portal modules.

Per stakeholder direction, the Starter-plan sidebar shows ONLY: Dashboard,
Cemetery Map, Records, Billing, Settings, Support. Memorials, Reports, News,
and Pages are hidden for Starter and must also 403 server-side — mirroring
the existing Sales/Scheduling gate pattern (require_feature router
dependency) rather than relying on the hidden sidebar item alone.

Note: this does NOT touch the public-facing memorial page or public news
display — those live under separate `/api/public/*` routers, untouched by
this gate. Only the tenant-admin management routers
(`/api/v1/memorials`, `/api/v1/reports`, `/api/v1/news`, `/api/v1/pages`)
are gated here.
"""
from uuid import uuid4

import pytest
from httpx import AsyncClient
from sqlalchemy.ext.asyncio import AsyncSession

from src.apps.auth.models.user import User
from src.apps.tenants.models.account import Account
from src.core.security import build_token_payload, create_access_token, hash_password

MODULE_URLS = {
    "memorials": "/api/v1/memorials",
    "reports": "/api/v1/reports/capacity",
    "news": "/api/v1/news",
    "pages": "/api/v1/pages/global",
}


async def _make_account(db: AsyncSession, *, plan: str) -> Account:
    uid = uuid4().hex[:8]
    acc = Account(
        organization_name=f"Plan Gate Cemetery {uid}",
        subdomain=f"plangate-mod-{uid}",
        contact_email=f"admin-{uid}@plangate.test",
        plan=plan,
        status="active",
    )
    db.add(acc)
    await db.flush()
    return acc


async def _make_admin_token(db: AsyncSession, account: Account) -> str:
    user = User(
        tenant_id=account.id,
        email=f"admin-{uuid4().hex[:6]}@plangate.test",
        password_hash=hash_password("Test1234!"),
        first_name="Admin",
        last_name="User",
        role="administrator",
        status="active",
    )
    db.add(user)
    await db.flush()
    return create_access_token(build_token_payload(user, account))


def _headers(token: str, account: Account) -> dict:
    return {"Authorization": f"Bearer {token}", "X-Tenant-ID": str(account.id)}


@pytest.mark.asyncio
@pytest.mark.parametrize("module,url", list(MODULE_URLS.items()))
async def test_starter_tenant_is_403_on_gated_admin_modules(
    client: AsyncClient, db_session: AsyncSession, module: str, url: str
):
    acc = await _make_account(db_session, plan="starter")
    token = await _make_admin_token(db_session, acc)

    resp = await client.get(url, headers=_headers(token, acc))

    assert resp.status_code == 403, f"{module} ({url}) should 403 for Starter, got {resp.status_code}"
    assert "Professional and Enterprise" in resp.json()["message"]


@pytest.mark.asyncio
@pytest.mark.parametrize("plan", ["professional", "enterprise"])
@pytest.mark.parametrize("module,url", list(MODULE_URLS.items()))
async def test_paid_plans_pass_admin_module_plan_gate(
    client: AsyncClient, db_session: AsyncSession, module: str, url: str, plan: str
):
    acc = await _make_account(db_session, plan=plan)
    token = await _make_admin_token(db_session, acc)

    resp = await client.get(url, headers=_headers(token, acc))

    assert resp.status_code == 200, f"{module} ({url}) should pass the gate for {plan}, got {resp.status_code}"


@pytest.mark.asyncio
async def test_starter_tenant_still_reaches_dashboard_and_records(
    client: AsyncClient, db_session: AsyncSession
):
    """Sanity check — the always-on Starter modules are untouched by this gate."""
    acc = await _make_account(db_session, plan="starter")
    token = await _make_admin_token(db_session, acc)

    resp = await client.get("/api/v1/dashboard", headers=_headers(token, acc))
    assert resp.status_code == 200

    resp = await client.get("/api/v1/records", headers=_headers(token, acc))
    assert resp.status_code == 200
