"""Doc scenario Test B -- email fallback.

Given: project requires outbound email; no project email connector is configured;
platform email is available.
Expect: the platform-default email capability resolves; generated code reflects it, not
"email unavailable" merely because there's no user connector. Also: a configured
connector overrides the default, and an explicit user-named provider overrides that.

Chains resolve_email_capability's *real return value* straight into app_sdk_files
instead of each test building its own hand-crafted capabilities dict -- this is the
seam a pair of individually-passing unit tests could still disagree on.
"""
from __future__ import annotations

from types import SimpleNamespace
from unittest.mock import AsyncMock
from uuid import uuid4

import pytest

from src.domain.codegen.app_sdk import app_sdk_files
from src.domain.codegen.runtime_contract import resolve_email_capability
from src.domain.projects.runtime_invariants import ProjectRuntimeInvariants


def _contract_with(email: dict) -> dict:
    return {
        "routes": {"admin_panel_path": "/admin", "customer_login_path": "/login"},
        "capabilities": {
            "data": {"provider": "p2hs-cloud", "available": True},
            "auth": {"provider": "p2hs-auth", "magic_link": False},
            "email": email,
        },
    }


@pytest.mark.asyncio
async def test_platform_default_resolves_and_reaches_the_generated_recipe(monkeypatch):
    monkeypatch.setattr(
        "src.integrations.email_provider.cloud_email_transport_configured", lambda settings: True
    )
    email = await resolve_email_capability(
        connector_service=SimpleNamespace(resolve_email_send=AsyncMock(return_value=None)),
        workspace_id=uuid4(),
        project_id=uuid4(),
        invariants=ProjectRuntimeInvariants(),
        enabled_capabilities=set(),
        email_domain_repo=SimpleNamespace(get_by_workspace=AsyncMock(return_value=None)),
    )
    assert email["available"] is True
    assert email["binding"] == "platform_default"

    files = app_sdk_files("html", runtime_contract=_contract_with(email))
    import json

    recipe = json.loads(files["p2hs/app-recipe.json"])
    notes = " ".join(recipe["recipes"]["send_email"]["notes"])
    assert "platform_default" in notes
    assert "unavailable" not in notes.lower()


@pytest.mark.asyncio
async def test_configured_connector_overrides_platform_default():
    decision = SimpleNamespace(allowed=True, connector=SimpleNamespace(key="mailgun"))
    email = await resolve_email_capability(
        connector_service=SimpleNamespace(resolve_email_send=AsyncMock(return_value=decision)),
        workspace_id=uuid4(),
        project_id=uuid4(),
        invariants=ProjectRuntimeInvariants(),
        enabled_capabilities=set(),
        email_domain_repo=SimpleNamespace(get_by_workspace=AsyncMock(return_value=None)),
    )
    assert email["provider"] == "p2hs-connector"
    assert email["binding"] == "mailgun"
    assert email["available"] is True
    assert email["capability"] == "email.send"
    assert email["request_type"] == "email.send"
    assert email["invoke"] == "POST /api/jobs/email.send"


@pytest.mark.asyncio
async def test_explicit_user_named_provider_is_passed_as_the_hint():
    """invariants.email_preference (from the deterministic extractor, Phase 1) is
    threaded through as resolve_email_send's provider_hint -- confirms Phase 1's
    output and Phase 2's resolver actually agree on this field's meaning."""
    connector_service = SimpleNamespace(resolve_email_send=AsyncMock(return_value=None))
    invariants = ProjectRuntimeInvariants(email_preference="resend")

    await resolve_email_capability(
        connector_service=connector_service,
        workspace_id=uuid4(),
        project_id=uuid4(),
        invariants=invariants,
        enabled_capabilities=set(),
        email_domain_repo=SimpleNamespace(get_by_workspace=AsyncMock(return_value=None)),
    )
    _, kwargs = connector_service.resolve_email_send.call_args
    assert kwargs["provider_hint"] == "resend"


@pytest.mark.asyncio
async def test_unavailable_when_nothing_is_configured_at_all(monkeypatch):
    monkeypatch.setattr(
        "src.integrations.email_provider.cloud_email_transport_configured", lambda settings: False
    )
    email = await resolve_email_capability(
        connector_service=SimpleNamespace(resolve_email_send=AsyncMock(return_value=None)),
        workspace_id=uuid4(),
        project_id=uuid4(),
        invariants=ProjectRuntimeInvariants(),
        enabled_capabilities=set(),
        email_domain_repo=SimpleNamespace(get_by_workspace=AsyncMock(return_value=None)),
    )
    assert email["available"] is False

    files = app_sdk_files("html", runtime_contract=_contract_with(email))
    import json

    recipe = json.loads(files["p2hs/app-recipe.json"])
    notes = " ".join(recipe["recipes"]["send_email"]["notes"])
    assert "unavailable" in notes.lower() or "report the missing capability" in notes.lower()
