"""6C crm.contact.* contract, resolver, and private Core execution."""
from __future__ import annotations

from uuid import uuid4

from src.domain.codegen.prompt_wrapper import _app_recipes
from src.domain.connectors import crm_contact as crm_runtime
from src.domain.connectors.catalog import slugs_implementing
from src.domain.connectors.crm_contact import (
    ACTION_BY_CAPABILITY,
    HUBSPOT_NULL_CLEAR,
    CRMConnectionSnapshot,
    decode_crm_cursor,
    encode_crm_cursor,
    map_contact_capability_input,
    resolve_crm_contact,
    to_public_crm_contact_result,
)
from src.domain.connectors.invoke_capabilities import (
    CAPABILITY_CONVERSION_PATTERN,
    CRM_CONTACT_FROZEN_VERBS,
    CRM_CONTACT_OUT_OF_SLICE,
    CRM_CONTACT_PHASE_6C,
    CRM_FAMILY_PLAN,
    CRM_HYPOTHESIZED_VERBS_NOT_FROZEN,
    INVOKE_CAPABILITIES,
    is_implemented,
)
from src.domain.connectors.public_gateway import (
    PHASE_6_STATUS,
    PUBLIC_INVOCABLE_CAPABILITIES,
    strip_capability_response,
)
from src.domain.connectors.router import capability_router
from src.main import app

_CAPS = {"integrations.execute"}


def _crm(provider: str, **overrides) -> CRMConnectionSnapshot:
    data = dict(
        connection_id=uuid4(),
        connector_key=provider,
        status="active",
        has_secrets=True,
        permission_mode="allow",
        execution_domain="C",
        requires_secrets=True,
        client_side_only=False,
    )
    data.update(overrides)
    return CRMConnectionSnapshot(**data)


def test_6c_freezes_five_contact_verbs_without_public_truth() -> None:
    assert PHASE_6_STATUS == "6p_complete"
    assert CAPABILITY_CONVERSION_PATTERN["next_program_slice"] == (
        "9_app_block_modernization"
    )
    assert CRM_FAMILY_PLAN["next_slice"] == "forms_first_class_product_domain"
    assert CRM_CONTACT_PHASE_6C["catalog_invocable"] is False
    assert CRM_CONTACT_PHASE_6C["implements_attached"] is False
    assert CRM_CONTACT_PHASE_6C["public_bff_capability_route"] is False
    assert CRM_CONTACT_PHASE_6C["core_private_invoke_http"] is True
    assert CRM_CONTACT_PHASE_6C["enqueue"] == "integration.execute"
    assert CRM_CONTACT_FROZEN_VERBS == crm_runtime.CRM_CONTACT_FROZEN_VERBS
    assert CRM_CONTACT_FROZEN_VERBS == (
        "crm.contact.create",
        "crm.contact.get",
        "crm.contact.update",
        "crm.contact.upsert",
        "crm.contact.search",
    )
    for verb in CRM_CONTACT_FROZEN_VERBS:
        spec = INVOKE_CAPABILITIES[verb]
        assert spec["status"] == "implemented"
        assert spec["invocable"] is True
        assert spec["method"] == f"POST /api/projects/{{project_id}}/capabilities/{verb}"
        assert spec["runtime"] == "integration.execute"
        assert is_implemented(verb) is True
        assert verb in PUBLIC_INVOCABLE_CAPABILITIES
        slugs = slugs_implementing(verb)
        assert any(s.startswith("hubspot.") for s in slugs)
        assert any(s.startswith("salesforce.") for s in slugs)
    for verb in CRM_CONTACT_OUT_OF_SLICE + CRM_HYPOTHESIZED_VERBS_NOT_FROZEN:
        assert verb not in INVOKE_CAPABILITIES
    recipes = _app_recipes()
    assert "capabilities/crm.contact." in recipes


def test_core_registers_private_crm_contact_routes() -> None:
    paths = {getattr(route, "path", "") for route in capability_router.routes}
    app_paths = {getattr(route, "path", "") for route in app.routes}
    for verb in CRM_CONTACT_FROZEN_VERBS:
        expected = f"/api/projects/{{project_id}}/capabilities/{verb}"
        assert expected in paths
        assert expected in app_paths


def test_hubspot_and_salesforce_action_slugs_are_repository_truth() -> None:
    assert ACTION_BY_CAPABILITY["crm.contact.create"] == {
        "hubspot": "hubspot.create_contact",
        "salesforce": "salesforce.create_contact",
    }
    assert ACTION_BY_CAPABILITY["crm.contact.upsert"] == {
        "hubspot": "hubspot.upsert_contact",
        "salesforce": "salesforce.upsert_contact",
    }
    for mapping in ACTION_BY_CAPABILITY.values():
        assert "salesforce.create_lead" not in mapping.values()
        assert "salesforce.get_lead" not in mapping.values()


def test_create_does_not_require_email_and_does_not_upsert() -> None:
    hs = _crm("hubspot")
    created = resolve_crm_contact(
        capability="crm.contact.create",
        payload={"contact": {"first_name": "Ada"}},
        connections=[hs],
        enabled_capabilities=_CAPS,
    )
    assert created.ok
    assert created.plan is not None
    assert created.plan.action == "hubspot.create_contact"
    assert "email" not in created.plan.resolved_input
    assert created.plan.resolved_input["properties"]["firstname"] == "Ada"
    duplicate = to_public_crm_contact_result(
        created,
        capability="crm.contact.create",
        enqueue={
            "ok": True,
            "result": {"id": "123", "already_exists": True, "properties": {}},
        },
    )
    assert duplicate.status == "rejected"
    assert duplicate.reason_code == "crm_duplicate_match"


def test_upsert_requires_email_and_uses_provider_upsert_action() -> None:
    missing = resolve_crm_contact(
        capability="crm.contact.upsert",
        payload={"contact": {"first_name": "Ada"}},
        connections=[_crm("salesforce")],
        enabled_capabilities=_CAPS,
    )
    assert missing.ok is False
    assert missing.reason_code == "crm_validation_failed"
    ok = resolve_crm_contact(
        capability="crm.contact.upsert",
        payload={"contact": {"email": "ada@example.com", "first_name": "Ada"}},
        connections=[_crm("salesforce")],
        enabled_capabilities=_CAPS,
    )
    assert ok.plan is not None
    assert ok.plan.action == "salesforce.upsert_contact"
    assert ok.plan.resolved_input["email"] == "ada@example.com"
    assert ok.plan.resolved_input["fields"]["FirstName"] == "Ada"
    assert ok.plan.resolved_input["fields"]["Email"] == "ada@example.com"


def test_get_uses_object_ref_not_email_or_local_id() -> None:
    row = _crm("hubspot")
    by_email = resolve_crm_contact(
        capability="crm.contact.get",
        payload={"contact": "ada@example.com"},
        connections=[row],
        enabled_capabilities=_CAPS,
    )
    assert by_email.reason_code == "crm_validation_failed"
    by_email_dict = resolve_crm_contact(
        capability="crm.contact.get",
        payload={"contact": {"email": "ada@example.com"}},
        connections=[row],
        enabled_capabilities=_CAPS,
    )
    assert by_email_dict.reason_code == "crm_validation_failed"
    ok = resolve_crm_contact(
        capability="crm.contact.get",
        payload={"contact": {"object_type": "contact", "external_id": "123"}},
        connections=[row],
        enabled_capabilities=_CAPS,
    )
    assert ok.plan is not None
    assert ok.plan.resolved_input["contact_id"] == "123"


def test_update_preserves_omitted_vs_null() -> None:
    hs = map_contact_capability_input(
        "crm.contact.update",
        "hubspot",
        {
            "contact": {"object_type": "contact", "external_id": "99"},
            "changes": {"phone": None, "first_name": "Ada"},
        },
    )
    assert isinstance(hs, dict)
    assert hs["properties"]["phone"] is None
    assert hs["properties"]["firstname"] == "Ada"
    assert "lastname" not in hs["properties"]
    sf = map_contact_capability_input(
        "crm.contact.update",
        "salesforce",
        {
            "contact": {"object_type": "contact", "external_id": "99"},
            "changes": {"phone": None, "first_name": "Ada"},
        },
    )
    assert isinstance(sf, dict)
    assert sf["fields"]["Phone"] is None
    assert sf["fields"]["FirstName"] == "Ada"
    assert "LastName" not in sf["fields"]


def test_property_collision_is_rejected() -> None:
    mapped = map_contact_capability_input(
        "crm.contact.create",
        "hubspot",
        {
            "contact": {
                "email": "a@x.com",
                "properties": {"email": "b@x.com"},
            }
        },
    )
    assert mapped == "crm_property_invalid"


def test_search_is_email_only_and_cursor_is_opaque() -> None:
    hs = _crm("hubspot")
    forbidden = resolve_crm_contact(
        capability="crm.contact.search",
        payload={"email": "ada@example.com", "filter_groups": []},
        connections=[hs],
        enabled_capabilities=_CAPS,
    )
    assert forbidden.reason_code == "provider_fields_forbidden"
    soql = resolve_crm_contact(
        capability="crm.contact.search",
        payload={"query": "SELECT Id FROM Contact"},
        connections=[_crm("salesforce")],
        enabled_capabilities=_CAPS,
    )
    assert soql.reason_code == "provider_fields_forbidden"
    planned = resolve_crm_contact(
        capability="crm.contact.search",
        payload={"email": "ada@example.com"},
        connections=[hs],
        enabled_capabilities=_CAPS,
    )
    assert planned.plan is not None
    assert planned.plan.action == "hubspot.search_contacts"
    assert planned.plan.resolved_input["filter_groups"][0]["filters"][0]["value"] == (
        "ada@example.com"
    )
    public = to_public_crm_contact_result(
        planned,
        capability="crm.contact.search",
        enqueue={
            "ok": True,
            "result": {
                "results": [
                    {
                        "id": "1",
                        "properties": {
                            "email": "ada@example.com",
                            "firstname": "Ada",
                        },
                    }
                ],
                "paging": {"next": {"after": "hs_after_token"}},
            },
        },
    )
    assert public.status == "succeeded"
    assert public.items is not None
    assert public.items[0]["ref"]["external_id"] == "1"
    assert public.next_cursor != "hs_after_token"
    assert decode_crm_cursor("hubspot", public.next_cursor or "") == "hs_after_token"
    encoded = encode_crm_cursor("hubspot", "hs_after_token")
    replay = map_contact_capability_input(
        "crm.contact.search",
        "hubspot",
        {"email": "ada@example.com", "cursor": encoded},
    )
    assert isinstance(replay, dict)
    assert replay["after"] == "hs_after_token"


def test_resolver_ignores_p_records_and_does_not_first_win() -> None:
    platform = _crm("hubspot", execution_domain="P")
    cloudish = _crm("p2hs_records")
    unbound = resolve_crm_contact(
        capability="crm.contact.create",
        payload={"contact": {"first_name": "Ada"}},
        connections=[platform, cloudish],
        enabled_capabilities=_CAPS,
    )
    assert unbound.reason_code == "crm_unbound"
    hs_a = _crm("hubspot")
    hs_b = _crm("hubspot")
    two_hs = resolve_crm_contact(
        capability="crm.contact.get",
        payload={"contact": {"object_type": "contact", "external_id": "1"}},
        connections=[hs_a, hs_b],
        enabled_capabilities=_CAPS,
        provider_hint="hubspot",
    )
    assert two_hs.reason_code == "binding_ambiguous"
    mixed = resolve_crm_contact(
        capability="crm.contact.get",
        payload={"contact": {"object_type": "contact", "external_id": "1"}},
        connections=[hs_a, _crm("salesforce")],
        enabled_capabilities=_CAPS,
        provider_hint="salesforce",
    )
    assert mixed.ok
    assert mixed.plan is not None
    assert mixed.plan.provider == "salesforce"


def test_queued_enqueue_does_not_fabricate_contact_ref() -> None:
    resolution = resolve_crm_contact(
        capability="crm.contact.create",
        payload={"contact": {"email": "ada@example.com"}},
        connections=[_crm("hubspot")],
        enabled_capabilities=_CAPS,
    )
    public = to_public_crm_contact_result(
        resolution,
        capability="crm.contact.create",
        enqueue={"ok": True, "job_id": "job_1", "status": "queued"},
    ).as_dict()
    assert public == {"capability": "crm.contact.create", "status": "queued"}
    assert "contact" not in public
    stripped = strip_capability_response(
        {**public, "contact_id": "123", "job_id": "job_1", "action": "x"}
    )
    assert stripped == public
    assert resolution.plan is not None
    assert resolution.plan.notes.get("hubspot_null_clear") == HUBSPOT_NULL_CLEAR


def test_salesforce_result_normalizes_to_crm_contact() -> None:
    resolution = resolve_crm_contact(
        capability="crm.contact.get",
        payload={"contact": {"object_type": "contact", "external_id": "003xx"}},
        connections=[_crm("salesforce")],
        enabled_capabilities=_CAPS,
    )
    public = to_public_crm_contact_result(
        resolution,
        capability="crm.contact.get",
        enqueue={
            "ok": True,
            "result": {
                "Id": "003xx",
                "Email": "ada@example.com",
                "FirstName": "Ada",
                "LastName": "Lovelace",
                "Phone": None,
            },
        },
    )
    assert public.status == "succeeded"
    assert public.contact == {
        "ref": {"object_type": "contact", "external_id": "003xx"},
        "email": "ada@example.com",
        "first_name": "Ada",
        "last_name": "Lovelace",
        "phone": None,
    }
