"""7L Forms conditional logic: typed rules over canonical values."""
from __future__ import annotations

import inspect
from datetime import UTC, datetime
from pathlib import Path

from src.domain.connectors.invoke_capabilities import (
    CAPABILITY_CONVERSION_PATTERN,
    FORMS_FAMILY_PLAN,
)
from src.domain.forms.actions import (
    FormCapabilityInvokeResult,
    FormPostSubmitContext,
    FormPostSubmitPlan,
    RecordingCapabilityInvoker,
    contact_compatible_plan,
    execute_post_submit_actions,
)
from src.domain.forms.automation import automation_workflow_action
from src.domain.forms.canonical import (
    FormDefinition,
    FormField,
    FormFieldOption,
    contact_block_compatible_definition,
    quote_request_block_compatible_definition,
)
from src.domain.forms.conditions import (
    CONDITION_NOT_MET,
    CONDITIONAL_FIELD_NOT_ALLOWED,
    CONDITIONAL_RULE_INVALID,
    FORMS_CONDITIONAL_LOGIC,
    HIDDEN_FIELD_POLICY,
    ActionConditionalRule,
    FieldConditionalRule,
    FormCondition,
    FormConditionSet,
    evaluate_action_conditions,
    evaluate_field_conditions,
    validate_condition_rules,
)
from src.domain.forms.crm import NO_EMAIL_CODE, crm_contact_upsert_action
from src.domain.forms.email import NO_RECIPIENT_CODE, email_send_action
from src.domain.forms.forward import http_forward_action
from src.domain.forms.runtime import accept_form_submission

_FIXED_AT = datetime(2026, 9, 13, 22, 0, tzinfo=UTC)
_FSB = "fsb_" + ("c" * 32)
_CTX = FormPostSubmitContext(project_id="prj_a")
_SAFE_TARGET = "https://example.com/webhook"


def _lead_form() -> FormDefinition:
    return FormDefinition(
        key="lead",
        fields=[
            FormField(
                key="contact_method",
                type="select",
                required=True,
                options=[
                    FormFieldOption(value="email", label="Email"),
                    FormFieldOption(value="phone", label="Phone"),
                ],
            ),
            FormField(key="email", type="email", required=False),
            FormField(key="phone", type="phone", required=False),
            FormField(key="has_company", type="checkbox", required=False),
            FormField(key="company_name", type="text", required=False),
            FormField(key="opt_in", type="checkbox", required=False),
            FormField(key="count", type="number", required=False),
            FormField(key="note", type="text", required=False),
            FormField(key="role", type="hidden", required=False),
            FormField(key="staff_code", type="text", required=False),
            FormField(key="message", type="textarea", required=False),
        ],
    )


def _phone_rules() -> FormConditionSet:
    phone_eq = FormCondition(field_key="contact_method", operator="equals", value="phone")
    return FormConditionSet(
        field_rules=(
            FieldConditionalRule(
                target_field="phone", effect="show_when", condition=phone_eq
            ),
            FieldConditionalRule(
                target_field="phone", effect="require_when", condition=phone_eq
            ),
        )
    )


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


def test_7l_conditional_logic_frozen() -> None:
    assert FORMS_CONDITIONAL_LOGIC["status"] == "frozen"
    assert FORMS_CONDITIONAL_LOGIC["expression_language"] is None
    assert FORMS_CONDITIONAL_LOGIC["coercion"] is False
    assert FORMS_CONDITIONAL_LOGIC["hidden_field_policy"] == HIDDEN_FIELD_POLICY == "reject"
    assert FORMS_CONDITIONAL_LOGIC["cross_action_dependencies"] is False
    assert FORMS_CONDITIONAL_LOGIC["routing_mutation"] is False
    assert FORMS_CONDITIONAL_LOGIC["file_sources"] is False
    assert FORMS_CONDITIONAL_LOGIC["public_bff"] is False
    assert FORMS_CONDITIONAL_LOGIC["codegen"] is False
    assert CAPABILITY_CONVERSION_PATTERN["phase_7_status"] == "complete"
    assert CAPABILITY_CONVERSION_PATTERN["next_program_slice"] == "9_app_block_modernization"
    assert CAPABILITY_CONVERSION_PATTERN["opened_families"]["forms.*"] == (
        "composition_integration"
    )
    assert FORMS_FAMILY_PLAN["status"] == "complete"
    assert FORMS_FAMILY_PLAN["conditional_logic_frozen"] is True
    assert FORMS_FAMILY_PLAN["slices"][11] == "7l_conditional_logic"
    assert FORMS_FAMILY_PLAN["next_slice"] == "9_app_block_modernization"
    src = Path("src/domain/forms/conditions.py").read_text(encoding="utf-8").lower()
    for banned in ("eval(", "jsonlogic", "jmespath", "cel", "jsonpath"):
        assert banned not in src
    params = inspect.signature(evaluate_action_conditions).parameters
    assert list(params) == ["values", "rules", "action_keys"]


def test_contact_and_quote_remain_unconditional() -> None:
    contact = contact_block_compatible_definition()
    quote = quote_request_block_compatible_definition()
    empty = FormConditionSet()
    assert validate_condition_rules(empty, contact) == ()
    assert validate_condition_rules(empty, quote) == ()
    accepted = _accept(
        contact,
        {"name": "Ada", "email": "ada@example.com", "message": "Hello"},
        conditions=empty,
    )
    assert "phone" not in accepted.submission.values
    plan = contact_compatible_plan()
    invoker = RecordingCapabilityInvoker()
    result = execute_post_submit_actions(
        accepted,
        plan,
        context=_CTX,
        invoker=invoker,
        definition=contact,
        conditions=empty,
    )
    assert all(
        item.status != "skipped" or item.error_code != CONDITION_NOT_MET
        for item in result.actions
    )


def test_conditional_requiredness_uses_7c_required() -> None:
    definition = _lead_form()
    rules = _phone_rules()
    missing_phone = accept_form_submission(
        definition,
        {"contact_method": "phone", "email": "ada@example.com"},
        conditions=rules,
    )
    assert missing_phone.accepted is False
    assert any(
        err.field == "phone" and err.code == "required" for err in missing_phone.errors
    )
    email_ok = accept_form_submission(
        definition,
        {"contact_method": "email", "email": "ada@example.com"},
        conditions=rules,
    )
    assert email_ok.accepted is True
    assert "phone" not in email_ok.submission.submission.values


def test_hidden_field_submitted_is_rejected_not_unknown() -> None:
    definition = _lead_form()
    rules = _phone_rules()
    result = accept_form_submission(
        definition,
        {
            "contact_method": "email",
            "email": "ada@example.com",
            "phone": "+1 555 0100",
        },
        conditions=rules,
    )
    assert result.accepted is False
    assert any(
        err.field == "phone" and err.code == CONDITIONAL_FIELD_NOT_ALLOWED
        for err in result.errors
    )
    assert all(err.code != "unknown_field" for err in result.errors)


def test_checkbox_false_is_not_missing() -> None:
    definition = _lead_form()
    rules = FormConditionSet(
        field_rules=(
            FieldConditionalRule(
                target_field="company_name",
                effect="show_when",
                condition=FormCondition(
                    field_key="has_company", operator="equals", value=True
                ),
            ),
        )
    )
    hidden = accept_form_submission(
        definition,
        {"contact_method": "email", "email": "a@b.co", "has_company": False},
        conditions=rules,
    )
    assert hidden.accepted is True
    rejected = accept_form_submission(
        definition,
        {
            "contact_method": "email",
            "email": "a@b.co",
            "has_company": False,
            "company_name": "Acme",
        },
        conditions=rules,
    )
    assert rejected.accepted is False
    assert rejected.errors[0].code == CONDITIONAL_FIELD_NOT_ALLOWED
    shown = _accept(
        definition,
        {
            "contact_method": "email",
            "email": "a@b.co",
            "has_company": True,
            "company_name": "Acme",
        },
        conditions=rules,
    )
    assert shown.submission.values["company_name"] == "Acme"
    assert shown.submission.values["has_company"] is True


def test_number_zero_is_not_missing() -> None:
    definition = _lead_form()
    rules = FormConditionSet(
        field_rules=(
            FieldConditionalRule(
                target_field="note",
                effect="show_when",
                condition=FormCondition(field_key="count", operator="equals", value=0),
            ),
        )
    )
    state = evaluate_field_conditions(definition, {"count": 0}, rules)
    assert "note" in state.visible_fields
    missing = evaluate_field_conditions(definition, {}, rules)
    assert "note" not in missing.visible_fields


def test_null_is_not_missing() -> None:
    definition = _lead_form()
    eq_null = FormCondition(field_key="note", operator="equals", value=None)
    missing = FormCondition(field_key="note", operator="is_missing")
    present = FormCondition(field_key="note", operator="is_present")
    null_state = evaluate_field_conditions(
        definition,
        {"note": None, "contact_method": "email"},
        FormConditionSet(
            field_rules=(
                FieldConditionalRule(
                    target_field="staff_code", effect="show_when", condition=eq_null
                ),
            )
        ),
    )
    assert "staff_code" in null_state.visible_fields
    miss_state = evaluate_field_conditions(
        definition,
        {"contact_method": "email"},
        FormConditionSet(
            field_rules=(
                FieldConditionalRule(
                    target_field="staff_code", effect="show_when", condition=missing
                ),
            )
        ),
    )
    assert "staff_code" in miss_state.visible_fields
    present_on_null = evaluate_field_conditions(
        definition,
        {"note": None},
        FormConditionSet(
            field_rules=(
                FieldConditionalRule(
                    target_field="staff_code", effect="show_when", condition=present
                ),
            )
        ),
    )
    assert "staff_code" in present_on_null.visible_fields
    present_on_missing = evaluate_field_conditions(
        definition,
        {},
        FormConditionSet(
            field_rules=(
                FieldConditionalRule(
                    target_field="staff_code", effect="show_when", condition=present
                ),
            )
        ),
    )
    assert "staff_code" not in present_on_missing.visible_fields


def test_no_coercion_false_and_zero_are_distinct() -> None:
    definition = _lead_form()
    rules = FormConditionSet(
        field_rules=(
            FieldConditionalRule(
                target_field="note",
                effect="show_when",
                condition=FormCondition(field_key="count", operator="equals", value=0),
            ),
        )
    )
    assert "note" in evaluate_field_conditions(definition, {"count": 0}, rules).visible_fields
    assert "note" not in evaluate_field_conditions(
        definition, {"count": False}, rules
    ).visible_fields
    # 7C numeric-literal normalization, not loose equality: "0" on a number field is 0.
    assert "note" in evaluate_field_conditions(definition, {"count": "0"}, rules).visible_fields
    bool_rules = FormConditionSet(
        field_rules=(
            FieldConditionalRule(
                target_field="note",
                effect="show_when",
                condition=FormCondition(
                    field_key="has_company", operator="equals", value=False
                ),
            ),
        )
    )
    assert "note" in evaluate_field_conditions(
        definition, {"has_company": False}, bool_rules
    ).visible_fields
    assert "note" not in evaluate_field_conditions(
        definition, {"has_company": 0}, bool_rules
    ).visible_fields


def test_unknown_source_and_type_mismatch_are_config_errors() -> None:
    definition = _lead_form()
    unknown = FormConditionSet(
        field_rules=(
            FieldConditionalRule(
                target_field="phone",
                effect="show_when",
                condition=FormCondition(
                    field_key="does_not_exist", operator="equals", value="x"
                ),
            ),
        )
    )
    assert CONDITIONAL_RULE_INVALID in validate_condition_rules(unknown, definition)
    mismatch = FormConditionSet(
        field_rules=(
            FieldConditionalRule(
                target_field="company_name",
                effect="show_when",
                condition=FormCondition(
                    field_key="has_company", operator="equals", value="yes"
                ),
            ),
        )
    )
    assert CONDITIONAL_RULE_INVALID in validate_condition_rules(mismatch, definition)
    file_form = FormDefinition(
        key="lead",
        fields=[
            FormField(key="resume", type="file", required=False),
            FormField(key="note", type="text", required=False),
        ],
    )
    file_src = FormConditionSet(
        field_rules=(
            FieldConditionalRule(
                target_field="note",
                effect="show_when",
                condition=FormCondition(field_key="resume", operator="is_present"),
            ),
        )
    )
    assert CONDITIONAL_RULE_INVALID in validate_condition_rules(file_src, file_form)
    self_dep = FormConditionSet(
        field_rules=(
            FieldConditionalRule(
                target_field="phone",
                effect="show_when",
                condition=FormCondition(field_key="phone", operator="is_present"),
            ),
        )
    )
    assert CONDITIONAL_RULE_INVALID in validate_condition_rules(self_dep, definition)
    dup = FormConditionSet(
        field_rules=(
            FieldConditionalRule(
                target_field="phone",
                effect="show_when",
                condition=FormCondition(
                    field_key="contact_method", operator="equals", value="phone"
                ),
            ),
            FieldConditionalRule(
                target_field="phone",
                effect="show_when",
                condition=FormCondition(
                    field_key="contact_method", operator="equals", value="email"
                ),
            ),
        )
    )
    assert CONDITIONAL_RULE_INVALID in validate_condition_rules(dup, definition)
    cycle = FormConditionSet(
        field_rules=(
            FieldConditionalRule(
                target_field="phone",
                effect="show_when",
                condition=FormCondition(
                    field_key="email", operator="is_present"
                ),
            ),
            FieldConditionalRule(
                target_field="email",
                effect="show_when",
                condition=FormCondition(
                    field_key="phone", operator="is_present"
                ),
            ),
        )
    )
    assert CONDITIONAL_RULE_INVALID in validate_condition_rules(cycle, definition)
    unknown_action = FormConditionSet(
        action_rules=(
            ActionConditionalRule(
                action_key="not_in_plan",
                condition=FormCondition(field_key="opt_in", operator="equals", value=True),
            ),
        )
    )
    assert CONDITIONAL_RULE_INVALID in validate_condition_rules(
        unknown_action, definition, action_keys=("send_confirmation",)
    )


def test_hidden_source_is_untrusted_client_data() -> None:
    definition = _lead_form()
    rules = FormConditionSet(
        field_rules=(
            FieldConditionalRule(
                target_field="staff_code",
                effect="show_when",
                condition=FormCondition(field_key="role", operator="equals", value="admin"),
            ),
        )
    )
    spoofed = _accept(
        definition,
        {
            "contact_method": "email",
            "email": "a@b.co",
            "role": "admin",
            "staff_code": "SECRET",
        },
        conditions=rules,
    )
    assert spoofed.submission.values["role"] == "admin"
    assert spoofed.submission.values["staff_code"] == "SECRET"


def test_action_eligibility_skip_does_not_invoke() -> None:
    definition = _lead_form()
    accepted = _accept(
        definition,
        {"contact_method": "email", "email": "ada@example.com", "opt_in": False},
    )
    plan = FormPostSubmitPlan(actions=(email_send_action(),))
    rules = FormConditionSet(
        action_rules=(
            ActionConditionalRule(
                action_key="send_confirmation",
                condition=FormCondition(field_key="opt_in", operator="equals", value=True),
            ),
        )
    )
    invoker = RecordingCapabilityInvoker()
    result = execute_post_submit_actions(
        accepted,
        plan,
        context=_CTX,
        invoker=invoker,
        definition=definition,
        conditions=rules,
    )
    assert result.actions[0].status == "skipped"
    assert result.actions[0].error_code == CONDITION_NOT_MET
    assert result.actions[0].idempotency_key == f"{_FSB}:send_confirmation"
    assert invoker.calls == []
    opted = _accept(
        definition,
        {
            "contact_method": "email",
            "email": "ada@example.com",
            "opt_in": True,
            "message": "Hi",
        },
    )
    invoker2 = RecordingCapabilityInvoker()
    execute_post_submit_actions(
        opted,
        plan,
        context=_CTX,
        invoker=invoker2,
        definition=definition,
        conditions=rules,
    )
    assert len(invoker2.calls) == 1
    assert "workflow" not in invoker2.calls[0]["payload"]
    assert "target" not in invoker2.calls[0]["payload"]
    assert "provider_hint" not in invoker2.calls[0]["payload"]


def test_crm_email_automation_skip_reasons_stay_distinct() -> None:
    definition = _lead_form()
    plan = FormPostSubmitPlan(
        actions=(
            crm_contact_upsert_action(),
            email_send_action(),
            automation_workflow_action(mapping={"message": "message"}),
            http_forward_action(target=_SAFE_TARGET, mapping={"email": "email"}),
        )
    )
    rules = FormConditionSet(
        action_rules=(
            ActionConditionalRule(
                action_key="sync_crm",
                condition=FormCondition(field_key="opt_in", operator="equals", value=True),
            ),
            ActionConditionalRule(
                action_key="send_confirmation",
                condition=FormCondition(field_key="opt_in", operator="equals", value=True),
            ),
            ActionConditionalRule(
                action_key="notify_automation",
                condition=FormCondition(field_key="opt_in", operator="equals", value=True),
            ),
        )
    )
    skipped = _accept(
        definition,
        {"contact_method": "email", "email": "ada@example.com", "opt_in": False},
    )
    invoker = RecordingCapabilityInvoker()
    result = execute_post_submit_actions(
        skipped,
        plan,
        context=_CTX,
        invoker=invoker,
        definition=definition,
        conditions=rules,
    )
    by_key = {item.action_key: item for item in result.actions}
    assert by_key["sync_crm"].error_code == CONDITION_NOT_MET
    assert by_key["send_confirmation"].error_code == CONDITION_NOT_MET
    assert by_key["notify_automation"].error_code == CONDITION_NOT_MET
    assert by_key["forward"].status == "succeeded"
    assert len(invoker.calls) == 1
    assert invoker.calls[0]["capability"] == "internal.http_forward"

    no_email = _accept(
        definition,
        {"contact_method": "phone", "phone": "+1 555 0100", "opt_in": True},
    )
    result2 = execute_post_submit_actions(
        no_email,
        plan,
        context=_CTX,
        invoker=RecordingCapabilityInvoker(
            outcomes={
                "automation.workflow.trigger": FormCapabilityInvokeResult(
                    status="failed", error_code="workflow_unbound"
                )
            }
        ),
        definition=definition,
        conditions=rules,
    )
    by_key2 = {item.action_key: item for item in result2.actions}
    assert by_key2["sync_crm"].error_code == NO_EMAIL_CODE
    assert by_key2["send_confirmation"].error_code == NO_RECIPIENT_CODE
    assert by_key2["notify_automation"].error_code == "workflow_unbound"
    assert by_key2["notify_automation"].status == "failed"


def test_conditions_do_not_rewrite_accepted_values() -> None:
    definition = _lead_form()
    accepted = _accept(
        definition,
        {"contact_method": "email", "email": "ada@example.com", "opt_in": True, "count": 0},
    )
    original = dict(accepted.submission.values)
    execute_post_submit_actions(
        accepted,
        FormPostSubmitPlan(actions=(email_send_action(),)),
        context=_CTX,
        invoker=RecordingCapabilityInvoker(),
        definition=definition,
        conditions=FormConditionSet(
            action_rules=(
                ActionConditionalRule(
                    action_key="send_confirmation",
                    condition=FormCondition(
                        field_key="opt_in", operator="equals", value=True
                    ),
                ),
            )
        ),
    )
    assert accepted.submission.values == original
    assert "_action_send_confirmation_eligible" not in accepted.submission.values
