"""Tests for KuberokuFactory — dependency wiring."""

from __future__ import annotations

import os
from unittest.mock import patch

import pytest

from kuberoku.branding import DEFAULT_LABEL_DOMAIN, DEFAULT_NAMESPACE, DEFAULT_RESOURCE_PREFIX
from kuberoku.factory import KuberokuFactory
from kuberoku.sdk.apps import AppsService
from tests.backends.fake import FakeK8sClient


class TestFactory:
    def test_defaults(self) -> None:
        f = KuberokuFactory(k8s_client=FakeK8sClient())
        assert f.namespace == DEFAULT_NAMESPACE
        assert f.prefix == DEFAULT_RESOURCE_PREFIX
        assert f.domain == DEFAULT_LABEL_DOMAIN

    def test_custom_namespace(self) -> None:
        f = KuberokuFactory(k8s_client=FakeK8sClient(), namespace="custom")
        assert f.namespace == "custom"

    def test_custom_prefix(self) -> None:
        f = KuberokuFactory(k8s_client=FakeK8sClient(), resource_prefix="k8u")
        assert f.prefix == "k8u"

    def test_custom_domain(self) -> None:
        f = KuberokuFactory(k8s_client=FakeK8sClient(), label_domain="app.k8u.io")
        assert f.domain == "app.k8u.io"

    def test_k8s_returns_injected_client(self) -> None:
        client = FakeK8sClient()
        f = KuberokuFactory(k8s_client=client)
        assert f.k8s is client

    def test_apps_service_cached(self) -> None:
        f = KuberokuFactory(k8s_client=FakeK8sClient())
        s1 = f.apps
        s2 = f.apps
        assert s1 is s2

    def test_apps_service_type(self) -> None:
        f = KuberokuFactory(k8s_client=FakeK8sClient())
        assert isinstance(f.apps, AppsService)

    def test_ensure_namespace_creates(self) -> None:
        client = FakeK8sClient()
        f = KuberokuFactory(k8s_client=client, namespace="new-ns")
        f.ensure_namespace()
        assert client.namespace_exists("new-ns")

    def test_ensure_namespace_idempotent(self) -> None:
        client = FakeK8sClient()
        f = KuberokuFactory(k8s_client=client, namespace="new-ns")
        f.ensure_namespace()
        f.ensure_namespace()  # No error on second call
        assert client.namespace_exists("new-ns")

    def test_ensure_namespace_race_condition(self) -> None:
        """create_namespace fails but namespace appeared (concurrent creation).

        Scenario: two processes race to create the namespace. One wins, the
        other gets a 409 Conflict. The loser's ensure_namespace should succeed
        because the namespace now exists.
        """
        client = FakeK8sClient()
        f = KuberokuFactory(k8s_client=client, namespace="race-ns")

        # Pre-create the namespace so namespace_exists returns True after failure
        client.create_namespace("race-ns")

        # Make create_namespace raise (simulating 409 Conflict)
        with patch.object(
            client,
            "create_namespace",
            side_effect=RuntimeError("Conflict: namespace already exists"),
        ):
            f.ensure_namespace()  # Should NOT raise
        assert client.namespace_exists("race-ns")

    def test_ensure_namespace_real_failure(self) -> None:
        """create_namespace fails AND namespace doesn't exist → raises."""
        client = FakeK8sClient()
        f = KuberokuFactory(k8s_client=client, namespace="missing-ns")

        with (
            patch.object(
                client,
                "create_namespace",
                side_effect=PermissionError("forbidden: cannot create namespaces"),
            ),
            pytest.raises(PermissionError, match="forbidden"),
        ):
            f.ensure_namespace()

    def test_namespace_from_env_var(self) -> None:
        """KUBEROKU_NAMESPACE env var overrides default namespace."""
        client = FakeK8sClient()
        with patch.dict(os.environ, {"KUBEROKU_NAMESPACE": "env-ns"}):
            f = KuberokuFactory(k8s_client=client)
            assert f.namespace == "env-ns"
