"""7E Forms persistence/retrieval. Domain contract; no SQL schema yet."""
from __future__ import annotations

from datetime import UTC, datetime
from pathlib import Path

import pytest
from src.domain.connectors.invoke_capabilities import (
    CAPABILITY_CONVERSION_PATTERN,
    FORMS_FAMILY_PLAN,
    INVOKE_CAPABILITIES,
)
from src.domain.forms.canonical import (
    FORBIDDEN_PROVIDER_TOKENS,
    FormDefinition,
    FormField,
    FormSubmission,
    contact_block_compatible_definition,
)
from src.domain.forms.persistence import (
    FORMS_PERSISTENCE,
    FormPersistenceContext,
    FormPersistenceError,
    FormSubmissionStorageRef,
    InMemoryFormSubmissionStore,
    PersistedFormSubmission,
    get_form_submission,
    persist_form_submission,
)
from src.domain.forms.runtime import AcceptedFormSubmission, accept_form_submission

_FIXED_ACCEPTED = datetime(2026, 9, 13, 12, 0, tzinfo=UTC)
_FIXED_PERSISTED = datetime(2026, 9, 13, 12, 5, tzinfo=UTC)
_ID_A = "fsb_" + ("a" * 32)
_ID_B = "fsb_" + ("b" * 32)
_CTX = FormPersistenceContext(project_id="prj_forms_7e")
_OTHER = FormPersistenceContext(project_id="prj_other")


def _accept(
    raw: dict,
    *,
    submission_id: str = _ID_A,
    definition: FormDefinition | None = None,
) -> AcceptedFormSubmission:
    result = accept_form_submission(
        definition or contact_block_compatible_definition(),
        raw,
        submission_id_factory=lambda: submission_id,
        clock=lambda: _FIXED_ACCEPTED,
    )
    assert result.accepted is True
    assert result.submission is not None
    return result.submission


def _contact_raw() -> dict:
    return {
        "name": "  Jane  ",
        "email": " Jane@Example.COM ",
        "message": "Hello",
    }


def test_7e_persistence_is_durable_without_public_surface() -> None:
    assert FORMS_PERSISTENCE["status"] == "frozen"
    assert FORMS_PERSISTENCE["persistence_optional"] is False
    assert FORMS_PERSISTENCE["canonical_store_required"] is True
    assert FORMS_PERSISTENCE["physical_schema"] == "core_postgres.form_submissions"
    assert FORMS_PERSISTENCE["schema_migration"] is True
    assert FORMS_PERSISTENCE["contact_submission_is_canonical"] is False
    assert FORMS_PERSISTENCE["composed_entity_id_is_forms_identity"] is False
    assert FORMS_PERSISTENCE["list_search"] is True
    assert "form.submit" not in INVOKE_CAPABILITIES
    assert CAPABILITY_CONVERSION_PATTERN["phase_7_status"] == "complete"
    assert CAPABILITY_CONVERSION_PATTERN["next_program_slice"] == "9_app_block_modernization"
    assert FORMS_FAMILY_PLAN["slices"][4] == "7e_persistence_and_retrieval"
    assert FORMS_FAMILY_PLAN["persistence_contract_frozen"] is True
    assert "persisted_at" not in FormSubmission.model_fields
    assert "submission_id" not in FormSubmission.model_fields


def test_round_trip_preserves_normalized_values_and_accepted_at() -> None:
    store = InMemoryFormSubmissionStore()
    accepted = _accept(_contact_raw())
    persisted = persist_form_submission(
        store, _CTX, accepted, clock=lambda: _FIXED_PERSISTED
    )
    loaded = get_form_submission(store, _CTX, _ID_A)
    assert loaded is not None
    assert loaded.submission_id == _ID_A
    assert loaded.accepted.submission.form_key == "contact"
    assert loaded.accepted.submission.values == {
        "name": "Jane",
        "email": "Jane@Example.COM",
        "message": "Hello",
    }
    assert loaded.accepted.accepted_at == _FIXED_ACCEPTED
    assert loaded.persisted_at == _FIXED_PERSISTED
    assert loaded.persisted_at != loaded.accepted.accepted_at
    assert persisted.submission_id == loaded.submission_id
    assert persisted.accepted.submission.values == loaded.accepted.submission.values


def test_persist_retry_is_idempotent() -> None:
    store = InMemoryFormSubmissionStore()
    accepted = _accept(_contact_raw())
    first = persist_form_submission(
        store, _CTX, accepted, clock=lambda: _FIXED_PERSISTED
    )
    later = datetime(2026, 9, 13, 13, 0, tzinfo=UTC)
    second = persist_form_submission(store, _CTX, accepted, clock=lambda: later)
    assert first.submission_id == second.submission_id == _ID_A
    assert first.persisted_at == second.persisted_at == _FIXED_PERSISTED
    assert first.accepted.submission.values == second.accepted.submission.values
    assert get_form_submission(store, _CTX, _ID_B) is None


def test_identity_conflict_does_not_overwrite() -> None:
    store = InMemoryFormSubmissionStore()
    first = _accept(_contact_raw())
    persist_form_submission(store, _CTX, first, clock=lambda: _FIXED_PERSISTED)
    other = AcceptedFormSubmission(
        submission_id=_ID_A,
        submission=FormSubmission(
            form_key="contact",
            values={"name": "Ada", "email": "ada@example.com", "message": "Hi"},
        ),
        accepted_at=_FIXED_ACCEPTED,
    )
    with pytest.raises(FormPersistenceError) as exc:
        persist_form_submission(store, _CTX, other, clock=lambda: _FIXED_PERSISTED)
    assert exc.value.code == "submission_identity_conflict"
    loaded = get_form_submission(store, _CTX, _ID_A)
    assert loaded is not None
    assert loaded.accepted.submission.values["name"] == "Jane"


def test_same_payload_distinct_ids_are_two_rows() -> None:
    store = InMemoryFormSubmissionStore()
    a = _accept(_contact_raw(), submission_id=_ID_A)
    b = _accept(_contact_raw(), submission_id=_ID_B)
    persist_form_submission(store, _CTX, a, clock=lambda: _FIXED_PERSISTED)
    persist_form_submission(store, _CTX, b, clock=lambda: _FIXED_PERSISTED)
    assert get_form_submission(store, _CTX, _ID_A) is not None
    assert get_form_submission(store, _CTX, _ID_B) is not None
    assert _ID_A != _ID_B


def test_retrieval_does_not_revalidate_against_new_definition() -> None:
    store = InMemoryFormSubmissionStore()
    accepted = _accept(_contact_raw())
    persist_form_submission(store, _CTX, accepted, clock=lambda: _FIXED_PERSISTED)
    FormDefinition(
        key="contact",
        fields=[FormField(key="email", type="email", required=True)],
    )
    loaded = get_form_submission(store, _CTX, _ID_A)
    assert loaded is not None
    assert loaded.accepted.submission.values["name"] == "Jane"
    assert "message" in loaded.accepted.submission.values


def test_missing_and_wrong_project_are_not_found() -> None:
    store = InMemoryFormSubmissionStore()
    persist_form_submission(
        store, _CTX, _accept(_contact_raw()), clock=lambda: _FIXED_PERSISTED
    )
    assert get_form_submission(store, _CTX, _ID_B) is None
    assert get_form_submission(store, _OTHER, _ID_A) is None
    with pytest.raises(FormPersistenceError) as exc:
        persist_form_submission(
            store, _OTHER, _accept(_contact_raw()), clock=lambda: _FIXED_PERSISTED
        )
    assert exc.value.code == "submission_identity_conflict"


def test_project_id_is_not_in_values() -> None:
    store = InMemoryFormSubmissionStore()
    loaded = persist_form_submission(
        store, _CTX, _accept(_contact_raw()), clock=lambda: _FIXED_PERSISTED
    )
    assert loaded.project_id == "prj_forms_7e"
    assert "_project_id" not in loaded.accepted.submission.values
    assert "project_id" not in loaded.accepted.submission.values


def test_storage_ref_is_not_canonical_identity() -> None:
    ref = FormSubmissionStorageRef(backend="contact_submission", native_id="9182")
    accepted = _accept(_contact_raw())
    assert ref.native_id != accepted.submission_id
    assert accepted.submission_id.startswith("fsb_")


def test_persisted_object_is_provider_neutral() -> None:
    store = InMemoryFormSubmissionStore()
    loaded = persist_form_submission(
        store, _CTX, _accept(_contact_raw()), clock=lambda: _FIXED_PERSISTED
    )
    dumped = loaded.model_dump()
    keys = set(dumped) | set(dumped["accepted"]) | set(
        dumped["accepted"]["submission"]["values"]
    )
    for token in FORBIDDEN_PROVIDER_TOKENS:
        assert token not in keys
    assert "crm_status" not in keys
    assert "turnstile_token" not in keys
    assert "email_sent" not in keys


def test_persistence_error_is_not_a_field_error() -> None:
    with pytest.raises(ValueError):
        FormPersistenceError("invalid_email")


def test_module_has_no_infrastructure_imports() -> None:
    source = Path("src/domain/forms/persistence.py").read_text(encoding="utf-8")
    for token in (
        "sqlalchemy",
        "src.domain.connectors",
        "src.integrations",
        "src.domain.codegen",
        "src.domain.cloud",
        "turnstile",
        "alembic",
    ):
        assert token not in source
    assert "form.submit" not in INVOKE_CAPABILITIES
    assert "accepted" in PersistedFormSubmission.model_fields
