"""Deploy account selection: default unchanged, override uses the workspace's account, and an
override with no account fails closed."""

from types import SimpleNamespace
from uuid import UUID

import pytest

from src.config import Settings
from src.domain.hosting.deploy_target import DeployAccountError, settings_for_workspace, workspace_uses_account_override

WS = UUID("5e890ff3-5c7b-43f5-a4ad-75c47f90bdba")
OTHER = UUID("9eb2c997-6e10-4162-b776-b4e03e4553b7")


def _settings(listed: str = "") -> Settings:
    return Settings(
        cloudflare_account_id="8551c80e9c3a0422d2fef6e2800d6143",
        cloudflare_api_token="GLOBAL",
        cloudflare_zone_id="ZONE-GLOBAL",
        cloudflare_w4p_namespace_production="p2hs-production",
        hosting_deploy_account_workspace_ids=listed,
    )


def _creds(**overrides):
    base = dict(account_id="b6152b2d03f9bbcc29e0023a294163d5", api_token="PLATFORM", zone_id="",
                w4p_namespace_production="p2hs-production", w4p_namespace_preview="p2hs-previews",
                w4p_namespace_staging="p2hs-staging", dispatch_kv_namespace_id="P2HS", w4p_trusted_workers=False,
                worker_compatibility_date="2026-03-25")
    base.update(overrides)
    return SimpleNamespace(**base)


async def _resolver(creds):
    async def resolve(_workspace_id):
        if isinstance(creds, Exception):
            raise creds
        return creds
    return resolve


def test_override_list_matches_only_listed_workspaces():
    s = _settings(listed=str(WS))
    assert workspace_uses_account_override(WS, s) is True
    assert workspace_uses_account_override(OTHER, s) is False
    assert workspace_uses_account_override(WS, _settings()) is False


@pytest.mark.asyncio
async def test_default_returns_the_global_settings_unchanged():
    s = _settings()
    out = await settings_for_workspace(WS, s, await _resolver(_creds()))
    assert out is s


@pytest.mark.asyncio
async def test_listed_workspace_deploys_to_its_assigned_account():
    s = _settings(listed=str(WS))
    out = await settings_for_workspace(WS, s, await _resolver(_creds()))
    assert out.cloudflare_account_id == "b6152b2d03f9bbcc29e0023a294163d5"
    assert out.cloudflare_api_token == "PLATFORM"
    assert out.cloudflare_zone_id == ""
    assert out.cloudflare_dispatch_kv_namespace_id == "P2HS"
    # The global settings are not modified.
    assert s.cloudflare_account_id == "8551c80e9c3a0422d2fef6e2800d6143"


@pytest.mark.asyncio
async def test_listed_workspace_without_assignment_fails_closed():
    s = _settings(listed=str(WS))
    with pytest.raises(DeployAccountError, match="no_assigned_cloud_account"):
        await settings_for_workspace(WS, s, await _resolver(LookupError("no assignment")))


@pytest.mark.asyncio
async def test_listed_workspace_with_incomplete_credentials_fails_closed():
    s = _settings(listed=str(WS))
    with pytest.raises(DeployAccountError, match="missing_credentials"):
        await settings_for_workspace(WS, s, await _resolver(_creds(api_token="")))


from datetime import datetime, timezone  # noqa: E402

CUTOFF = "2026-10-07T00:00:00+00:00"


def _platform_settings(cutoff: str = CUTOFF, apex: str = "p2hs.dev") -> Settings:
    return Settings(
        cloudflare_account_id="8551c80e9c3a0422d2fef6e2800d6143",
        cloudflare_api_token="GLOBAL",
        cloudflare_zone_id="ZONE-GLOBAL",
        hosting_public_apex="p2hsapp.com",
        hosting_platform_projects_created_after=cutoff,
        new_cloudflare_account_id="b6152b2d03f9bbcc29e0023a294163d5",
        new_cloudflare_api_token="PLATFORM",
        new_hosting_public_apex=apex,
        hosting_platform_account_enabled=True,
    )


@pytest.mark.asyncio
async def test_no_cutoff_keeps_every_existing_project_on_the_global_account_and_apex():
    from src.domain.hosting.deploy_target import settings_for_project
    s = _platform_settings(cutoff="")
    out = await settings_for_project(WS, datetime(2026, 10, 8, tzinfo=timezone.utc), s, await _resolver(_creds()))
    assert out is s


@pytest.mark.asyncio
async def test_project_created_after_cutoff_deploys_to_platform_on_the_new_apex():
    from src.domain.hosting.deploy_target import settings_for_project
    s = _platform_settings()
    out = await settings_for_project(WS, datetime(2026, 10, 8, tzinfo=timezone.utc), s, await _resolver(_creds()))
    assert out.cloudflare_account_id == "b6152b2d03f9bbcc29e0023a294163d5"
    assert out.cloudflare_api_token == "PLATFORM"
    assert out.cloudflare_zone_id == ""
    assert out.hosting_public_apex == "p2hs.dev"


@pytest.mark.asyncio
async def test_project_created_before_cutoff_keeps_its_apex_and_account():
    from src.domain.hosting.deploy_target import settings_for_project
    s = _platform_settings()
    out = await settings_for_project(WS, datetime(2026, 9, 1, tzinfo=timezone.utc), s, await _resolver(_creds()))
    assert out is s
    assert out.hosting_public_apex == "p2hsapp.com"


@pytest.mark.asyncio
async def test_new_project_does_not_call_the_workspace_lookup():
    from src.domain.hosting.deploy_target import settings_for_project
    called = []

    async def resolver(_ws):
        called.append(True)
        return _creds()

    await settings_for_project(WS, datetime(2026, 10, 8, tzinfo=timezone.utc), _platform_settings(), resolver)
    assert called == []


@pytest.mark.asyncio
async def test_new_project_fails_closed_without_a_platform_apex():
    from src.domain.hosting.deploy_target import settings_for_project
    s = _platform_settings(apex="")
    with pytest.raises(DeployAccountError, match="platform_apex_not_configured"):
        await settings_for_project(WS, datetime(2026, 10, 8, tzinfo=timezone.utc), s, await _resolver(_creds()))


@pytest.mark.asyncio
async def test_new_project_fails_closed_without_a_platform_account_token():
    """A new project must never fall back to the original account when the platform account is unset."""
    from src.domain.hosting.deploy_target import settings_for_project
    s = _platform_settings().model_copy(update={"new_cloudflare_api_token": ""})
    with pytest.raises(DeployAccountError, match="platform_account_not_configured"):
        await settings_for_project(WS, datetime(2026, 10, 8, tzinfo=timezone.utc), s, await _resolver(_creds()))


def test_project_hosting_provider_is_w4p_for_new_projects_and_global_for_existing():
    from src.domain.hosting.project_provider import W4P_STATIC, project_hosting_provider
    s = _platform_settings().model_copy(update={"hosting_provider": "cloudflare_pages"})
    assert project_hosting_provider(datetime(2026, 10, 8, tzinfo=timezone.utc), s) == W4P_STATIC
    assert project_hosting_provider(datetime(2026, 9, 1, tzinfo=timezone.utc), s) == "cloudflare_pages"
    assert project_hosting_provider(None, s) == "cloudflare_pages"


def test_unassigned_existing_project_can_be_selected_for_w4p_migration():
    from src.domain.hosting.project_provider import W4P_STATIC, project_hosting_provider
    s = _platform_settings().model_copy(update={"hosting_provider": "cloudflare_pages"})
    assert project_hosting_provider(
        datetime(2026, 9, 1, tzinfo=timezone.utc),
        s,
        assume_unassigned_w4p=True,
    ) == W4P_STATIC
    assert project_hosting_provider(
        datetime(2026, 9, 1, tzinfo=timezone.utc),
        s,
        primary_hosting_provider="cloudflare_pages",
        assume_unassigned_w4p=True,
    ) == "cloudflare_pages"


def test_existing_live_pages_project_is_not_auto_migrated():
    from src.domain.hosting.project_provider import project_hosting_provider

    s = _platform_settings().model_copy(update={"hosting_provider": "cloudflare_pages"})
    assert project_hosting_provider(
        datetime(2026, 9, 1, tzinfo=timezone.utc),
        s,
        assume_unassigned_w4p=True,
        has_successful_pages_deployment=True,
    ) == "cloudflare_pages"


def test_pages_marked_never_deployed_is_eligible_for_migration():
    from src.domain.hosting.project_provider import W4P_STATIC, project_hosting_provider

    s = _platform_settings().model_copy(update={"hosting_provider": "cloudflare_pages"})
    assert project_hosting_provider(
        datetime(2026, 9, 1, tzinfo=timezone.utc),
        s,
        primary_hosting_provider="cloudflare_pages",
        assume_unassigned_w4p=True,
        has_successful_pages_deployment=False,
    ) == W4P_STATIC


def test_pages_project_limit_error_is_narrowly_recognized():
    from src.domain.hosting.project_provider import is_pages_project_limit_error
    assert is_pages_project_limit_error("code 8000027: reached the limit of projects")
    assert not is_pages_project_limit_error("code 10090: authentication failed")
