"""8J leftover contact runtime migration / removal readiness.

Inspect and plan only. Does not apply migrations, delete leftover execution,
or add persistence. Artifact presence is not runtime invocation.
"""
from __future__ import annotations

import hashlib
import os
import re
from dataclasses import dataclass
from pathlib import Path
from typing import Any, Literal

from src.domain.codegen.legacy_contact_generation import (
    CONTACT_SUBMIT_RELATIVE_PATHS,
    repo_has_legacy_contact_submit,
)

ProjectClass = Literal[
    "canonical",
    "legacy_active",
    "legacy_present_but_unused",
    "mixed",
    "unknown",
]
MigrationClass = Literal[
    "auto_migratable",
    "manual_review_required",
    "not_migratable_yet",
    "already_canonical",
    "cleanup_only",
]

_SKIP_DIRS = {
    ".git",
    ".p2hs",
    "node_modules",
    ".nuxt",
    ".output",
    ".next",
    "dist",
    "build",
    "coverage",
    ".venv",
    "venv",
    "__pycache__",
}
_PLATFORM_CONTACT_FILES = frozenset(
    {
        *CONTACT_SUBMIT_RELATIVE_PATHS,
        "functions/_lib/p2hs-contact.mjs",
        "functions/api/contact/inbox.js",
        "functions/api/public-config.js",
        "server/utils/p2hs-contact.mjs",
        "server/api/contact/inbox.get.ts",
        "server/api/public-config.get.ts",
        "js/p2hs-app.js",
        "src/lib/p2hs-app.js",
        "lib/p2hs-app.js",
        "composables/useP2hs.ts",
        "p2hs/app-recipe.json",
    }
)
_FORMS_SUBMIT_FILES = (
    "functions/api/forms/[formKey]/submissions.js",
    "server/api/forms/[formKey]/submissions.post.ts",
)
_UI_SUBMIT_CONTACT = re.compile(r"\bsubmitContact\s*\(")
_UI_CONTACT_POST = re.compile(
    r"""["'`]\/api\/contact(?:["'`]|\?|#)|POST\s+\/api\/contact\b""",
    re.I,
)
_UI_CONTACT_INBOX = re.compile(r"/api/contact/inbox", re.I)

LEGACY_CONTACT_RUNTIME: dict[str, Any] = {
    "slice_id": "8j_legacy_contact_runtime_removal_readiness",
    "status": "complete",
    "outcome": "compatibility_retention",
    "legacy_generation": "deprecated_for_new_projects",
    "legacy_runtime": "compatibility_only",
    "legacy_runtime_removal_ready": False,
    "live_project_counts": "unmeasured",
    "usage_evidence": "artifact_and_wiring_only",
    "telemetry": False,
    "auto_migration": False,
    "apply_in_slice": False,
    "database_schema_change_required": False,
    "docs": "docs/audits/EMAIL_TEMPLATES_DOMAIN_8J.md",
}

RETAINED_EXECUTION: tuple[dict[str, Any], ...] = (
    {
        "id": "post_api_contact",
        "paths": CONTACT_SUBMIT_RELATIVE_PATHS,
        "role": "leftover_public_submit",
        "status": "compatibility_only",
    },
    {
        "id": "p2hs_contact_mjs",
        "paths": (
            "functions/_lib/p2hs-contact.mjs",
            "server/utils/p2hs-contact.mjs",
        ),
        "role": "submit_notify_inbox_public_config",
        "status": "compatibility_only",
    },
    {
        "id": "notify_contact_owners",
        "role": "best_effort_admin_email_after_record_create",
        "status": "compatibility_only",
    },
    {
        "id": "submit_contact_client",
        "role": "browser_helper",
        "status": "compatibility_only",
    },
    {
        "id": "contact_inbox",
        "role": "staff_list_contact_submission",
        "status": "supported_existing_only",
    },
    {
        "id": "contact_capture_pack_notify",
        "role": "entity_record_created_admin_and_confirmation",
        "status": "canonical_for_entity_path",
    },
)

BEHAVIORAL_EQUIVALENCE: tuple[dict[str, Any], ...] = (
    {
        "axis": "submission_persist",
        "legacy": "Cloud contact_submission record then HTTP 200",
        "canonical": "Forms accept + FormSubmission (not contact_submission)",
        "equivalent": False,
    },
    {
        "axis": "http_success_when_email_fails",
        "legacy": "yes_best_effort_after_record_save",
        "canonical": "yes_acceptance_independent_BEST_EFFORT",
        "equivalent": True,
    },
    {
        "axis": "admin_recipient",
        "legacy": "NOTIFY_TO_EMAIL split all valid addresses",
        "canonical": "notify_to_email first address only",
        "equivalent": False,
    },
    {
        "axis": "confirmation",
        "legacy": "adapter_none_pack_on_record_created",
        "canonical": "forms_post_submit_when_configured",
        "equivalent": False,
    },
    {
        "axis": "reply_to",
        "legacy": "submission.email when present",
        "canonical": "mapping reply_to=email",
        "equivalent": True,
    },
    {
        "axis": "copy_source",
        "legacy": "Cloud render with leftover inline fallback",
        "canonical": "Cloud render via EmailTemplateInvocation; action BEST_EFFORT on fail",
        "equivalent": False,
    },
    {
        "axis": "request_shape",
        "legacy": "{name,email,phone,message,website,turnstile_token}",
        "canonical": "{values,challenge} against FormDefinition",
        "equivalent": False,
    },
    {
        "axis": "idempotency",
        "legacy": "contact-notify:{recordId}",
        "canonical": "submission_id_plus_action_key",
        "equivalent": False,
    },
    {
        "axis": "retry",
        "legacy": "Cloud job retry after enqueue",
        "canonical": "one email.send enqueue then Cloud retry",
        "equivalent": True,
    },
    {
        "axis": "honeypot",
        "legacy": "website set → ok ignored no persist",
        "canonical": "Forms anti-abuse fake success without persist",
        "equivalent": True,
    },
)

REMOVAL_GATE: dict[str, bool] = {
    "no_new_projects_generate_it": True,
    "active_legacy_usage_measurable": False,
    "all_active_legacy_migrated_or_exempt": False,
    "compatibility_artifacts_not_runtime_dependencies": False,
    "redeploy_no_longer_expects_runtime": False,
    "tests_no_longer_require_leftover_for_canonical": False,
    "rollback_window_or_policy_allows_removal": False,
}

FIELD_MAPPING: dict[str, str] = {
    "name": "name",
    "email": "email",
    "phone": "phone",
    "message": "message",
}

ROLLBACK: dict[str, str] = {
    "source": "git_previous_commit",
    "deploy": "POST /api/projects/{project_id}/deploys/{deploy}/rollback",
    "overlay": "restore_previous_email-templates.json_then_replace_all",
    "invented_rollback_system": "no",
}


@dataclass(frozen=True)
class LegacyContactInspection:
    project_class: ProjectClass
    migration_class: MigrationClass
    artifact_present: bool
    route_wired: bool
    adapter_customized: bool
    canonical_forms_present: bool
    recent_runtime_usage: Literal["unknown"]
    evidence_level: str
    blockers: tuple[str, ...] = ()
    notes: tuple[str, ...] = ()


@dataclass(frozen=True)
class LegacyContactMigrationPlan:
    source_path: str
    target_path: str
    notification_mapping: dict[str, Any]
    template_mapping: dict[str, str]
    recipient_mapping: dict[str, str]
    field_mapping: dict[str, str]
    changes: tuple[str, ...]
    blockers: tuple[str, ...]
    eligibility: MigrationClass
    apply_allowed: bool = False
    shadow_compare_only: bool = True


def _platform_contact_digest() -> str:
    from src.domain.codegen.contact_adapter import contact_adapter_files

    files = contact_adapter_files("html", include_submit_route=True)
    text = files.get("functions/_lib/p2hs-contact.mjs") or ""
    return hashlib.sha256(text.encode("utf-8")).hexdigest()


def leftover_adapter_customized(repo_path: str) -> bool:
    root = Path(repo_path)
    platform = _platform_contact_digest()
    found = False
    for rel in (
        "functions/_lib/p2hs-contact.mjs",
        "server/utils/p2hs-contact.mjs",
    ):
        path = root / rel
        if not path.is_file():
            continue
        found = True
        if hashlib.sha256(path.read_bytes()).hexdigest() != platform:
            return True
    return False if found else False


def leftover_ui_wired(repo_path: str) -> bool:
    """True when app source (not platform adapters) still POSTs leftover contact."""
    root = Path(repo_path)
    if not root.is_dir():
        return False
    for directory, dirs, files in os.walk(root, followlinks=False):
        dir_path = Path(directory)
        dirs[:] = [
            d for d in dirs if d not in _SKIP_DIRS and not (dir_path / d).is_symlink()
        ]
        for name in files:
            path = dir_path / name
            rel = path.relative_to(root).as_posix()
            if rel in _PLATFORM_CONTACT_FILES:
                continue
            if path.suffix.lower() not in {
                ".js",
                ".ts",
                ".mjs",
                ".cjs",
                ".jsx",
                ".tsx",
                ".vue",
                ".html",
                ".htm",
            }:
                continue
            try:
                text = path.read_text(encoding="utf-8-sig")
            except (OSError, UnicodeDecodeError):
                continue
            if "p2hs-contact" in text and rel.startswith(("functions/", "server/")):
                continue
            if _UI_SUBMIT_CONTACT.search(text):
                return True
            stripped = _UI_CONTACT_INBOX.sub("", text)
            if _UI_CONTACT_POST.search(stripped):
                return True
    return False


def canonical_forms_present(repo_path: str) -> bool:
    root = Path(repo_path)
    return any((root / rel).is_file() for rel in _FORMS_SUBMIT_FILES)


def inspect_legacy_contact_runtime(repo_path: str) -> LegacyContactInspection:
    artifacts = repo_has_legacy_contact_submit(repo_path)
    wired = leftover_ui_wired(repo_path)
    forms = canonical_forms_present(repo_path)
    custom = leftover_adapter_customized(repo_path) if artifacts else False
    if wired:
        evidence = "active_generated_route_wiring"
    elif artifacts:
        evidence = "artifact_presence_only"
    else:
        evidence = "project_composition_configuration"

    if not artifacts and not wired:
        return LegacyContactInspection(
            project_class="canonical" if forms else "unknown",
            migration_class="already_canonical",
            artifact_present=False,
            route_wired=False,
            adapter_customized=False,
            canonical_forms_present=forms,
            recent_runtime_usage="unknown",
            evidence_level=evidence,
            notes=("no_leftover_submit_route",),
        )

    if artifacts and not wired:
        return LegacyContactInspection(
            project_class="legacy_present_but_unused",
            migration_class="cleanup_only",
            artifact_present=True,
            route_wired=False,
            adapter_customized=custom,
            canonical_forms_present=forms,
            recent_runtime_usage="unknown",
            evidence_level="artifact_presence_only",
            blockers=("stale_files_are_not_proof_of_zero_traffic",),
            notes=("cleanup_must_not_change_behavior",),
        )

    blockers = [
        "frontend_backend_pairing_required",
        "request_shape_not_interchangeable",
        "admin_recipient_cardinality_differs",
        "confirmation_owner_differs",
        "inline_fallback_vs_canonical_render",
        "no_execution_telemetry",
        "auto_migration_forbidden",
    ]
    if custom:
        blockers.insert(0, "adapter_customized")
    return LegacyContactInspection(
        project_class="mixed" if forms and wired else "legacy_active",
        migration_class="manual_review_required" if custom else "not_migratable_yet",
        artifact_present=artifacts,
        route_wired=wired,
        adapter_customized=custom,
        canonical_forms_present=forms,
        recent_runtime_usage="unknown",
        evidence_level=evidence,
        blockers=tuple(blockers),
        notes=("apply_not_in_8j",),
    )


def plan_legacy_contact_migration(repo_path: str) -> LegacyContactMigrationPlan:
    inspection = inspect_legacy_contact_runtime(repo_path)
    return LegacyContactMigrationPlan(
        source_path="POST /api/contact + notifyContactOwners",
        target_path=(
            "POST /api/forms/{form_key}/submissions + Forms template actions"
        ),
        notification_mapping={
            "admin": "forms_post_submit owner_notify",
            "confirmation": "forms_post_submit send_confirmation if configured",
            "pack_entity": "do_not_also_write_contact_submission",
        },
        template_mapping={
            "admin": "contact_capture.admin_notify",
            "confirmation": "contact_capture.confirmation",
        },
        recipient_mapping={
            "admin": "notify_to_email_first_address_only_is_not_legacy_split",
            "confirmation": "submission.email",
        },
        field_mapping=dict(FIELD_MAPPING),
        changes=(
            "frontend_submitGeneratedForm",
            "install_canonical_forms_binding",
            "do_not_enqueue_legacy_and_canonical",
        ),
        blockers=inspection.blockers or ("apply_not_in_8j",),
        eligibility=inspection.migration_class,
        apply_allowed=False,
        shadow_compare_only=True,
    )


def merge_contact_overrides_into_manifest(
    current: dict[str, Any] | None,
    contact_updates: list[dict[str, Any]],
) -> dict[str, Any]:
    """Replace-all safety: contact keys merge into the full current desired set."""
    by_key: dict[str, dict[str, Any]] = {}
    for row in (current or {}).get("templates") or []:
        key = row.get("template_key")
        if isinstance(key, str) and key:
            by_key[key] = dict(row)
    for row in contact_updates:
        key = row.get("template_key")
        if not isinstance(key, str) or not key:
            raise ValueError("contact override missing template_key")
        by_key[key] = dict(row)
    return {
        "version": int((current or {}).get("version") or 1),
        "templates": list(by_key.values()),
    }


def leftover_runtime_removable() -> bool:
    return all(REMOVAL_GATE.values())


def shadow_admin_payload(*, notify_to: str, email: str) -> dict[str, Any]:
    """Addressing-only shadow. No body logging."""
    recipients = [
        part.strip()
        for part in str(notify_to).split(",")
        if "@" in part
    ]
    return {
        "legacy_to_count": len(recipients),
        "canonical_to_count": 1 if recipients else 0,
        "reply_to": email or None,
        "send": False,
    }


SYNTHETIC_FIXTURES: tuple[dict[str, Any], ...] = (
    {"id": "admin_only", "notify_to_email": "ops@example.com", "send_confirmation_email": False},
    {"id": "confirmation_only", "notify_to_email": "", "send_confirmation_email": True},
    {"id": "both", "notify_to_email": "ops@example.com", "send_confirmation_email": True},
    {"id": "custom_reply_to", "notify_to_email": "ops@example.com", "reply_to_field": "email"},
    {"id": "missing_optional_phone", "values": {"name": "Ada", "email": "a@b.co", "message": "Hi"}},
    {"id": "multi_admin_legacy", "notify_to_email": "ops@example.com,alerts@example.com"},
)
