"""notification.sms Template A — contract + current-path mapping. No Codegen default yet."""
from __future__ import annotations

from src.domain.codegen.platform_backend import _compact_connectors
from src.domain.codegen.prompt_wrapper import (
    _P2HS_CLOUD_CONTRACT,
    _P2HS_CORE_API_GUIDANCE,
    _app_recipes,
)
from src.domain.connectors.catalog import get_action, slugs_implementing
from src.domain.connectors.invoke_capabilities import (
    CAPABILITY_CONVERSION_PATTERN,
    NOTIFICATION_SMS_ERRORS,
    NOTIFICATION_SMS_FORBIDDEN_METADATA_KEYS,
    NOTIFICATION_SMS_INPUT_SCHEMA,
    NOTIFICATION_SMS_INVOKE_METHOD,
    NOTIFICATION_SMS_OUTPUT_SCHEMA,
    NOTIFICATION_SMS_RESOLVER_DESIGN,
    TWILIO_NOTIFICATION_SMS_MAPPING,
    is_implemented,
)
from src.domain.manifest.service import _connectors_manifest_envelope


def test_notification_sms_is_opened_as_template_a() -> None:
    pattern = CAPABILITY_CONVERSION_PATTERN
    assert pattern["opened_families"]["messaging.sms.send"] == "A"
    assert pattern["templates"]["messaging.sms.send"] == "provider_backed_then_codegen_normalize"
    assert "notification.sms" not in pattern["next_candidates"]
    assert "messaging.sms.send" not in pattern["next_candidates"]
    assert "notification.sms" not in pattern["next_candidate_classification"]
    assert pattern["parked_families"] == {}
    assert pattern["current_program_phase"] == 8
    assert pattern["next_candidates"] == ("email.templates",)


def test_notification_sms_contract_is_provider_neutral() -> None:
    props = NOTIFICATION_SMS_INPUT_SCHEMA["properties"]
    assert set(props) == {"destination", "text", "metadata"}
    assert NOTIFICATION_SMS_INPUT_SCHEMA["additionalProperties"] is False
    assert set(NOTIFICATION_SMS_INPUT_SCHEMA["required"]) == {"destination", "text"}
    dest = props["destination"]
    assert dest["x-p2hs"]["kind"] == "e164_recipient"
    assert dest["x-p2hs"]["normalization"] == "e164"
    assert dest["x-p2hs"]["not_sender"] is True
    for leaked in (
        "from",
        "media_url",
        "messaging_service_sid",
        "status_callback",
        "content_sid",
        "to",
        "body",
    ):
        assert leaked not in props
    meta = props["metadata"]
    assert meta["x-p2hs"]["must_not_affect_provider_rendering"] is True
    assert set(NOTIFICATION_SMS_FORBIDDEN_METADATA_KEYS) >= {
        "media_url",
        "from",
        "messaging_service_sid",
        "content_sid",
    }
    assert set(NOTIFICATION_SMS_OUTPUT_SCHEMA["properties"]) == {"message_id", "status"}
    assert "twilio_sid" not in NOTIFICATION_SMS_OUTPUT_SCHEMA["properties"]
    assert "from_number" not in NOTIFICATION_SMS_OUTPUT_SCHEMA["properties"]
    assert set(NOTIFICATION_SMS_ERRORS) >= {
        "capability_not_invocable",
        "capability_not_bound",
        "binding_ambiguous",
        "destination_invalid",
        "sender_unbound",
        "provider_fields_forbidden",
    }


def test_twilio_send_sms_generic_fields_map_and_vendor_fields_stay_off_contract() -> None:
    mapping = TWILIO_NOTIFICATION_SMS_MAPPING
    assert mapping["provider_action"] == "twilio.send_sms"
    assert mapping["status"] == "current_path_audit"
    assert mapping["fields"] == {"destination": "to", "text": "body"}
    assert mapping["sender"]["capability_field"] is None
    assert mapping["sender"]["connection_config"] == ("messaging_service_sid", "from_phone")
    pair = get_action("twilio.send_sms")
    assert pair is not None
    action = pair[1]
    twilio_props = set(action.input_schema.get("properties") or {})
    assert {"to", "body", "from", "media_url"} <= twilio_props
    assert "from" in mapping["unmapped_provider_fields"]
    assert "media_url" in mapping["unmapped_provider_fields"]
    assert "MMS" in mapping["escape_hatch"]
    assert action.implements == ("messaging.sms.send",)
    assert action.required_capabilities == ("integrations.execute",)
    assert slugs_implementing("messaging.sms.send") == ("twilio.send_sms",)
    assert slugs_implementing("notification.sms") == ()


def test_resolver_design_is_contract_mapping_only() -> None:
    design = NOTIFICATION_SMS_RESOLVER_DESIGN
    assert design["template"] == "A"
    assert design["catalog_invocable"] is True
    assert design["implements_attached"] is True
    assert design["codegen_default"] is False
    assert design["not_messaging_send"] is True
    assert design["not_email_first_wins"] is True
    assert design["existing_runtime_path"] == "twilio.send_sms"
    assert design["dispatch"] == "integration.execute"
    assert "twilio.send_sms" in design["candidate_eligibility"]["adapter"]
    assert "messaging.send" in design["candidate_eligibility"]["adapter"]
    selection = design["selection"]
    assert selection["zero"] == "capability_not_bound"
    assert "first-wins" in selection["multiple"]
    sender = design["sender_resolution"]
    assert "connection" in sender["source"]
    assert sender["unbound"].startswith("sender_unbound")
    dest = design["destination_binding"]
    assert "E.164" in dest["input"]
    assert dest["maps_to"].startswith("Twilio Messages API To")
    assert design["flip_order"][0] == "freeze_notification_sms_contract"
    assert design["flip_order"][4] == "core_private_resolver_execution_plan"
    assert design["flip_order"][6] == "dashboard_bff_public_proxy"
    assert "codegen_default_notification_sms_bff_path" in design["flip_order"]
    assert design["public_topology"] == "dashboard_bff_then_private_core"
    assert design["no_installed_app_jobs_route"] is True
    assert set(design["failure_semantics"]) <= set(NOTIFICATION_SMS_ERRORS)
    assert NOTIFICATION_SMS_INVOKE_METHOD.endswith("/capabilities/messaging.sms.send")


def test_manifest_exposes_contract_not_codegen_default() -> None:
    envelope = _connectors_manifest_envelope(items={})
    cap = envelope["capabilities"]["messaging.sms.send"]
    assert cap["status"] == "implemented"
    assert cap["role"] == "default"
    assert cap["invocable"] is True
    assert cap["request_type"] == "integration.execute"
    assert cap["method"].endswith("/capabilities/messaging.sms.send")
    assert cap["implemented_by"] == ["twilio.send_sms"]
    assert is_implemented("messaging.sms.send") is True
    assert "notification.sms" not in envelope["capabilities"]
    compact = _compact_connectors(envelope)
    assert compact["capabilities"]["messaging.sms.send"]["invocable"] is True
    assert compact["capabilities"]["messaging.sms.send"]["role"] == "default"


def test_codegen_still_uses_twilio_send_sms_not_notification_sms() -> None:
    recipes = _app_recipes()
    assert "notification.sms" not in recipes
    assert "capabilities/notification.sms" not in recipes
    assert "POST /api/jobs/notification.sms" not in recipes
    assert "Do not emit `POST /api/jobs/messaging.send`" in recipes
    assert "notification.sms" not in _P2HS_CLOUD_CONTRACT
    assert "notification.sms" not in _P2HS_CORE_API_GUIDANCE
    hints = envelope_actions()
    assert "twilio.send_sms" in hints


def envelope_actions() -> list[str]:
    envelope = _connectors_manifest_envelope(items={})
    return list(envelope["catalog"]["twilio"]["actions"])
