"""Proof suite: the reviewer's own five named "boring but representative" Level 1
examples (quote request, job application, customer inquiry, lead capture, feedback
submission) each compose successfully end-to-end -- no catalog match, a named
synthesized pack results, the correct access pattern is chosen, install delegates to
the existing unmodified PackInstallService, no provision.json fallback is needed.

Ticketing -- Level 1's own deliberate boundary case, which used to return
primitive_gap -- is now the first proof of Level 2: workflow.transition exists, so it
composes successfully with an enforced status-transition graph attached to the entity.
A fresh boundary case (approval.quorum, still genuinely unsupported) replaces it to
keep proving the "don't invent a backend when Cloud can't express something" rule
actually holds, not just in prose.
"""
from __future__ import annotations

from types import SimpleNamespace
from unittest.mock import AsyncMock, patch
from uuid import uuid4

import pytest

from src.domain.feature_packs.composer import compose_and_register_pack
from src.domain.feature_packs.requirements_spec import CompositionRequirement

# Every example: an anonymous visitor creates, staff/admin reviews. No catalog pack
# covers any of these (they are not contact-capture, booking, CRM, ...).
_EXAMPLES = {
    "quote_request": [
        {"key": "name", "label": "Name", "type": "text", "required": True},
        {"key": "email", "label": "Email", "type": "text", "required": True},
        {"key": "item", "label": "Item", "type": "text", "required": True},
    ],
    "job_application": [
        {"key": "applicant_name", "label": "Applicant Name", "type": "text", "required": True},
        {"key": "email", "label": "Email", "type": "text", "required": True},
        {"key": "position", "label": "Position", "type": "text", "required": True},
    ],
    "customer_inquiry": [
        {"key": "name", "label": "Name", "type": "text", "required": True},
        {"key": "message", "label": "Message", "type": "text", "required": True},
    ],
    "lead_capture": [
        {"key": "name", "label": "Name", "type": "text", "required": True},
        {"key": "email", "label": "Email", "type": "text", "required": True},
        {"key": "company", "label": "Company", "type": "text"},
    ],
    "feedback_submission": [
        {"key": "rating", "label": "Rating", "type": "number", "required": True},
        {"key": "comments", "label": "Comments", "type": "text"},
    ],
}


def _requirement(name: str, fields: list[dict]) -> CompositionRequirement:
    return CompositionRequirement.model_validate({
        "name": name,
        "actors": ["anonymous", "admin"],
        "requirements": [
            {"action": "create", "resource": name, "actor": "anonymous"},
            {"action": "read", "resource": name, "actor": "admin"},
        ],
        "fields": fields,
    })


def _fake_db():
    execute_result = SimpleNamespace(scalar_one_or_none=lambda: None)
    return SimpleNamespace(
        execute=AsyncMock(return_value=execute_result),
        add=lambda obj: None,
        flush=AsyncMock(),
    )


@pytest.mark.asyncio
@pytest.mark.parametrize("name,fields", list(_EXAMPLES.items()))
async def test_composable_example_installs_through_the_existing_pipeline(name, fields):
    req = _requirement(name, fields)
    db = _fake_db()
    project_ref = "p78ot2o6"
    install_mock = AsyncMock(return_value={"ok": True, "status": "installed", "errors": []})

    with patch("src.domain.feature_packs.service.PackInstallService.install_pack", install_mock):
        outcome = await compose_and_register_pack(db, object(), uuid4(), project_ref, req, f"build a {name} form")

    # No primitive_gap -- this shape is genuinely composable from existing primitives.
    assert outcome.get("status") != "primitive_gap"
    assert outcome["ok"] is True
    assert outcome["pack_slug"] == f"local-{project_ref}-{name}"

    # Installed through the real, unmodified pipeline -- not a parallel install path.
    install_mock.assert_awaited_once()
    _, kwargs = install_mock.call_args
    assert kwargs["pack_slug"] == f"local-{project_ref}-{name}"


@pytest.mark.asyncio
async def test_ticketing_now_composes_via_the_workflow_transition_primitive():
    """Level 1's own deliberate boundary case, now closed by Level 2: a ticket
    lifecycle needs enforced state transitions, and workflow.transition exists."""
    req = CompositionRequirement.model_validate({
        "name": "support_ticket",
        "actors": ["member", "admin"],
        "requirements": [
            {"action": "create", "resource": "support_ticket", "actor": "member"},
            {"action": "update", "resource": "support_ticket", "actor": "admin"},
        ],
        "fields": [
            {"key": "subject", "label": "Subject", "type": "text", "required": True},
            {"key": "status", "label": "Status", "type": "select",
             "options": ["open", "pending", "resolved"]},
        ],
        "workflow": {
            "field": "status",
            "transitions": {"open": ["pending"], "pending": ["open", "resolved"], "resolved": []},
        },
    })
    db = _fake_db()
    install_mock = AsyncMock(return_value={"ok": True, "status": "installed", "errors": []})

    with patch("src.domain.feature_packs.service.PackInstallService.install_pack", install_mock):
        outcome = await compose_and_register_pack(db, object(), uuid4(), "p78ot2o6", req)

    assert outcome.get("status") != "primitive_gap"
    assert outcome["ok"] is True
    assert outcome["pack_slug"] == "local-p78ot2o6-support_ticket"
    install_mock.assert_awaited_once()


@pytest.mark.asyncio
async def test_approval_quorum_is_the_new_boundary_case_reported_honestly_not_faked():
    """A requirement needing a primitive Cloud genuinely doesn't have yet (multi-
    approver quorum) must still return primitive_gap, never a fake success -- keeps
    proving the honest-failure rule now that workflow.transition is supported."""
    req = CompositionRequirement.model_validate({
        "name": "expense_report",
        "actors": ["member", "admin"],
        "requirements": [
            {"action": "create", "resource": "expense_report", "actor": "member"},
            {"action": "update", "resource": "expense_report", "actor": "admin"},
        ],
        "fields": [{"key": "amount", "label": "Amount", "type": "number", "required": True}],
        "requires": ["approval.quorum"],
    })
    db = _fake_db()
    install_mock = AsyncMock()

    with patch("src.domain.feature_packs.service.PackInstallService.install_pack", install_mock):
        outcome = await compose_and_register_pack(db, object(), uuid4(), "p78ot2o6", req)

    assert outcome["ok"] is False
    assert outcome["status"] == "primitive_gap"
    assert "approval.quorum" in outcome["missing"]
    install_mock.assert_not_awaited()  # never fell back to installing something broken
