"""Hosting is a project-scoped profile, not a name checked inside generic orchestration."""

from datetime import UTC, datetime
from types import SimpleNamespace

from src.domain.hosting.deployment_targets import deploy_workflow_for_project
from src.domain.hosting.factory import get_runtime_projection_adapter
from src.domain.hosting.managed_files import classify_managed_file
from src.domain.hosting.profile import (
    ApplicationHostingRequirements,
    HostingProfile,
    evaluate_hosting_compatibility,
    plan_hosting_migration,
    register_hosting_profile,
    register_projection_factory,
    register_workflow_renderer,
    resolve_hosting_profile,
    unregister_hosting_profile,
    unregister_workflow_renderer,
)
from src.domain.hosting.project_provider import W4P_STATIC, project_hosting_provider
from src.domain.hosting.runtime_projection import (
    LegacyPagesRuntimeProjection,
    W4PSharedBFFRuntimeProjection,
)


def _settings():
    from src.config import Settings

    return Settings(
        hosting_provider="cloudflare_pages",
        hosting_platform_projects_created_after="2026-10-08T00:00:00+00:00",
    )


def test_explicit_provider_beats_the_cutoff_and_the_global_default():
    created = datetime(2026, 10, 9, tzinfo=UTC)
    assert project_hosting_provider(
        created,
        _settings(),
        primary_hosting_provider="fake_static",
    ) == "fake_static"


def test_empty_selection_uses_the_default_profile():
    profile = resolve_hosting_profile(None, default_provider="w4p")
    assert profile.provider_id == W4P_STATIC
    assert profile.server_function_surface == "worker_bundle"
    assert profile.ssr_supported is False


def test_w4p_is_the_only_default_and_pages_stays_a_legacy_target():
    from src.domain.hosting.profile import platform_default_profile, provider_for_new_project

    default = platform_default_profile()
    pages = resolve_hosting_profile("cloudflare_pages", default_provider=W4P_STATIC)
    assert default.provider_id == W4P_STATIC
    assert default.lifecycle == "default"
    assert pages.lifecycle == "legacy"
    assert pages.migration_source is True
    assert pages.migration_target is True
    assert provider_for_new_project("html") == W4P_STATIC
    try:
        provider_for_new_project("html", "cloudflare_pages")
    except Exception as exc:
        assert "legacy" in str(exc)
    else:
        raise AssertionError("Pages was selectable for a new project")
    assert provider_for_new_project(
        "react_app",
        "cloudflare_pages",
        authorized_override=True,
    ) == "cloudflare_pages"


def test_w4p_to_pages_is_an_explicit_migration_and_does_not_move_the_active_provider():
    plan = plan_hosting_migration(
        "w4p",
        "cloudflare_pages",
        ApplicationHostingRequirements("react_app"),
    )
    assert plan.platform_default == W4P_STATIC
    assert plan.active_provider == W4P_STATIC
    assert plan.migration_target == "cloudflare_pages"
    assert plan.commits_active_provider is False
    assert plan.mutates_production is False
    assert plan.compatibility.status == "compatible_with_transformation"


def test_persisted_pages_selection_is_not_replaced_by_a_w4p_default():
    profile = resolve_hosting_profile("cloudflare", default_provider=W4P_STATIC)
    assert profile.provider_id == "cloudflare_pages"
    assert profile.server_function_surface == "pages_functions"


def test_nuxt_ssr_moves_to_w4p_only_as_a_static_transformation():
    plan = plan_hosting_migration(
        "cloudflare_pages",
        "w4p",
        ApplicationHostingRequirements("nuxt_app", requires_ssr=True),
    )
    assert plan.dry_run is True
    assert plan.mutates_production is False
    assert plan.compatibility.status == "compatible_with_transformation"
    assert "activate_traffic" in plan.stages
    assert any("Nitro" in reason for reason in plan.compatibility.remediations)


def test_html_ssr_is_blocked_instead_of_reported_compatible():
    result = evaluate_hosting_compatibility(
        resolve_hosting_profile("cloudflare_pages", default_provider="cloudflare_pages"),
        resolve_hosting_profile("w4p", default_provider="w4p"),
        ApplicationHostingRequirements("html", requires_ssr=True),
    )
    assert result.status == "blocked"


def test_fake_provider_uses_generic_workflow_projection_and_preflight():
    provider_id = "fake_static"
    workflow_id = "fake_static_workflow"
    sentinel = object()

    def render(profile, project_type, project_ref, settings):
        del profile, project_type, project_ref, settings
        return "name: Fake host\n"

    def projection():
        return sentinel

    register_hosting_profile(HostingProfile(
        provider_id=provider_id,
        profile_version=1,
        lifecycle="supported",
        migration_source=True,
        migration_target=True,
        supported_frameworks=frozenset({"html", "react_app", "nuxt_app"}),
        static_assets=True,
        ssr_supported=False,
        server_function_surface="none",
        bff_strategy="none",
        execution_mode="static",
        runtime_restrictions=(),
        build_outputs={"html": ("", "")},
        secret_bindings=(),
        preview_supported=True,
        routing_strategy="fake_dns",
        ssl_lifecycle="provider_managed",
        health_check="fake_health",
        rollback_supported=False,
        workflow_id=workflow_id,
        projection_id="fake_projection",
        migration_requirements=("preview_before_cutover",),
    ))
    register_workflow_renderer(workflow_id, render)
    register_projection_factory("fake_projection", projection)
    try:
        workflow = deploy_workflow_for_project(
            "html",
            "pabc12345",
            datetime(2026, 10, 9, tzinfo=UTC),
            SimpleNamespace(),
            primary_hosting_provider=provider_id,
        )
        assert workflow == "name: Fake host\n"
        assert get_runtime_projection_adapter(provider_id=provider_id) is sentinel
        plan = plan_hosting_migration(
            "cloudflare_pages",
            provider_id,
            ApplicationHostingRequirements("html"),
        )
        assert plan.compatibility.status == "blocked"
        assert plan.stages == ("discover", "resolve_profiles", "evaluate_compatibility")
        assert plan.mutates_production is False
    finally:
        unregister_hosting_profile(provider_id)
        unregister_workflow_renderer(workflow_id)


def test_existing_projection_adapters_remain_bound_to_their_profiles():
    assert isinstance(
        get_runtime_projection_adapter(SimpleNamespace(hosting_provider=W4P_STATIC)),
        W4PSharedBFFRuntimeProjection,
    )
    assert isinstance(
        get_runtime_projection_adapter(SimpleNamespace(hosting_provider="cloudflare_pages")),
        LegacyPagesRuntimeProjection,
    )


def test_customer_edit_of_a_managed_file_is_a_conflict():
    assert classify_managed_file(None, None, "next") == "create"
    assert classify_managed_file("next", "recorded", "next") == "unchanged"
    assert classify_managed_file("owned", classify_hash("owned"), "next") == "regenerate"
    assert classify_managed_file("customer", classify_hash("owned"), "next") == "conflict"


def classify_hash(text: str) -> str:
    from src.domain.hosting.managed_files import content_hash

    return content_hash(text)


def test_catalog_install_preserves_a_customer_edit(tmp_path):
    from src.domain.codegen.port_adapter import install_catalog_adapters

    install_catalog_adapters(str(tmp_path), "html", {"legacy_contact_submit": False})
    target = tmp_path / "functions" / "_lib" / "p2hs-ports.mjs"
    original = target.read_text(encoding="utf-8")
    target.write_text(original + "\n// customer edit\n", encoding="utf-8")
    result = install_catalog_adapters(str(tmp_path), "html", {"legacy_contact_submit": False})
    assert "functions/_lib/p2hs-ports.mjs" in result["conflicts"]
    assert target.read_text(encoding="utf-8").endswith("// customer edit\n")
