"""6I logical CRM stage/pipeline bindings. Public catalog truth stays 6M."""
from __future__ import annotations

from uuid import uuid4

from src.domain.connectors.crm_deal import (
    map_deal_capability_input,
    resolve_crm_deal,
    to_public_crm_deal_result,
)
from src.domain.connectors.crm_resources import CRMPipelineRef, CRMStageRef
from src.domain.connectors.crm_resolve import CRMConnectionSnapshot
from src.domain.connectors.invoke_capabilities import (
    CAPABILITY_CONVERSION_PATTERN,
    CRM_FAMILY_PLAN,
    CRM_PIPELINE_STAGE_PHASE_6I,
    INVOKE_CAPABILITIES,
)
from src.domain.connectors.public_gateway import PHASE_6_STATUS, PUBLIC_INVOCABLE_CAPABILITIES

_CAPS = {"integrations.execute"}
_HS = {
    "stage_map": {"qualified": "appointmentscheduled", "won": "closedwon"},
    "pipeline_map": {"sales": "default"},
}
_SF = {"stage_map": {"qualified": "Qualification", "won": "Closed Won"}}


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,
        config={},
    )
    data.update(overrides)
    return CRMConnectionSnapshot(**data)


def test_6i_acceptance_matrix() -> None:
    assert PHASE_6_STATUS == "6p_complete"
    assert CAPABILITY_CONVERSION_PATTERN["next_program_slice"] == (
        "9_app_block_modernization"
    )
    assert CRM_FAMILY_PLAN["stage_binding"] == "logical_connection_scoped"
    assert CRM_FAMILY_PLAN["pipeline_binding"] == "hubspot_only"
    assert CRM_FAMILY_PLAN["salesforce_pipeline"] == "REJECT"
    assert CRM_FAMILY_PLAN["deal_search_stage"] == "stage_exact_logical_alias"
    assert CRM_PIPELINE_STAGE_PHASE_6I["raw_provider_fallback"] is False
    assert CRM_PIPELINE_STAGE_PHASE_6I["bidirectional"] is True
    assert CRM_PIPELINE_STAGE_PHASE_6I["salesforce_pipeline_not_record_type"] is True
    assert CRM_PIPELINE_STAGE_PHASE_6I["catalog_invocable"] is False
    CRMStageRef(alias="qualified")
    CRMPipelineRef(alias="sales")
    for verb in (
        "crm.deal.create",
        "crm.deal.update",
        "crm.deal.get",
        "crm.deal.search",
    ):
        assert INVOKE_CAPABILITIES[verb]["invocable"] is True
        assert verb in PUBLIC_INVOCABLE_CAPABILITIES


def test_stage_alias_resolves_per_connection() -> None:
    hs = map_deal_capability_input(
        "crm.deal.create",
        "hubspot",
        {"deal": {"name": "A", "stage": "qualified"}},
        _HS,
    )
    assert hs["properties"]["dealstage"] == "appointmentscheduled"
    sf = map_deal_capability_input(
        "crm.deal.create",
        "salesforce",
        {"deal": {"name": "A", "stage": "qualified"}},
        _SF,
    )
    assert sf["fields"]["StageName"] == "Qualification"
    missing = map_deal_capability_input(
        "crm.deal.create",
        "hubspot",
        {"deal": {"name": "A", "stage": "qualified"}},
        {},
    )
    assert missing == "crm_stage_unbound"
    raw = map_deal_capability_input(
        "crm.deal.create",
        "salesforce",
        {"deal": {"name": "A", "stage": "Qualification"}},
        _SF,
    )
    assert raw == "crm_validation_failed"


def test_hubspot_pipeline_binding_salesforce_rejected() -> None:
    hs = map_deal_capability_input(
        "crm.deal.create",
        "hubspot",
        {"deal": {"name": "A", "pipeline": "sales"}},
        _HS,
    )
    assert hs["properties"]["pipeline"] == "default"
    unbound = map_deal_capability_input(
        "crm.deal.create",
        "hubspot",
        {"deal": {"name": "A", "pipeline": "sales"}},
        {},
    )
    assert unbound == "crm_pipeline_unbound"
    sf = map_deal_capability_input(
        "crm.deal.create",
        "salesforce",
        {"deal": {"name": "A", "pipeline": "sales"}},
        _SF,
    )
    assert sf == "crm_pipeline_unsupported"
    record_type = map_deal_capability_input(
        "crm.deal.create",
        "salesforce",
        {"deal": {"name": "A", "properties": {"RecordTypeId": "012xx"}}},
        _SF,
    )
    assert isinstance(record_type, dict)
    # extra properties still pass through provider bag; pipeline alias never becomes RecordTypeId
    assert "pipeline" not in record_type["fields"]


def test_read_normalizes_and_omits_unknown() -> None:
    bound = resolve_crm_deal(
        capability="crm.deal.get",
        payload={"deal": {"object_type": "deal", "external_id": "1"}},
        connections=[_crm("hubspot", config=_HS)],
        enabled_capabilities=_CAPS,
    )
    public = to_public_crm_deal_result(
        bound,
        capability="crm.deal.get",
        enqueue={
            "ok": True,
            "result": {
                "id": "1",
                "properties": {
                    "dealname": "A",
                    "dealstage": "closedwon",
                    "pipeline": "default",
                },
            },
        },
    )
    assert public.deal["stage"] == "won"
    assert public.deal["pipeline"] == "sales"
    unknown = to_public_crm_deal_result(
        bound,
        capability="crm.deal.get",
        enqueue={
            "ok": True,
            "result": {
                "id": "1",
                "properties": {"dealname": "A", "dealstage": "legalreview"},
            },
        },
    )
    assert "stage" not in unknown.deal
    assert "legalreview" not in str(unknown.deal)


def test_search_stage_exact_and_name_still_works() -> None:
    hs = map_deal_capability_input(
        "crm.deal.search",
        "hubspot",
        {"stage": "qualified"},
        _HS,
    )
    assert hs["filter_groups"][0]["filters"] == [
        {
            "propertyName": "dealstage",
            "operator": "EQ",
            "value": "appointmentscheduled",
        }
    ]
    both = map_deal_capability_input(
        "crm.deal.search",
        "salesforce",
        {"name": "Renewal", "stage": "won"},
        _SF,
    )
    assert both["filters"] == {"Name": "Renewal", "StageName": "Closed Won"}
    name_only = map_deal_capability_input(
        "crm.deal.search", "hubspot", {"name": "Renewal"}, _HS
    )
    assert name_only["filter_groups"][0]["filters"][0]["propertyName"] == "dealname"
    planned = resolve_crm_deal(
        capability="crm.deal.search",
        payload={"stage": "qualified"},
        connections=[_crm("salesforce", config=_SF)],
        enabled_capabilities=_CAPS,
    )
    assert planned.ok
    assert planned.plan.resolved_input["filters"]["StageName"] == "Qualification"


def test_resolver_still_ambiguous_before_stage_lookup() -> None:
    two = resolve_crm_deal(
        capability="crm.deal.create",
        payload={"deal": {"name": "A", "stage": "qualified"}},
        connections=[_crm("hubspot", config=_HS), _crm("hubspot", config=_HS)],
        enabled_capabilities=_CAPS,
        provider_hint="hubspot",
    )
    assert two.reason_code == "binding_ambiguous"
