"""Covers the Portal Report Builder's backend surface: /datasets/ai-query
and /datasets/export.xlsx becoming vendor-aware (mirroring /datasets/query's
existing per-record grant check), the new /datasets/export.pdf endpoint, and
the whole-feature "reports" grant a Portal role can hold on top of that — see
app/routers/datasets.py::_require_query_access/_require_reports_feature/
_rows_to_pdf."""

import uuid

from app.core.auth import create_access_token
from tests.conftest import AsyncSessionLocal
from app.models.identity import Role, User, UserRole


async def _create_vendor_user_with_grant(
    tenant_id: uuid.UUID, master_id: uuid.UUID | None, grant_reports: bool = True
) -> str:
    """A vendor user holding a real scope="portal" role — the shape
    PortalRoles.tsx actually creates (action_matrix: module -> [record_id,
    ...]) — unlike test_vendor_portal.py's _vendor_token_with_full_access,
    which deliberately uses an internal-scope role to prove deny_vendor
    blocks regardless of permissions. Here we need the real portal grant
    path (resolve_portal_grants) to be exercised. grant_reports defaults to
    True so existing call sites keep exercising the masters/forms grant path
    without also needing the separate "reports" feature gate spelled out."""
    async with AsyncSessionLocal() as db:
        async with db.begin():
            action_matrix: dict[str, list[str]] = {}
            if master_id:
                action_matrix["masters"] = [str(master_id)]
            if grant_reports:
                action_matrix["reports"] = ["enabled"]
            role = Role(tenant_id=tenant_id, name=f"Portal Grant {uuid.uuid4().hex[:6]}", scope="portal", action_matrix=action_matrix)
            db.add(role)
            await db.flush()
            vendor_user = User(
                tenant_id=tenant_id, name="Vendor Reporter", email=f"vendor-reporter-{role.id}@example.com", status="active"
            )
            db.add(vendor_user)
            await db.flush()
            db.add(UserRole(user_id=vendor_user.id, role_id=role.id))
            await db.flush()
            user_id = vendor_user.id

    return create_access_token(tenant_id=tenant_id, user_id=user_id, vendor_id=uuid.uuid4())


async def _create_master_with_record(client, auth_headers, name: str) -> str:
    resp = await client.post(
        "/masters",
        headers=auth_headers,
        json={"name": name, "field_schema": [{"name": "revenue", "type": "number"}]},
    )
    master_id = resp.json()["id"]
    await client.post(f"/masters/{master_id}/records", headers=auth_headers, json={"field_values": {"revenue": 42}})
    return master_id


async def test_vendor_ai_query_no_longer_403s_outright(client, auth_headers, test_tenant):
    """With zero grants, the vendor branch still runs (no blanket
    require_permission 403) — the endpoint itself reports "nothing to
    query" via AiQueryResult.error, a 200 response, not a 403."""
    token = await _create_vendor_user_with_grant(test_tenant["tenant_id"], None)
    resp = await client.post(
        "/datasets/ai-query", headers={"Authorization": f"Bearer {token}"}, json={"prompt": "show me everything"}
    )
    assert resp.status_code == 200
    assert resp.json()["error"]


async def test_vendor_export_xlsx_succeeds_for_granted_master(client, auth_headers, test_tenant):
    master_id = await _create_master_with_record(client, auth_headers, "Vendor Orders")
    token = await _create_vendor_user_with_grant(test_tenant["tenant_id"], uuid.UUID(master_id))
    resp = await client.post(
        "/datasets/export.xlsx",
        headers={"Authorization": f"Bearer {token}"},
        json={"source_type": "master", "source_id": master_id},
    )
    assert resp.status_code == 200
    assert resp.headers["content-type"] == "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"


async def test_vendor_export_xlsx_403s_for_ungranted_master(client, auth_headers, test_tenant):
    master_id = await _create_master_with_record(client, auth_headers, "Ungranted Orders")
    token = await _create_vendor_user_with_grant(test_tenant["tenant_id"], None)
    resp = await client.post(
        "/datasets/export.xlsx",
        headers={"Authorization": f"Bearer {token}"},
        json={"source_type": "master", "source_id": master_id},
    )
    assert resp.status_code == 403


async def test_vendor_export_pdf_succeeds_and_produces_pdf_bytes(client, auth_headers, test_tenant):
    master_id = await _create_master_with_record(client, auth_headers, "Vendor PDF Orders")
    token = await _create_vendor_user_with_grant(test_tenant["tenant_id"], uuid.UUID(master_id))
    resp = await client.post(
        "/datasets/export.pdf",
        headers={"Authorization": f"Bearer {token}"},
        json={"source_type": "master", "source_id": master_id},
    )
    assert resp.status_code == 200
    assert resp.headers["content-type"] == "application/pdf"
    assert resp.content.startswith(b"%PDF")


async def test_vendor_export_pdf_403s_for_ungranted_master(client, auth_headers, test_tenant):
    master_id = await _create_master_with_record(client, auth_headers, "Ungranted PDF Orders")
    token = await _create_vendor_user_with_grant(test_tenant["tenant_id"], None)
    resp = await client.post(
        "/datasets/export.pdf",
        headers={"Authorization": f"Bearer {token}"},
        json={"source_type": "master", "source_id": master_id},
    )
    assert resp.status_code == 403


async def test_studio_caller_still_works_for_all_three_endpoints(client, auth_headers):
    """Regression: the non-vendor (Studio) path through ai-query/export.xlsx/
    export.pdf must be unaffected by removing their blanket
    require_permission dependency in favor of the manual branch."""
    master_id = await _create_master_with_record(client, auth_headers, "Studio Orders")

    ai_resp = await client.post("/datasets/ai-query", headers=auth_headers, json={"prompt": "show me studio orders"})
    assert ai_resp.status_code == 200

    xlsx_resp = await client.post(
        "/datasets/export.xlsx", headers=auth_headers, json={"source_type": "master", "source_id": master_id}
    )
    assert xlsx_resp.status_code == 200

    pdf_resp = await client.post(
        "/datasets/export.pdf", headers=auth_headers, json={"source_type": "master", "source_id": master_id}
    )
    assert pdf_resp.status_code == 200
    assert pdf_resp.content.startswith(b"%PDF")


async def test_vendor_ai_query_403s_without_reports_feature(client, auth_headers, test_tenant):
    """A vendor holding masters/forms grants but no "reports" feature grant
    (see PortalRoles.tsx's new toggle) must still be blocked from ai-query —
    the per-record master/form grant alone isn't enough."""
    master_id = await _create_master_with_record(client, auth_headers, "Gated Orders")
    token = await _create_vendor_user_with_grant(test_tenant["tenant_id"], uuid.UUID(master_id), grant_reports=False)
    resp = await client.post(
        "/datasets/ai-query", headers={"Authorization": f"Bearer {token}"}, json={"prompt": "show me gated orders"}
    )
    assert resp.status_code == 403


async def test_vendor_export_xlsx_403s_without_reports_feature(client, auth_headers, test_tenant):
    master_id = await _create_master_with_record(client, auth_headers, "Gated Xlsx Orders")
    token = await _create_vendor_user_with_grant(test_tenant["tenant_id"], uuid.UUID(master_id), grant_reports=False)
    resp = await client.post(
        "/datasets/export.xlsx",
        headers={"Authorization": f"Bearer {token}"},
        json={"source_type": "master", "source_id": master_id},
    )
    assert resp.status_code == 403


async def test_vendor_export_pdf_403s_without_reports_feature(client, auth_headers, test_tenant):
    master_id = await _create_master_with_record(client, auth_headers, "Gated Pdf Orders")
    token = await _create_vendor_user_with_grant(test_tenant["tenant_id"], uuid.UUID(master_id), grant_reports=False)
    resp = await client.post(
        "/datasets/export.pdf",
        headers={"Authorization": f"Bearer {token}"},
        json={"source_type": "master", "source_id": master_id},
    )
    assert resp.status_code == 403


async def test_vendor_query_dataset_unaffected_by_missing_reports_feature(client, auth_headers, test_tenant):
    """/datasets/query (what Page/Dashboard widgets call) must stay open on
    the existing per-record master/form grant alone — the "reports" feature
    gate only applies to the standalone Report Builder's own endpoints."""
    master_id = await _create_master_with_record(client, auth_headers, "Widget Orders")
    token = await _create_vendor_user_with_grant(test_tenant["tenant_id"], uuid.UUID(master_id), grant_reports=False)
    resp = await client.post(
        "/datasets/query",
        headers={"Authorization": f"Bearer {token}"},
        json={"source_type": "master", "source_id": master_id},
    )
    assert resp.status_code == 200
