"""Version-2 semantic App Block contracts.

V2 keeps product language separate from implementation providers.  A generated
application depends on semantic capabilities (for example
``payments.subscription``); a provider binding only records which adapter can
currently satisfy that capability and whether configuration is still needed.
This module is deliberately a catalog/contract layer.  Cloud remains the
executor and Core remains authoritative for policy and entitlements.
"""

from __future__ import annotations

from typing import Literal

from pydantic import BaseModel, ConfigDict, Field

V2_CONTRACT_SCHEMA_VERSION = 2

V2BlockStatus = Literal["contracted", "configuration_required", "planned"]
V2BindingStatus = Literal["ready", "configuration_required", "degraded", "unsupported"]


class V2ProviderBinding(BaseModel):
    model_config = ConfigDict(extra="forbid")

    provider: str
    status: V2BindingStatus
    supported: list[str] = Field(default_factory=list)
    configuration_required: bool = False
    missing_configuration_behavior: Literal["degraded", "disabled", "block_install"] = "degraded"


class V2AppBlockContract(BaseModel):
    model_config = ConfigDict(extra="forbid")

    schema_version: Literal[2] = 2
    id: str
    title: str
    family: str
    status: V2BlockStatus = "contracted"
    requires: list[str] = Field(default_factory=list)
    bindings: dict[str, V2ProviderBinding] = Field(default_factory=dict)
    ui_primitives: list[str] = Field(default_factory=list)
    events: list[str] = Field(default_factory=list)

    def to_runtime_contract(self) -> dict:
        """Serialize the stable semantic contract sent to a generated runtime."""
        return {
            "schema_version": self.schema_version,
            "id": self.id,
            "requires": list(self.requires),
            "bindings": {key: value.model_dump(mode="json") for key, value in self.bindings.items()},
            "ui_primitives": list(self.ui_primitives),
            "events": list(self.events),
            "status": self.status,
        }


def _binding(
    provider: str = "platform",
    *,
    status: V2BindingStatus = "ready",
    supported: tuple[str, ...] = (),
    configuration_required: bool = False,
) -> V2ProviderBinding:
    return V2ProviderBinding(
        provider=provider,
        status=status,
        supported=list(supported),
        configuration_required=configuration_required,
        missing_configuration_behavior="degraded",
    )


V2_APP_BLOCKS: dict[str, V2AppBlockContract] = {
    "content.page": V2AppBlockContract(
        id="content.page",
        title="Page",
        family="content",
        requires=["records.crud", "seo.sitemap"],
        ui_primitives=["layout.page", "form.standard", "state.success", "state.error"],
        events=["content.page.created", "content.page.updated"],
    ),
    "content.post": V2AppBlockContract(
        id="content.post",
        title="Post",
        family="content",
        requires=["records.crud", "records.search", "seo.sitemap"],
        ui_primitives=["collection.index", "collection.grid", "form.standard", "ui.richtext"],
        events=["content.post.created", "content.post.updated"],
    ),
    "organization.workspace": V2AppBlockContract(
        id="organization.workspace",
        title="Workspace",
        family="organization",
        requires=["auth", "records.crud", "access.roles"],
        ui_primitives=["layout.admin", "record.detail", "state.configuration_required"],
        events=["organization.workspace.created", "organization.workspace.updated"],
    ),
    "team.members": V2AppBlockContract(
        id="team.members",
        title="Team Members",
        family="organization",
        requires=["organization.workspace", "records.crud", "access.roles"],
        ui_primitives=["record.table", "record.create", "record.edit", "gate.permission"],
        events=["team.member.added", "team.member.updated", "team.member.removed"],
    ),
    "access.roles": V2AppBlockContract(
        id="access.roles",
        title="Roles and Access",
        family="organization",
        requires=["auth", "organization.workspace"],
        ui_primitives=["record.table", "record.edit", "gate.permission"],
        events=["access.role.created", "access.role.updated"],
    ),
    "search.experience": V2AppBlockContract(
        id="search.experience",
        title="Search",
        family="search",
        requires=["records.search"],
        ui_primitives=["search.box", "filter.bar", "record.list", "state.empty"],
        events=["search.performed"],
    ),
    "automation.trigger": V2AppBlockContract(
        id="automation.trigger",
        title="Automation Trigger",
        family="automation",
        requires=["integration.webhook", "events.emit"],
        ui_primitives=["form.standard", "state.success", "state.error"],
        events=["automation.triggered", "automation.completed", "automation.failed"],
    ),
    "admin.audit": V2AppBlockContract(
        id="admin.audit",
        title="Audit Log",
        family="governance",
        requires=["records.crud", "activity.timeline"],
        ui_primitives=["record.table", "filter.bar", "record.detail"],
        events=["admin.audit.recorded"],
    ),
    "analytics.metrics": V2AppBlockContract(
        id="analytics.metrics",
        title="Metrics",
        family="analytics",
        requires=["records.aggregate"],
        ui_primitives=["metric.card", "chart.line", "chart.bar", "state.empty"],
        events=[],
    ),
    "payments.subscription": V2AppBlockContract(
        id="payments.subscription",
        title="Subscription Billing",
        family="payments",
        status="configuration_required",
        requires=["payments.subscription", "payments.customer", "payments.webhook"],
        bindings={
            "payments": _binding(
                "stripe",
                status="configuration_required",
                supported=("stripe", "paddle", "paypal"),
                configuration_required=True,
            )
        },
        ui_primitives=["record.table", "record.detail", "ui.currency_input", "state.configuration_required"],
        events=["subscription.created", "subscription.status_changed", "subscription.canceled"],
    ),
}


def get_v2_app_block(block_id: str) -> V2AppBlockContract:
    try:
        return V2_APP_BLOCKS[block_id]
    except KeyError as exc:
        raise KeyError(f"Unknown V2 App Block: {block_id}") from exc


def v2_contract_catalog_payload() -> dict:
    return {
        "schema_version": V2_CONTRACT_SCHEMA_VERSION,
        "blocks": [item.to_runtime_contract() for item in V2_APP_BLOCKS.values()],
        "provider_neutral": True,
        "policy_owner": "core",
        "execution_owner": "cloud",
    }


__all__ = [
    "V2_APP_BLOCKS",
    "V2_CONTRACT_SCHEMA_VERSION",
    "V2AppBlockContract",
    "V2ProviderBinding",
    "get_v2_app_block",
    "v2_contract_catalog_payload",
]
