"""8G additive Forms Email Template consumption. Literal 7J remains valid."""
from __future__ import annotations

from datetime import UTC, datetime

import pytest
from pydantic import ValidationError

from src.domain.codegen.email_template_consumption import (
    CONTACT_CAPTURE_CONFIRMATION,
    MISSING_REQUIRED_VARIABLE_BINDING,
    UNKNOWN_TEMPLATE_KEY,
    UNKNOWN_TEMPLATE_VARIABLE,
    EmailTemplateInvocation,
    EmailTemplateVariableBinding,
)
from src.domain.connectors.invoke_capabilities import CAPABILITY_CONVERSION_PATTERN, FORMS_FAMILY_PLAN
from src.domain.connectors.schemas import InvokeEmailSendRequest
from src.domain.feature_packs.catalog_v2 import CATALOG_OVERLAYS
from src.domain.forms.actions import (
    FormPostSubmitAction,
    FormPostSubmitContext,
    FormPostSubmitPlan,
    RecordingCapabilityInvoker,
    execute_post_submit_actions,
    validate_post_submit_plan,
)
from src.domain.forms.canonical import FormDefinition, FormField
from src.domain.forms.composition import _contact_plan
from src.domain.forms.email import FORMS_EMAIL_COMPOSITION, build_email_send_payload, email_send_action
from src.domain.forms.email_template import (
    CONFLICTING_CONTENT_MODE,
    FORMS_EMAIL_TEMPLATE_CONSUMPTION,
    TEMPLATE_RENDER_FAILED,
    RecordingEmailTemplateRenderer,
    email_send_template_action,
    validate_email_template_mapping,
)
from src.domain.forms.runtime import accept_form_submission

_FIXED_AT = datetime(2026, 9, 14, 1, 0, tzinfo=UTC)
_FSB = "fsb_" + ("c" * 32)
_CTX = FormPostSubmitContext(project_id="prj_forms_8g")


def _definition() -> FormDefinition:
    return FormDefinition(
        key="lead",
        fields=[
            FormField(key="name", type="text", required=False),
            FormField(key="email", type="email", required=False),
            FormField(key="message", type="textarea", required=False),
        ],
    )


def _accept(definition, raw):
    result = accept_form_submission(
        definition,
        raw,
        clock=lambda: _FIXED_AT,
        submission_id_factory=lambda: _FSB,
    )
    assert result.accepted is True
    return result.submission


def test_8g_contract_is_additive() -> None:
    assert FORMS_EMAIL_COMPOSITION["status"] == "frozen"
    assert FORMS_EMAIL_COMPOSITION["email_templates"] is False
    assert FORMS_EMAIL_COMPOSITION["interpolation"] is False
    assert FORMS_EMAIL_COMPOSITION["template_consumption"] == "additive"
    assert FORMS_EMAIL_TEMPLATE_CONSUMPTION["literal_mode"] == "preserved_7j"
    assert FORMS_EMAIL_TEMPLATE_CONSUMPTION["exclusivity"] == "literal_xor_template"
    assert FORMS_EMAIL_TEMPLATE_CONSUMPTION["invocation"] == "EmailTemplateInvocation"
    assert FORMS_EMAIL_TEMPLATE_CONSUMPTION["contact_capture_migrated"] is False
    assert CAPABILITY_CONVERSION_PATTERN["phase_8g_status"] == "complete"
    assert CAPABILITY_CONVERSION_PATTERN["next_program_slice"] == (
        "9_app_block_modernization"
    )
    assert FORMS_FAMILY_PLAN["next_slice"] == "9_app_block_modernization"


def test_literal_7j_still_sends_without_renderer() -> None:
    definition = _definition()
    accepted = _accept(definition, {"email": "ada@example.com", "message": "Hello {{name}}"})
    invoker = RecordingCapabilityInvoker()
    result = execute_post_submit_actions(
        accepted,
        FormPostSubmitPlan(
            actions=(
                email_send_action(
                    mapping={"to": "email", "text": "message"},
                    constants={"subject": "Thanks {{name}}"},
                ),
            )
        ),
        context=_CTX,
        invoker=invoker,
        definition=definition,
    )
    assert result.actions[0].status == "succeeded"
    payload = invoker.calls[0]["payload"]
    assert payload["subject"] == "Thanks {{name}}"
    assert payload["text"] == "Hello {{name}}"
    assert "template_key" not in payload


def test_known_template_key_and_bindings() -> None:
    definition = _definition()
    action = email_send_template_action(
        key="confirm",
        invocation=CONTACT_CAPTURE_CONFIRMATION,
        mapping={"to": "email"},
    )
    assert validate_email_template_mapping(action, definition) == ()
    assert validate_post_submit_plan(FormPostSubmitPlan(actions=(action,)), definition) == ()


def test_unknown_template_key_rejected_statically() -> None:
    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="contact_capture.confirmation",
            variables={
                "name": EmailTemplateVariableBinding(source="field", field="name"),
                "nickname": EmailTemplateVariableBinding(source="field", field="name"),
            },
        )
    with pytest.raises(ValidationError, match=MISSING_REQUIRED_VARIABLE_BINDING):
        EmailTemplateInvocation(template_key="auth.verify_email", variables={})


def test_conflicting_literal_and_template_rejected() -> None:
    definition = _definition()
    action = FormPostSubmitAction(
        key="confirm",
        action_type="email.send",
        mapping={"to": "email", "text": "message"},
        constants={"subject": "Hi"},
        template=CONTACT_CAPTURE_CONFIRMATION,
    )
    errors = validate_email_template_mapping(action, definition)
    assert CONFLICTING_CONTENT_MODE in errors


def test_template_mode_field_and_literal_bindings_render_then_send() -> None:
    definition = _definition()
    accepted = _accept(
        definition,
        {"name": "Ada", "email": "ada@example.com", "message": "Hi"},
    )
    action = email_send_template_action(
        key="confirm",
        invocation=EmailTemplateInvocation(
            template_key="contact_capture.confirmation",
            variables={
                "name": EmailTemplateVariableBinding(source="field", field="name"),
            },
        ),
        mapping={"to": "email"},
        constants={"reply_to": "ops@example.com"},
    )
    renderer = RecordingEmailTemplateRenderer(
        {
            "subject": "Thanks Ada",
            "text": "We got it",
            "html": "<p>Ada</p>",
            "template_key": "must-drop",
            "used_default": True,
        }
    )
    invoker = RecordingCapabilityInvoker()
    result = execute_post_submit_actions(
        accepted,
        FormPostSubmitPlan(actions=(action,)),
        context=_CTX,
        invoker=invoker,
        definition=definition,
        email_template_renderer=renderer,
    )
    assert result.actions[0].status == "succeeded"
    assert renderer.calls[0]["template_key"] == "contact_capture.confirmation"
    assert renderer.calls[0]["vars"] == {"name": "Ada"}
    payload = invoker.calls[0]["payload"]
    assert payload == {
        "to": "ada@example.com",
        "subject": "Thanks Ada",
        "text": "We got it",
        "html": "<p>Ada</p>",
        "reply_to": "ops@example.com",
    }
    assert set(payload) <= set(InvokeEmailSendRequest.model_fields)
    assert "template_key" not in payload
    assert "variables" not in payload
    assert "used_default" not in payload


def test_forms_does_not_pre_escape_mapped_values() -> None:
    definition = _definition()
    accepted = _accept(
        definition,
        {
            "name": "<script>alert(1)</script>",
            "email": "ada@example.com",
            "message": "<img src=x onerror=alert(1)>",
        },
    )
    action = email_send_template_action(
        key="admin",
        invocation=EmailTemplateInvocation(
            template_key="contact_capture.admin_notify",
            variables={
                "name": EmailTemplateVariableBinding(source="field", field="name"),
                "email": EmailTemplateVariableBinding(source="field", field="email"),
                "message": EmailTemplateVariableBinding(source="field", field="message"),
            },
        ),
        constants={"to": "ops@example.com"},
    )
    renderer = RecordingEmailTemplateRenderer()
    execute_post_submit_actions(
        accepted,
        FormPostSubmitPlan(actions=(action,)),
        context=_CTX,
        invoker=RecordingCapabilityInvoker(),
        definition=definition,
        email_template_renderer=renderer,
    )
    assert renderer.calls[0]["vars"]["name"] == "<script>alert(1)</script>"
    assert renderer.calls[0]["vars"]["message"] == "<img src=x onerror=alert(1)>"
    assert "&lt;" not in renderer.calls[0]["vars"]["name"]


def test_render_failure_does_not_send() -> None:
    definition = _definition()
    accepted = _accept(definition, {"email": "ada@example.com"})
    action = email_send_template_action(
        key="verify",
        invocation=EmailTemplateInvocation(
            template_key="auth.verify_email",
            variables={
                "action_url": EmailTemplateVariableBinding(source="field", field="email"),
            },
        ),
        mapping={"to": "email"},
    )
    renderer = RecordingEmailTemplateRenderer(error_code="missing_required_variable")
    invoker = RecordingCapabilityInvoker()
    result = execute_post_submit_actions(
        accepted,
        FormPostSubmitPlan(actions=(action,)),
        context=_CTX,
        invoker=invoker,
        definition=definition,
        email_template_renderer=renderer,
    )
    assert result.actions[0].status == "failed"
    assert result.actions[0].error_code == "missing_required_variable"
    assert invoker.calls == []
    built = build_email_send_payload(
        action,
        {"email": "ada@example.com"},
        renderer=RecordingEmailTemplateRenderer(error_code=TEMPLATE_RENDER_FAILED),
        project_id="prj_forms_8g",
    )
    assert built.payload is None
    assert built.error_code == TEMPLATE_RENDER_FAILED


def test_missing_runtime_field_fails_before_send_for_required_var() -> None:
    definition = _definition()
    accepted = _accept(definition, {"email": "ada@example.com"})
    action = email_send_template_action(
        key="verify",
        invocation=EmailTemplateInvocation(
            template_key="auth.magic_link",
            variables={
                "action_url": EmailTemplateVariableBinding(source="field", field="message"),
            },
        ),
        mapping={"to": "email"},
    )
    invoker = RecordingCapabilityInvoker()
    result = execute_post_submit_actions(
        accepted,
        FormPostSubmitPlan(actions=(action,)),
        context=_CTX,
        invoker=invoker,
        definition=definition,
        email_template_renderer=RecordingEmailTemplateRenderer(),
    )
    assert result.actions[0].status == "failed"
    assert result.actions[0].error_code == "source_field_missing"
    assert invoker.calls == []


def test_enabled_false_is_not_forms_suppression() -> None:
    definition = _definition()
    accepted = _accept(definition, {"email": "ada@example.com"})
    action = email_send_template_action(
        key="confirm",
        invocation=CONTACT_CAPTURE_CONFIRMATION,
        mapping={"to": "email"},
    )
    renderer = RecordingEmailTemplateRenderer(
        {"subject": "Default confirmation", "text": "Default body"}
    )
    invoker = RecordingCapabilityInvoker()
    execute_post_submit_actions(
        accepted,
        FormPostSubmitPlan(actions=(action,)),
        context=_CTX,
        invoker=invoker,
        definition=definition,
        email_template_renderer=renderer,
    )
    assert invoker.calls[0]["payload"]["subject"] == "Default confirmation"
    assert "enabled" not in invoker.calls[0]["payload"]


def test_template_field_must_exist_on_form() -> None:
    definition = _definition()
    action = email_send_template_action(
        key="confirm",
        invocation=EmailTemplateInvocation(
            template_key="contact_capture.confirmation",
            variables={
                "name": EmailTemplateVariableBinding(source="field", field="customer_name"),
            },
        ),
        mapping={"to": "email"},
    )
    assert "unknown_source_field" in validate_email_template_mapping(action, definition)


def test_contact_composition_uses_canonical_template_actions() -> None:
    plan = _contact_plan(
        {"notify_to_email": "ops@example.com", "send_confirmation_email": True}
    )
    email_actions = [action for action in plan.actions if action.action_type == "email.send"]
    assert len(email_actions) == 2
    assert email_actions[0].template is not None
    assert email_actions[0].template.template_key == "contact_capture.admin_notify"
    assert email_actions[1].template.template_key == "contact_capture.confirmation"
    assert "contact-capture" in CATALOG_OVERLAYS
