"""Email touchpoint contract tests.

For every PRD-required SME-Hub touchpoint, this test asserts the verb exists
on ``Notification.Verb``. As later phases land they will register hooks that
*emit* these verbs end-to-end; those will live next to each phase's tests.
This file is the registry that prevents accidental verb deletion / typo
during refactors.

Phase 0 only enforces verb existence. Each touchpoint row also records the
phase that owns delivering it, so future contributors can see which row is
currently "verb only" (no emitter wired) versus "fully delivered."
"""
from __future__ import annotations

from dataclasses import dataclass

import pytest

from apps.core.notifications.models import Notification


@dataclass(frozen=True)
class Touchpoint:
    """A single PRD email/notification touchpoint."""

    description: str
    verb: str
    phase: str  # which phase wires the emitter end-to-end


# Ordered by user journey: SP1 -> SP2 -> SP3 -> SP4 -> SP5.
TOUCHPOINTS: tuple[Touchpoint, ...] = (
    # SP1 — Onboarding
    Touchpoint("Self-register: verification email", "smehub_registration_verify_email", "shipped"),
    Touchpoint("Admin alert: entrepreneur pending review", "smehub_entrepreneur_pending_review", "P0"),
    Touchpoint("Entrepreneur verified", "smehub_entrepreneur_verified", "shipped"),
    Touchpoint("Entrepreneur rejected with reason", "smehub_entrepreneur_rejected", "shipped"),
    Touchpoint("Entrepreneur pending more info", "smehub_entrepreneur_more_info", "shipped"),
    Touchpoint("Business pending review", "smehub_business_pending_review", "shipped"),
    Touchpoint("Business verified", "smehub_business_verified", "shipped"),
    Touchpoint("Business rejected", "smehub_business_rejected", "shipped"),
    Touchpoint("Business revoked", "smehub_business_revoked", "shipped"),
    Touchpoint("Role profile verified (mentor / investor / SP / partner / buyer)", "smehub_role_profile_verified", "P0"),
    Touchpoint("M&E officer alert: new tracking record", "smehub_new_tracking_record", "P2"),
    # SP2 — Incubation
    Touchpoint("Programme published", "smehub_programme_published", "shipped"),
    Touchpoint("Eligible-entrepreneur targeted alert", "smehub_programme_eligible", "P3"),
    Touchpoint("Application received confirmation", "smehub_application_received", "shipped"),
    Touchpoint("Application returned for info", "smehub_application_returned", "shipped"),
    Touchpoint("Judge assigned", "smehub_judge_assigned", "shipped"),
    Touchpoint("Judge reminder", "smehub_judge_reminder", "shipped"),
    Touchpoint("Cohort accepted", "smehub_cohort_accepted", "shipped"),
    Touchpoint("Cohort rejected", "smehub_cohort_rejected", "shipped"),
    Touchpoint("Mentor assigned", "smehub_mentor_assigned", "shipped"),
    Touchpoint("Session scheduled (.ics in P6)", "smehub_session_scheduled", "shipped"),
    Touchpoint("Session cancelled", "smehub_session_cancelled", "shipped"),
    Touchpoint("Programme complete", "smehub_programme_complete", "shipped"),
    Touchpoint("Certificate issued", "smehub_certificate_issued", "shipped"),
    # SP3 — Linkage / marketplace
    Touchpoint("Connection request received", "smehub_connection_requested", "shipped"),
    Touchpoint("Connection accepted", "smehub_connection_accepted", "shipped"),
    Touchpoint("Connection declined", "smehub_connection_declined", "shipped"),
    Touchpoint("MoU drafted", "smehub_mou_drafted", "shipped"),
    Touchpoint("MoU formalised (two-party in P6)", "smehub_mou_formalised", "shipped"),
    Touchpoint("Market demand match", "smehub_market_demand_match", "shipped"),
    Touchpoint("Demand response received", "smehub_demand_response", "shipped"),
    Touchpoint("Advisory session booked (.ics in P6)", "smehub_advisory_booked", "shipped"),
    Touchpoint("Advisory session cancelled", "smehub_advisory_cancelled", "shipped"),
    # SP4 — Showcasing & deal management
    Touchpoint("Showcase published", "smehub_showcase_published", "shipped"),
    Touchpoint("Challenge published", "smehub_challenge_published", "shipped"),
    Touchpoint("Showcase participant confirmed", "smehub_showcase_participant_confirmed", "shipped"),
    Touchpoint("Deal Room opened", "smehub_deal_room_opened", "shipped"),
    Touchpoint("Deal Room new message", "smehub_deal_room_message", "shipped"),
    Touchpoint("Deal Room new document", "smehub_deal_room_document", "shipped"),
    Touchpoint("Deal Room expired", "smehub_deal_room_expired", "shipped"),
    Touchpoint("Agreement formalised", "smehub_agreement_formalised", "shipped"),
    # SP5 — Investment
    Touchpoint("Funding call published", "smehub_funding_call_published", "shipped"),
    Touchpoint("Funding call match", "smehub_funding_call_match", "shipped"),
    Touchpoint("Funding application outcome", "smehub_funding_outcome", "shipped"),
    Touchpoint("Investor pitch request received", "smehub_investor_request", "shipped"),
    Touchpoint("Investor accepted", "smehub_investor_accepted", "shipped"),
    Touchpoint("Investor declined", "smehub_investor_declined", "shipped"),
    Touchpoint("Funding secured", "smehub_funding_secured", "shipped"),
    # SP6 — feedback survey (cross-cutting)
    Touchpoint("Feedback survey dispatch", "smehub_feedback_survey", "P7"),
)


@pytest.mark.parametrize("tp", TOUCHPOINTS, ids=lambda tp: tp.verb)
def test_touchpoint_verb_exists(tp: Touchpoint):
    """Each PRD touchpoint must map to a real ``Notification.Verb`` value."""
    valid_verbs = {v.value for v in Notification.Verb}
    assert tp.verb in valid_verbs, (
        f"Touchpoint '{tp.description}' uses verb '{tp.verb}' which is not "
        f"defined on Notification.Verb. Add it before wiring the emitter "
        f"in {tp.phase}."
    )


def test_no_duplicate_touchpoints():
    """A verb should map to exactly one touchpoint description."""
    seen: dict[str, str] = {}
    for tp in TOUCHPOINTS:
        if tp.verb in seen:
            pytest.fail(
                f"Verb {tp.verb!r} maps to two touchpoints: "
                f"{seen[tp.verb]!r} and {tp.description!r}"
            )
        seen[tp.verb] = tp.description
