"""E2E: domain add/remove/clear lifecycle with real Ingress verification.

Requires: K8s cluster with an Ingress controller installed.

Run with: pytest tests/e2e/test_domains_lifecycle.py -v -s
"""

from __future__ import annotations

from typing import Any

import pytest

from kuberoku.factory import KuberokuFactory
from kuberoku.k8s.resources import safe_name
from kuberoku.sdk.ingress import detect_ingress_controller
from tests.e2e.helpers import (
    cleanup_namespace_fixture,
    make_real_factory,
    skip_if_no_cluster,
    wait_for_pods_ready,
)


@pytest.fixture(scope="module")
def real_factory() -> KuberokuFactory:
    return make_real_factory("e2e-domains")


@pytest.fixture(scope="module", autouse=True)
def cleanup_namespace(real_factory: KuberokuFactory) -> Any:
    yield
    cleanup_namespace_fixture(real_factory)


def test_00_skip_if_no_cluster(real_factory: KuberokuFactory) -> None:
    skip_if_no_cluster()


def test_01_skip_if_no_ingress(real_factory: KuberokuFactory) -> None:
    controller = detect_ingress_controller(real_factory.k8s, real_factory.namespace)
    if controller is None:
        pytest.skip("No Ingress controller detected")
    print(f"\n  Ingress controller: {controller.name} ({controller.class_name})")


def test_02_create_and_deploy(real_factory: KuberokuFactory) -> None:
    real_factory.apps.create("domtest", on_step=lambda s: None)
    real_factory.deploy.deploy(
        "domtest",
        image="nginx:1.27-alpine",
        ports=[{"containerPort": 80, "protocol": "TCP"}],
        wait=False,
    )
    wait_for_pods_ready(real_factory, "domtest")
    print(f"\n  Deployed in ns: {real_factory.namespace}")


def test_03_domains_add(real_factory: KuberokuFactory) -> None:
    domain = real_factory.domains.add(
        "domtest",
        "test.example.com",
        no_tls=True,
        on_step=lambda s: print(f"  {s}"),
    )
    assert domain.hostname == "test.example.com"
    print(f"\n  Added domain: {domain.hostname}")


def test_04_verify_ingress_exists(real_factory: KuberokuFactory) -> None:
    """K8s Ingress resource should exist with the correct rule."""
    ingress_name = safe_name(real_factory.prefix, "ingress", "domtest")
    ingress = real_factory.k8s.get_ingress(real_factory.namespace, ingress_name)
    rules = ingress.get("spec", {}).get("rules", [])
    hosts = [r.get("host") for r in rules]
    assert "test.example.com" in hosts, f"Expected host not in rules: {hosts}"
    print(f"\n  Ingress verified: {ingress_name} with hosts {hosts}")


def test_05_domains_list(real_factory: KuberokuFactory) -> None:
    domains = real_factory.domains.list("domtest")
    hostnames = [d.hostname for d in domains]
    assert "test.example.com" in hostnames
    print(f"\n  Domains: {hostnames}")


def test_06_domains_remove(real_factory: KuberokuFactory) -> None:
    real_factory.domains.remove(
        "domtest",
        "test.example.com",
        on_step=lambda s: print(f"  {s}"),
    )
    domains = real_factory.domains.list("domtest")
    hostnames = [d.hostname for d in domains]
    assert "test.example.com" not in hostnames
    print(f"\n  Removed domain, remaining: {hostnames}")


def test_07_verify_ingress_removed(real_factory: KuberokuFactory) -> None:
    """Ingress should be deleted when last domain is removed."""
    ingress_name = safe_name(real_factory.prefix, "ingress", "domtest")
    try:
        real_factory.k8s.get_ingress(real_factory.namespace, ingress_name)
        pytest.fail("Ingress should have been deleted")
    except Exception:
        print(f"\n  Ingress {ingress_name} correctly removed")


def test_08_domains_clear(real_factory: KuberokuFactory) -> None:
    """Add 2 domains, clear all, verify gone."""
    real_factory.domains.add("domtest", "a.example.com", no_tls=True)
    real_factory.domains.add("domtest", "b.example.com", no_tls=True)

    domains = real_factory.domains.list("domtest")
    assert len(domains) == 2

    real_factory.domains.clear("domtest")

    domains_after = real_factory.domains.list("domtest")
    assert len(domains_after) == 0

    # Verify ingress is deleted
    ingress_name = safe_name(real_factory.prefix, "ingress", "domtest")
    try:
        real_factory.k8s.get_ingress(real_factory.namespace, ingress_name)
        pytest.fail("Ingress should have been deleted after clear")
    except Exception:
        print("\n  Clear verified: 2 domains removed, ingress deleted")


def test_09_cleanup(real_factory: KuberokuFactory) -> None:
    real_factory.apps.destroy("domtest")
    apps = real_factory.apps.list()
    assert not any(a.name == "domtest" for a in apps)
    print("\n  Cleanup complete")


def test_10_auto_domain_on_deploy(real_factory: KuberokuFactory) -> None:
    """Auto-domain should create an Ingress when KUBEROKU_BASE_DOMAIN is set."""
    with pytest.MonkeyPatch.context() as mp:
        mp.setenv("KUBEROKU_BASE_DOMAIN", "apps.test.local")
        try:
            real_factory.apps.create("autodomtest")
            real_factory.deploy.deploy(
                "autodomtest",
                image="nginx:1.27-alpine",
                ports=[{"containerPort": 80, "protocol": "TCP"}],
                wait=False,
            )
            wait_for_pods_ready(real_factory, "autodomtest")

            domains = real_factory.domains.list("autodomtest")
            auto_domains = [d for d in domains if d.auto_generated]
            if auto_domains:
                print(f"\n  Auto-domain created: {auto_domains[0].hostname}")
                assert "autodomtest" in auto_domains[0].hostname
            else:
                print("\n  Auto-domain not created (ingress controller may not support it)")
        finally:
            try:
                real_factory.apps.destroy("autodomtest")
            except Exception:
                pass


def test_11_auto_domain_idempotent(real_factory: KuberokuFactory) -> None:
    """Deploy again with auto-domain — should not duplicate."""
    with pytest.MonkeyPatch.context() as mp:
        mp.setenv("KUBEROKU_BASE_DOMAIN", "apps.test.local")
        try:
            real_factory.apps.create("autodom2")
            real_factory.deploy.deploy(
                "autodom2",
                image="nginx:1.27-alpine",
                ports=[{"containerPort": 80, "protocol": "TCP"}],
                wait=False,
            )
            wait_for_pods_ready(real_factory, "autodom2")

            # Deploy again
            real_factory.deploy.deploy(
                "autodom2",
                image="nginx:1.27",
                ports=[{"containerPort": 80, "protocol": "TCP"}],
                wait=False,
                no_procfile=True,
            )
            wait_for_pods_ready(real_factory, "autodom2", image="nginx:1.27")

            domains = real_factory.domains.list("autodom2")
            auto_domains = [d for d in domains if d.auto_generated]
            if auto_domains:
                assert len(auto_domains) == 1, f"Expected 1 auto-domain, got {len(auto_domains)}"
                print(f"\n  Auto-domain still 1: {auto_domains[0].hostname}")
            else:
                print("\n  Auto-domain not created (OK if no ingress controller)")
        finally:
            try:
                real_factory.apps.destroy("autodom2")
            except Exception:
                pass
