"""Runtime-contract resolver + adapter injection.

Email precedence mirrors email_delivery.py's tiers but read-only (no quota
reservation) -- these tests use the same fake-dependency-injection convention as
tests/test_cloud_email_delivery.py, not a real DB/connector round-trip.
"""
from __future__ import annotations

import tempfile
from pathlib import Path
from types import SimpleNamespace
from unittest.mock import AsyncMock
from uuid import uuid4

import pytest
from src.domain.codegen.admin_presentation import (
    ADMIN_PRESENTATION_CONTRACT_VERSION,
    build_admin_presentation_contract,
)
from src.domain.codegen.app_sdk import app_sdk_files, staff_shell_files
from src.domain.codegen.contact_adapter import contact_adapter_files
from src.domain.codegen.runtime_contract import ProjectRuntimeContract, resolve_email_capability
from src.domain.projects.runtime_invariants import ProjectRuntimeInvariants


def _connector_service(decision=None):
    return SimpleNamespace(resolve_email_send=AsyncMock(return_value=decision))


def _domain_repo(domain=None):
    return SimpleNamespace(get_by_workspace=AsyncMock(return_value=domain))


_EMAIL_INVOKE = {
    "capability": "email.send",
    "request_type": "email.send",
    "invoke": "POST /api/jobs/email.send",
    "provider_actions_role": "escape_hatch",
}


@pytest.mark.asyncio
async def test_connector_tier_wins_when_present(monkeypatch):
    decision = SimpleNamespace(allowed=True, connector=SimpleNamespace(key="resend"))
    result = await resolve_email_capability(
        connector_service=_connector_service(decision),
        workspace_id=uuid4(),
        project_id=uuid4(),
        invariants=ProjectRuntimeInvariants(),
        enabled_capabilities=set(),
        email_domain_repo=_domain_repo(domain=SimpleNamespace(status="verified")),
    )
    assert result == {
        "provider": "p2hs-connector",
        "binding": "resend",
        "available": True,
        **_EMAIL_INVOKE,
    }


@pytest.mark.asyncio
async def test_verified_domain_wins_when_no_connector():
    result = await resolve_email_capability(
        connector_service=_connector_service(None),
        workspace_id=uuid4(),
        project_id=uuid4(),
        invariants=ProjectRuntimeInvariants(),
        enabled_capabilities=set(),
        email_domain_repo=_domain_repo(domain=SimpleNamespace(status="verified")),
    )
    assert result == {
        "provider": "p2hs-platform-email", "binding": "managed_domain", "available": True,
        **_EMAIL_INVOKE,
    }


@pytest.mark.asyncio
async def test_platform_default_when_no_connector_or_domain(monkeypatch):
    monkeypatch.setattr(
        "src.integrations.email_provider.cloud_email_transport_configured", lambda settings: True
    )
    result = await resolve_email_capability(
        connector_service=_connector_service(None),
        workspace_id=uuid4(),
        project_id=uuid4(),
        invariants=ProjectRuntimeInvariants(),
        enabled_capabilities=set(),
        email_domain_repo=_domain_repo(domain=None),
    )
    assert result == {
        "provider": "p2hs-platform-email", "binding": "platform_default", "available": True,
        **_EMAIL_INVOKE,
    }


@pytest.mark.asyncio
async def test_unavailable_when_nothing_configured(monkeypatch):
    monkeypatch.setattr(
        "src.integrations.email_provider.cloud_email_transport_configured", lambda settings: False
    )
    result = await resolve_email_capability(
        connector_service=_connector_service(None),
        workspace_id=uuid4(),
        project_id=uuid4(),
        invariants=ProjectRuntimeInvariants(),
        enabled_capabilities=set(),
        email_domain_repo=_domain_repo(domain=None),
    )
    assert result == {"provider": None, "binding": None, "available": False, **_EMAIL_INVOKE}


@pytest.mark.asyncio
async def test_resolution_is_logged_distinguishing_tier_including_the_unavailable_case(monkeypatch):
    """Regression test: the resolver used to return the identical `unavailable` dict
    on both a real resolver exception and "this project just has no email configured"
    with zero logging either way -- an outage was indistinguishable from normal.
    resolve_email_capability itself can't tell those apart (an exception propagates
    out of it, handled by resolve_runtime_contract's own log line), but it must always
    log which tier decided, including "none"."""
    import structlog.testing

    monkeypatch.setattr(
        "src.integrations.email_provider.cloud_email_transport_configured", lambda settings: False
    )
    project_id = uuid4()
    with structlog.testing.capture_logs() as logs:
        await resolve_email_capability(
            connector_service=_connector_service(None),
            workspace_id=uuid4(),
            project_id=project_id,
            invariants=ProjectRuntimeInvariants(),
            enabled_capabilities=set(),
            email_domain_repo=_domain_repo(domain=None),
        )
    resolved = [e for e in logs if e.get("event") == "capability.email.resolved"]
    assert len(resolved) == 1
    assert resolved[0]["tier"] == "none"
    assert resolved[0]["available"] is False
    assert resolved[0]["project_id"] == str(project_id)


@pytest.mark.asyncio
async def test_unverified_domain_does_not_count_as_available(monkeypatch):
    monkeypatch.setattr(
        "src.integrations.email_provider.cloud_email_transport_configured", lambda settings: False
    )
    result = await resolve_email_capability(
        connector_service=_connector_service(None),
        workspace_id=uuid4(),
        project_id=uuid4(),
        invariants=ProjectRuntimeInvariants(),
        enabled_capabilities=set(),
        email_domain_repo=_domain_repo(domain=SimpleNamespace(status="pending_dns")),
    )
    assert result["available"] is False


def _contract(admin_path="/be-admin", email_available=True):
    return ProjectRuntimeContract(
        routes={"admin_panel_path": admin_path, "customer_login_path": "/login"},
        capabilities={
            "data": {"provider": "p2hs-cloud", "available": True},
            "auth": {"provider": "p2hs-auth", "magic_link": True},
            "email": (
                {
                    "provider": "p2hs-platform-email",
                    "binding": "platform_default",
                    "available": True,
                }
                if email_available
                else {"provider": None, "binding": None, "available": False}
            ),
        },
    ).model_dump()


def test_contact_adapter_bakes_resolved_admin_path_into_magic_consume():
    files = contact_adapter_files("html", runtime_contract=_contract("/be-admin"))
    magic = files["functions/_lib/p2hs-auth-magic.mjs"]
    assert '"/be-admin"' in magic
    assert "__P2HS_ADMIN_PANEL_PATH__" not in magic


def test_contact_adapter_defaults_to_admin_when_unresolved():
    files = contact_adapter_files("html", runtime_contract=None)
    magic = files["functions/_lib/p2hs-auth-magic.mjs"]
    assert '"/admin"' in magic
    assert "__P2HS_ADMIN_PANEL_PATH__" not in magic


def test_app_sdk_client_sends_resolved_admin_path_as_default_link_path():
    files = app_sdk_files("html", runtime_contract=_contract("/be-admin"))
    client = files["js/p2hs-app.js"]
    assert 'DEFAULT_ADMIN_PATH = "/be-admin"' in client
    assert "link_path" in client


def test_app_sdk_recipe_reflects_resolved_admin_path_and_email_binding():
    import json

    files = app_sdk_files("html", runtime_contract=_contract("/be-admin", email_available=True))
    recipe = json.loads(files["p2hs/app-recipe.json"])
    assert recipe["recipes"]["staff_dashboard"]["path"] == "/be-admin"
    assert "platform_default" in " ".join(recipe["recipes"]["send_email"]["notes"])


def test_app_sdk_recipe_unchanged_when_unresolved():
    raw = (
        __import__("pathlib").Path(__file__).parent.parent
        / "src/domain/codegen/runtime/app-recipe.json"
    ).read_text(encoding="utf-8")
    files = app_sdk_files("html", runtime_contract=None)
    assert files["p2hs/app-recipe.json"] == raw


def test_staff_shell_nuxt_uses_resolved_admin_path():
    with tempfile.TemporaryDirectory() as repo_path:
        files = staff_shell_files("nuxt_app", repo_path, runtime_contract=_contract("/be-admin"))
    assert "pages/be-admin/index.vue" in files
    assert "pages/admin/index.vue" not in files


def test_staff_shell_nuxt_defaults_to_admin_when_unresolved():
    with tempfile.TemporaryDirectory() as repo_path:
        files = staff_shell_files("nuxt_app", repo_path, runtime_contract=None)
    assert "pages/admin/index.vue" in files


def test_staff_shell_html_uses_resolved_admin_path():
    with tempfile.TemporaryDirectory() as repo_path:
        files = staff_shell_files("html", repo_path, runtime_contract=_contract("/be-admin"))
    assert "be-admin.html" in files


def test_admin_presentation_is_capability_driven_and_never_invents_modules():
    contract = _contract("/be-admin")
    contract["capabilities"]["records.search.external_index"] = {"available": True}
    presentation = build_admin_presentation_contract(contract)
    assert presentation["contract_version"] == ADMIN_PRESENTATION_CONTRACT_VERSION
    assert presentation["profile"] == "professional-admin"
    assert presentation["admitted_surfaces"] == {
        "auth": True,
        "records": True,
        "external_search": True,
        "email": True,
    }
    assert "orders" not in presentation["admitted_surfaces"]
    assert "inventory" not in presentation["admitted_surfaces"]
    assert "never invent entities" in " ".join(presentation["rules"])


def test_app_sdk_projects_admin_presentation_contract():
    import json

    files = app_sdk_files("html", runtime_contract=_contract("/be-admin"))
    projection = json.loads(files["p2hs/admin-presentation.json"])
    assert projection["contract_version"] == ADMIN_PRESENTATION_CONTRACT_VERSION
    assert projection["theme"]["admin_derivation"] == "dense-neutral"


def test_staff_shell_projects_canonical_application_identity():
    contract = _contract("/be-admin")
    contract["presentation"] = {
        "branding": {"application_name": "Acme Dental"}
    }
    with tempfile.TemporaryDirectory() as repo_path:
        files = staff_shell_files("html", repo_path, runtime_contract=contract)
    assert "Acme Dental" in files["be-admin.html"]
    assert "Workspace admin" not in files["be-admin.html"]


def test_seeded_admin_shell_has_safe_rendering_and_responsive_states():
    with tempfile.TemporaryDirectory() as repo_path:
        files = staff_shell_files("html", repo_path, runtime_contract=_contract("/be-admin"))
    html = files["be-admin.html"]
    assert "color-mix" in html
    assert "prefers-reduced-motion" in html
    assert "overflow:auto" in html
    assert "replace(/[&<>" in html
    assert "No submissions yet" in html


def test_install_catalog_adapters_writes_runtime_contract_json():
    import json

    from src.domain.codegen.port_adapter import install_catalog_adapters
    from src.integrations.platform_ports import CATALOG_VERSION, entitled_ports

    context = {
        "ports": entitled_ports(),
        "catalog_version": CATALOG_VERSION,
        "runtime_contract": _contract("/be-admin"),
    }
    with tempfile.TemporaryDirectory() as repo_path:
        install_catalog_adapters(repo_path, "html", context)
        written = (Path(repo_path) / "p2hs" / "runtime-contract.json").read_text(encoding="utf-8")
    assert json.loads(written)["routes"]["admin_panel_path"] == "/be-admin"


def test_install_catalog_adapters_skips_runtime_contract_when_unresolved():
    from src.domain.codegen.port_adapter import install_catalog_adapters
    from src.integrations.platform_ports import CATALOG_VERSION, entitled_ports

    context = {"ports": entitled_ports(), "catalog_version": CATALOG_VERSION}
    with tempfile.TemporaryDirectory() as repo_path:
        install_catalog_adapters(repo_path, "html", context)
        assert not (Path(repo_path) / "p2hs" / "runtime-contract.json").exists()
