"""8F: caller-side Email Template invocation → Cloud render vars → concrete email.send."""
from __future__ import annotations

import pytest
from pydantic import ValidationError

from src.domain.codegen.email_template_consumption import (
    APP_BLOCK_EMAIL_TEMPLATE_POLICY,
    CONTACT_CAPTURE_ADMIN_NOTIFY,
    CONTACT_CAPTURE_CONFIRMATION,
    EMAIL_TEMPLATE_CONSUMPTION,
    FEATURE_PACK_EMAIL_TEMPLATE_CONSUMPTION,
    INVALID_FIELD_VALUE,
    INVALID_VARIABLE_BINDING,
    MISSING_REQUIRED_VALUE,
    MISSING_REQUIRED_VARIABLE_BINDING,
    SOURCE_FIELD_MISSING,
    SURFACE_CLASSIFICATION,
    UNKNOWN_TEMPLATE_KEY,
    UNKNOWN_TEMPLATE_VARIABLE,
    EmailTemplateInvocation,
    EmailTemplateVariableBinding,
    concrete_email_send_payload,
    resolve_email_template_variables,
)
from src.domain.connectors.invoke_capabilities import CAPABILITY_CONVERSION_PATTERN, FORMS_FAMILY_PLAN
from src.domain.connectors.schemas import InvokeEmailSendRequest
from src.domain.forms.email import FORBIDDEN_EMAIL_CONSTANT_KEYS, FORMS_EMAIL_COMPOSITION
from src.domain.feature_packs.contract import FEATURE_PACK_CONTRACT_VERSION


def test_consumption_contract_keeps_render_off_email_send() -> None:
    assert EMAIL_TEMPLATE_CONSUMPTION["template_key_on_email_send"] is False
    assert EMAIL_TEMPLATE_CONSUMPTION["interpolation"] is False
    assert EMAIL_TEMPLATE_CONSUMPTION["new_email_verb"] is False
    assert EMAIL_TEMPLATE_CONSUMPTION["forms"] == "additive"
    assert EMAIL_TEMPLATE_CONSUMPTION["variable_sources"] == ("literal", "field")
    assert "template_key" in FORBIDDEN_EMAIL_CONSTANT_KEYS
    assert FORMS_EMAIL_COMPOSITION["email_templates"] is False
    assert FORMS_EMAIL_COMPOSITION["interpolation"] is False


def test_known_and_unknown_template_keys() -> None:
    ok = EmailTemplateInvocation(
        template_key="auth.verify_email",
        variables={"action_url": EmailTemplateVariableBinding(source="literal", value="https://example.com/v")},
    )
    assert ok.template_key == "auth.verify_email"
    with pytest.raises(ValidationError, match=UNKNOWN_TEMPLATE_KEY):
        EmailTemplateInvocation(template_key="customer.welcome", variables={})


def test_unknown_and_required_variable_bindings() -> None:
    with pytest.raises(ValidationError, match=UNKNOWN_TEMPLATE_VARIABLE):
        EmailTemplateInvocation(
            template_key="auth.verify_email",
            variables={
                "action_url": EmailTemplateVariableBinding(source="literal", value="https://example.com/v"),
                "debug": EmailTemplateVariableBinding(source="literal", value="x"),
            },
        )
    with pytest.raises(ValidationError, match=MISSING_REQUIRED_VARIABLE_BINDING):
        EmailTemplateInvocation(template_key="auth.otp_request", variables={})
    omitted_optional = EmailTemplateInvocation(template_key="contact_capture.confirmation", variables={})
    assert omitted_optional.variables == {}


def test_invalid_binding_shapes() -> None:
    with pytest.raises(ValidationError, match=INVALID_VARIABLE_BINDING):
        EmailTemplateVariableBinding(source="literal", field="name")
    with pytest.raises(ValidationError, match=INVALID_VARIABLE_BINDING):
        EmailTemplateVariableBinding(source="field", value="Ada")
    with pytest.raises(ValidationError, match=INVALID_VARIABLE_BINDING):
        EmailTemplateVariableBinding(source="field", field="")


def test_literal_and_field_resolution() -> None:
    invocation = EmailTemplateInvocation(
        template_key="auth.verify_email",
        variables={"action_url": EmailTemplateVariableBinding(source="field", field="verify_url")},
    )
    ok = resolve_email_template_variables(invocation, {"verify_url": "https://example.com/v", "debug": "x"})
    assert ok.ok is True
    assert ok.vars == {"action_url": "https://example.com/v"}
    missing = resolve_email_template_variables(invocation, {})
    assert missing.ok is False
    assert missing.error_code == SOURCE_FIELD_MISSING
    empty = resolve_email_template_variables(invocation, {"verify_url": ""})
    assert empty.ok is False
    assert empty.error_code == MISSING_REQUIRED_VALUE
    bad_type = resolve_email_template_variables(invocation, {"verify_url": 1})
    assert bad_type.ok is False
    assert bad_type.error_code == INVALID_FIELD_VALUE


def test_optional_field_omitted_does_not_fail() -> None:
    resolved = resolve_email_template_variables(CONTACT_CAPTURE_CONFIRMATION, {})
    assert resolved.ok is True
    assert resolved.vars == {}
    named = resolve_email_template_variables(CONTACT_CAPTURE_CONFIRMATION, {"name": "Ada"})
    assert named.vars == {"name": "Ada"}
    empty_optional = resolve_email_template_variables(CONTACT_CAPTURE_ADMIN_NOTIFY, {"name": "", "email": "a@b.co"})
    assert empty_optional.ok is True
    assert "name" not in empty_optional.vars
    assert empty_optional.vars["email"] == "a@b.co"


def test_no_second_interpolation_or_pre_escape() -> None:
    invocation = EmailTemplateInvocation(
        template_key="contact_capture.confirmation",
        variables={"name": EmailTemplateVariableBinding(source="literal", value="<b>Ada</b>")},
    )
    resolved = resolve_email_template_variables(invocation, {})
    assert resolved.vars["name"] == "<b>Ada</b>"
    assert "&lt;" not in resolved.vars["name"]


def test_failed_resolution_must_not_build_send_payload() -> None:
    invocation = EmailTemplateInvocation(
        template_key="auth.magic_link",
        variables={"action_url": EmailTemplateVariableBinding(source="field", field="link")},
    )
    failed = resolve_email_template_variables(invocation, {})
    assert failed.ok is False
    assert failed.vars == {}


def test_rendered_handoff_is_concrete_email_send() -> None:
    payload = concrete_email_send_payload(
        to="ada@example.com",
        rendered={"subject": "Hi", "text": "Body", "html": "<p>Ada</p>", "used_default": True, "template_key": "nope"},
        reply_to="ops@example.com",
    )
    assert payload == {
        "to": "ada@example.com",
        "subject": "Hi",
        "text": "Body",
        "html": "<p>Ada</p>",
        "reply_to": "ops@example.com",
    }
    assert set(payload) <= set(InvokeEmailSendRequest.model_fields)
    assert "template_key" not in payload
    assert "vars" not in payload
    assert "used_default" not in payload


def test_contact_capture_pack_consumption_is_canonical() -> None:
    invocations = FEATURE_PACK_EMAIL_TEMPLATE_CONSUMPTION["contact-capture"]
    assert invocations == (CONTACT_CAPTURE_ADMIN_NOTIFY, CONTACT_CAPTURE_CONFIRMATION)
    assert CONTACT_CAPTURE_ADMIN_NOTIFY.template_key == "contact_capture.admin_notify"
    assert CONTACT_CAPTURE_CONFIRMATION.variables["name"].source == "field"
    assert FEATURE_PACK_CONTRACT_VERSION == 2
    assert APP_BLOCK_EMAIL_TEMPLATE_POLICY["forms.contact"]["template_keys"] == ()
    assert "email.send" in APP_BLOCK_EMAIL_TEMPLATE_POLICY["forms.contact"]["requires"]
    assert SURFACE_CLASSIFICATION["email_template_invocation"] == "canonical"
    assert SURFACE_CLASSIFICATION["contact_capture_notify_function"] == "supported"
    assert SURFACE_CLASSIFICATION["forms_7j"] == "unchanged"
    assert SURFACE_CLASSIFICATION["forms_template_mode"] == "canonical"
    assert SURFACE_CLASSIFICATION["legacy_api_contact"] == "compatibility_only"


def test_cloud_render_route_still_owns_runtime() -> None:
    from pathlib import Path

    route = (
        Path(__file__).resolve().parents[1].parent
        / "P2HSCloud"
        / "apps"
        / "pc-gateway"
        / "src"
        / "routes"
        / "email-templates.ts"
    ).read_text(encoding="utf-8")
    assert "renderEmailTemplate(" in route
    assert "template_key" in route.lower() or "templateKey" in route


def test_tracker_advances_past_8f() -> None:
    assert CAPABILITY_CONVERSION_PATTERN["phase_8e_status"] == "complete"
    assert CAPABILITY_CONVERSION_PATTERN["phase_8f_status"] == "complete"
    assert CAPABILITY_CONVERSION_PATTERN["next_program_slice"] == "9_app_block_modernization"
    assert FORMS_FAMILY_PLAN["next_slice"] == "9_app_block_modernization"
    assert FORMS_EMAIL_COMPOSITION["status"] == "frozen"
    assert CAPABILITY_CONVERSION_PATTERN["phase_7_status"] == "complete"
