"""6P CRM application fixtures. No new verbs, packs, or Codegen semantics."""
from __future__ import annotations

from typing import Any
from uuid import UUID, uuid4

from src.domain.app_blocks.compiler import compile_install_plan
from src.domain.app_blocks.crm_composition import (
    CONTACT_FORM_UPSERT_CAPABILITY,
    OBJECT_REF_PERSISTENCE,
    contact_form_crm_capability,
    map_form_fields_to_crm_contact,
    select_contact_form_composition,
    select_local_lead_composition,
)
from src.domain.codegen.crm_codegen import (
    CRM_PUBLIC_INVOKE_PATH,
    GENERIC_CRM_LEAK_TOKENS,
    generic_snippet_leaks,
    select_crm_generation,
)
from src.domain.connectors.crm_resolve import CRMConnectionSnapshot
from src.domain.connectors.public_gateway import (
    FORBIDDEN_RESPONSE_KEYS,
    strip_capability_response,
)
from src.domain.feature_packs.normalize import load_pack_contract
from src.domain.projects.discovery_schemas import (
    Actor,
    AuthenticationSpec,
    DiscoverySpec,
    Entity,
    ProductDefinition,
    TenancySpec,
    Workflow,
)

DURABLE_OBJECT_REF_DECISION = "DEFERRED"
DURABLE_OBJECT_REF_REASON = (
    "Current 6P workflows are outbound and identity-by-email (form upsert) or "
    "in-session CRMObjectRef from capability results (deal/association). "
    "A durable local_entity_id → CRMObjectRef store is not required to close "
    "these applications. Bidirectional local↔external mirroring is not claimed."
)

PORTABLE_SALES_CAPABILITIES = (
    "crm.contact.upsert",
    "crm.deal.create",
    "crm.deal.update",
    "crm.association.create",
)

LEGACY_CRM_SYNC_TOKENS = (
    "contact-capture-crm-sync",
    "CRM_CONNECTION_ID",
    "CRM_CONNECTOR_ACTION",
    "hubspot.upsert_contact",
    "salesforce.upsert_lead",
)

FORBIDDEN_GENERATED_HOSTS = (
    "beapipie",
    "api.hubapi.com",
    "my.salesforce.com",
    "/api/crm/",
    "/api/connectors",
    "/api/integrations",
    "/api/jobs/crm.",
)

SECRET_LEAK_TOKENS = (
    "access_token",
    "refresh_token",
    "client_secret",
    "portal_id",
    "org_id",
    "instance_url",
    "login_host",
)


def _spec(**overrides) -> DiscoverySpec:
    data: dict[str, Any] = {
        "product": ProductDefinition(
            name="Site",
            name_status="working",
            purpose="Allow prospective customers to contact us.",
            first_build_goal="Capture website enquiries.",
        ),
        "archetypes": ["marketing_site"],
        "actors": [
            Actor(id="visitor", name="Website visitor"),
            Actor(id="staff", name="Staff"),
        ],
        "workflows": [
            Workflow(
                id="submit_enquiry",
                name="Submit enquiry",
                description="Visitor sends a message",
            )
        ],
        "entities": [Entity(id="enquiry", name="Enquiry", description="A website enquiry")],
        "tenancy": TenancySpec(model="single_workspace"),
        "authentication": AuthenticationSpec(required=False),
    }
    product_updates = {}
    if "purpose" in overrides:
        product_updates["purpose"] = overrides.pop("purpose")
    if "first_build_goal" in overrides:
        product_updates["first_build_goal"] = overrides.pop("first_build_goal")
    if product_updates:
        current = data["product"]
        data["product"] = current.model_copy(update=product_updates)
    data.update(overrides)
    return DiscoverySpec(**data)


def fixture_contact_form_only() -> dict[str, Any]:
    plan = compile_install_plan(_spec())
    composition = select_contact_form_composition(sync_to_crm=False)
    return {
        "id": "A",
        "plan": plan,
        "composition": composition,
        "capabilities": (),
        "source": generated_app_source(local_form=True, capabilities=()),
    }


def fixture_contact_form_crm_sync() -> dict[str, Any]:
    spec = _spec(
        purpose="Marketing site with a contact form that syncs submissions to CRM.",
        first_build_goal="Capture website enquiries.",
    )
    plan = compile_install_plan(spec)
    composition = select_contact_form_composition(
        sync_to_crm=True, hubspot_connected=True, salesforce_connected=True
    )
    caps = (CONTACT_FORM_UPSERT_CAPABILITY,)
    return {
        "id": "B",
        "plan": plan,
        "composition": composition,
        "capabilities": caps,
        "source": generated_app_source(local_form=True, capabilities=caps),
        "codegen": select_crm_generation("Sync form submissions to CRM by email"),
    }


def fixture_local_lead_only() -> dict[str, Any]:
    spec = _spec(
        purpose="Internal CRM for managing sales leads.",
        first_build_goal="Track leads through a pipeline.",
        archetypes=["operations"],
        actors=[Actor(id="agent", name="Sales agent")],
        workflows=[
            Workflow(
                id="pipeline",
                name="Lead pipeline",
                description="Move leads through stages",
            )
        ],
        entities=[Entity(id="lead", name="Lead", description="A sales lead")],
    )
    plan = compile_install_plan(spec)
    composition = select_local_lead_composition(sync_to_crm=False)
    return {
        "id": "C",
        "plan": plan,
        "composition": composition,
        "capabilities": (),
        "source": generated_app_source(local_lead=True, capabilities=()),
    }


def fixture_portable_sales_app() -> dict[str, Any]:
    source = generated_app_source(
        local_form=True, capabilities=PORTABLE_SALES_CAPABILITIES
    )
    graph = {
        select_crm_generation("Sync form submissions to CRM by email").capability,
        select_crm_generation("Create a deal").capability,
        select_crm_generation("Move deal to qualified").capability,
        select_crm_generation("Associate this contact with the company").capability,
    }
    return {
        "id": "H",
        "capabilities": PORTABLE_SALES_CAPABILITIES,
        "source": source,
        "codegen_graph": graph,
    }


def fixture_bare_crm_prompt() -> dict[str, Any]:
    spec = _spec(
        purpose="Build me a CRM for the team website.",
        first_build_goal="A simple CRM landing page.",
        archetypes=["marketing_site"],
    )
    return {"id": "legacy_avoidance", "plan": compile_install_plan(spec)}


def generated_app_source(
    *,
    local_form: bool = False,
    local_lead: bool = False,
    capabilities: tuple[str, ...] = (),
) -> str:
    lines: list[str] = []
    if local_form:
        lines.append("await submitContact(fields) // POST /api/contact local persist")
        lines.append("localRecordId = submission.id")
    if local_lead:
        lines.append('await listRecords("lead")')
        lines.append('await patchRecord("lead", id, { status: "qualified" })')
    for capability in capabilities:
        path = CRM_PUBLIC_INVOKE_PATH.format(
            project_id="${projectId}", capability=capability
        )
        lines.append(f"await fetch({path!r}, {{ method: 'POST', body }})")
        if capability == "crm.contact.upsert":
            lines.append(
                "body = { contact: { email, first_name, last_name, phone } }"
            )
        if capability == "crm.deal.update":
            lines.append("changes = { stage: 'qualified' }")
    return "\n".join(lines)


def contact_form_submit(
    *,
    fields: dict[str, Any],
    sync_enabled: bool,
    crm_enqueue: dict[str, Any] | None = None,
) -> dict[str, Any]:
    """Best-effort: local persist always wins on the default disabled binding."""
    local_id = "sub_local_1"
    local = {
        "id": local_id,
        "entity": "contact_submission",
        "persisted": True,
        "status": "accepted",
    }
    capability = contact_form_crm_capability(
        enabled=sync_enabled, has_email=bool(fields.get("email"))
    )
    if capability is None:
        return {
            "local": local,
            "crm": None,
            "crm_unavailable": sync_enabled,
            "local_rolled_back": False,
            "ux": "success",
        }
    contact = map_form_fields_to_crm_contact(fields)
    enqueue = crm_enqueue or {"ok": True, "status": "queued"}
    crm_ok = bool(enqueue.get("ok"))
    if crm_ok and enqueue.get("result"):
        crm_status = "succeeded"
    elif crm_ok:
        crm_status = "queued"
    else:
        crm_status = "rejected"
    raw = (enqueue.get("result") or {}) if crm_ok else {}
    external_id = raw.get("id") or raw.get("Id")
    if crm_status == "queued":
        external_id = None
    return {
        "local": local,
        "crm": {
            "capability": capability,
            "contact": contact,
            "status": crm_status,
            "reason_code": None if crm_ok else enqueue.get("reason_code"),
            "external_id": external_id,
        },
        "local_rolled_back": False,
        "ids_distinct": external_id is None or str(external_id) != local_id,
        "ux": "success",
    }


def snapshot_leaks(source: str) -> tuple[str, ...]:
    found = list(generic_snippet_leaks(source))
    extra = (*LEGACY_CRM_SYNC_TOKENS, *FORBIDDEN_GENERATED_HOSTS, *SECRET_LEAK_TOKENS)
    for token in extra:
        if token in source and token not in found:
            found.append(token)
    return tuple(found)


def public_bff_body(payload: dict[str, Any]) -> dict[str, Any]:
    return strip_capability_response(payload)


def crm_snapshot(
    provider: str,
    *,
    status: str = "active",
    connection_id: UUID | None = None,
    config: dict[str, Any] | None = None,
) -> CRMConnectionSnapshot:
    return CRMConnectionSnapshot(
        connection_id=connection_id or uuid4(),
        connector_key=provider,
        status=status,
        has_secrets=True,
        permission_mode="allow",
        execution_domain="C",
        requires_secrets=True,
        client_side_only=False,
        config=config or {},
    )


def local_p_records() -> dict[str, list[dict[str, str]]]:
    return {
        "lead": [{"id": "lead_p", "status": "new"}],
        "contact_submission": [{"id": "sub_p", "email": "local@p2hs.test"}],
        "crm_contact": [{"id": "legacy_p"}],
        "crm_deal": [{"id": "deal_p"}],
    }


def pack_is_selectable(slug: str) -> bool:
    return load_pack_contract(slug, {}).planner.selectable


def invoke_path_is_public(capability: str) -> bool:
    path = CRM_PUBLIC_INVOKE_PATH.format(
        project_id="{project_id}", capability=capability
    )
    return path.startswith("POST /api/projects/{project_id}/capabilities/")


assert OBJECT_REF_PERSISTENCE["decision"] == "GAP_DOCUMENTED"
assert GENERIC_CRM_LEAK_TOKENS
assert FORBIDDEN_RESPONSE_KEYS
