"""RealK8sClient — wraps K8sClient with error normalization.

Translates kubernetes ApiException (404/409) into FakeNotFoundError /
FakeConflictError so contract tests use the same exception types
regardless of backend.
"""

from __future__ import annotations

from collections.abc import Iterator
from typing import Any

from kubernetes.client.exceptions import ApiException  # type: ignore[import-untyped]

from kuberoku.k8s.client import K8sClient
from tests.backends.fake import FakeConflictError, FakeNotFoundError


def _wrap(
    fn: Any,
    args: tuple[Any, ...],
    kind: str,
    ns: str,
    name: str,
) -> Any:
    """Call *fn(*args)* and translate ApiException 404/409."""
    try:
        return fn(*args)
    except ApiException as e:
        if e.status == 404:
            raise FakeNotFoundError(kind, ns, name) from None
        if e.status == 409:
            raise FakeConflictError(str(e)) from None
        raise


def _wrap_void(
    fn: Any,
    args: tuple[Any, ...],
    kind: str,
    ns: str,
    name: str,
) -> None:
    """Like _wrap but for void methods (delete)."""
    try:
        fn(*args)
    except ApiException as e:
        if e.status == 404:
            raise FakeNotFoundError(kind, ns, name) from None
        if e.status == 409:
            raise FakeConflictError(str(e)) from None
        raise


class RealK8sClient:
    """Wraps K8sClient, normalizes ApiException to match FakeK8sClient errors."""

    def __init__(self, context: str | None = None) -> None:
        self._inner = K8sClient.from_context(context)

    # ── Namespaces ──────────────────────────────────────────────

    def get_namespace(self, name: str) -> dict[str, Any]:
        return _wrap(self._inner.get_namespace, (name,), "Namespace", "", name)

    def namespace_exists(self, name: str) -> bool:
        return self._inner.namespace_exists(name)

    def create_namespace(self, name: str) -> dict[str, Any]:
        return _wrap(self._inner.create_namespace, (name,), "Namespace", "", name)

    # ── Deployments ─────────────────────────────────────────────

    def create_deployment(self, namespace: str, body: dict[str, Any]) -> dict[str, Any]:
        n = body.get("metadata", {}).get("name", "")
        return _wrap(self._inner.create_deployment, (namespace, body), "Deployment", namespace, n)

    def get_deployment(self, namespace: str, name: str) -> dict[str, Any]:
        return _wrap(self._inner.get_deployment, (namespace, name), "Deployment", namespace, name)

    def update_deployment(self, namespace: str, name: str, body: dict[str, Any]) -> dict[str, Any]:
        return _wrap(
            self._inner.update_deployment,
            (namespace, name, body),
            "Deployment",
            namespace,
            name,
        )

    def delete_deployment(self, namespace: str, name: str) -> None:
        _wrap_void(self._inner.delete_deployment, (namespace, name), "Deployment", namespace, name)

    def list_deployments(
        self, namespace: str, labels: dict[str, str] | None = None
    ) -> list[dict[str, Any]]:
        return self._inner.list_deployments(namespace, labels)

    # ── ConfigMaps ──────────────────────────────────────────────

    def create_configmap(self, namespace: str, body: dict[str, Any]) -> dict[str, Any]:
        n = body.get("metadata", {}).get("name", "")
        return _wrap(self._inner.create_configmap, (namespace, body), "ConfigMap", namespace, n)

    def get_configmap(self, namespace: str, name: str) -> dict[str, Any]:
        return _wrap(self._inner.get_configmap, (namespace, name), "ConfigMap", namespace, name)

    def update_configmap(self, namespace: str, name: str, body: dict[str, Any]) -> dict[str, Any]:
        return _wrap(
            self._inner.update_configmap,
            (namespace, name, body),
            "ConfigMap",
            namespace,
            name,
        )

    def delete_configmap(self, namespace: str, name: str) -> None:
        _wrap_void(self._inner.delete_configmap, (namespace, name), "ConfigMap", namespace, name)

    def list_configmaps(
        self, namespace: str, labels: dict[str, str] | None = None
    ) -> list[dict[str, Any]]:
        return self._inner.list_configmaps(namespace, labels)

    # ── Secrets ─────────────────────────────────────────────────

    def create_secret(self, namespace: str, body: dict[str, Any]) -> dict[str, Any]:
        n = body.get("metadata", {}).get("name", "")
        return _wrap(self._inner.create_secret, (namespace, body), "Secret", namespace, n)

    def get_secret(self, namespace: str, name: str) -> dict[str, Any]:
        return _wrap(self._inner.get_secret, (namespace, name), "Secret", namespace, name)

    def update_secret(self, namespace: str, name: str, body: dict[str, Any]) -> dict[str, Any]:
        return _wrap(
            self._inner.update_secret,
            (namespace, name, body),
            "Secret",
            namespace,
            name,
        )

    def delete_secret(self, namespace: str, name: str) -> None:
        _wrap_void(self._inner.delete_secret, (namespace, name), "Secret", namespace, name)

    def list_secrets(
        self, namespace: str, labels: dict[str, str] | None = None
    ) -> list[dict[str, Any]]:
        return self._inner.list_secrets(namespace, labels)

    # ── Services ────────────────────────────────────────────────

    def create_service(self, namespace: str, body: dict[str, Any]) -> dict[str, Any]:
        n = body.get("metadata", {}).get("name", "")
        return _wrap(self._inner.create_service, (namespace, body), "Service", namespace, n)

    def get_service(self, namespace: str, name: str) -> dict[str, Any]:
        return _wrap(self._inner.get_service, (namespace, name), "Service", namespace, name)

    def update_service(self, namespace: str, name: str, body: dict[str, Any]) -> dict[str, Any]:
        return _wrap(
            self._inner.update_service,
            (namespace, name, body),
            "Service",
            namespace,
            name,
        )

    def delete_service(self, namespace: str, name: str) -> None:
        _wrap_void(self._inner.delete_service, (namespace, name), "Service", namespace, name)

    def list_services(
        self, namespace: str, labels: dict[str, str] | None = None
    ) -> list[dict[str, Any]]:
        return self._inner.list_services(namespace, labels)

    # ── Pods (limited) ──────────────────────────────────────────

    def create_pod(self, namespace: str, body: dict[str, Any]) -> dict[str, Any]:
        n = body.get("metadata", {}).get("name", "")
        return _wrap(self._inner.create_pod, (namespace, body), "Pod", namespace, n)

    def list_pods(
        self, namespace: str, labels: dict[str, str] | None = None
    ) -> list[dict[str, Any]]:
        return self._inner.list_pods(namespace, labels)

    def delete_pod(self, namespace: str, name: str) -> None:
        _wrap_void(self._inner.delete_pod, (namespace, name), "Pod", namespace, name)

    def exec_in_pod(
        self,
        namespace: str,
        name: str,
        command: list[str],
        tty: bool = False,
        container: str | None = None,
    ) -> str:
        return self._inner.exec_in_pod(namespace, name, command, tty, container)

    def stream_pod_logs(
        self,
        namespace: str,
        name: str,
        follow: bool = False,
        tail_lines: int | None = None,
        since_seconds: int | None = None,
        previous: bool = False,
    ) -> Iterator[str]:
        return self._inner.stream_pod_logs(
            namespace, name, follow, tail_lines, since_seconds, previous
        )

    # ── Ingress ─────────────────────────────────────────────────

    def create_ingress(self, namespace: str, body: dict[str, Any]) -> dict[str, Any]:
        n = body.get("metadata", {}).get("name", "")
        return _wrap(self._inner.create_ingress, (namespace, body), "Ingress", namespace, n)

    def get_ingress(self, namespace: str, name: str) -> dict[str, Any]:
        return _wrap(self._inner.get_ingress, (namespace, name), "Ingress", namespace, name)

    def update_ingress(self, namespace: str, name: str, body: dict[str, Any]) -> dict[str, Any]:
        return _wrap(
            self._inner.update_ingress,
            (namespace, name, body),
            "Ingress",
            namespace,
            name,
        )

    def delete_ingress(self, namespace: str, name: str) -> None:
        _wrap_void(self._inner.delete_ingress, (namespace, name), "Ingress", namespace, name)

    def list_ingresses(
        self, namespace: str, labels: dict[str, str] | None = None
    ) -> list[dict[str, Any]]:
        return self._inner.list_ingresses(namespace, labels)

    def list_ingress_classes(self) -> list[dict[str, Any]]:
        return self._inner.list_ingress_classes()

    def create_ingress_class(self, body: dict[str, Any]) -> None:
        self._inner.create_ingress_class(body)

    # ── StatefulSets ────────────────────────────────────────────

    def create_statefulset(self, namespace: str, body: dict[str, Any]) -> dict[str, Any]:
        n = body.get("metadata", {}).get("name", "")
        return _wrap(
            self._inner.create_statefulset, (namespace, body), "StatefulSet", namespace, n
        )

    def get_statefulset(self, namespace: str, name: str) -> dict[str, Any]:
        return _wrap(
            self._inner.get_statefulset, (namespace, name), "StatefulSet", namespace, name
        )

    def update_statefulset(
        self, namespace: str, name: str, body: dict[str, Any]
    ) -> dict[str, Any]:
        return _wrap(
            self._inner.update_statefulset,
            (namespace, name, body),
            "StatefulSet",
            namespace,
            name,
        )

    def delete_statefulset(self, namespace: str, name: str) -> None:
        _wrap_void(
            self._inner.delete_statefulset,
            (namespace, name),
            "StatefulSet",
            namespace,
            name,
        )

    def list_statefulsets(
        self, namespace: str, labels: dict[str, str] | None = None
    ) -> list[dict[str, Any]]:
        return self._inner.list_statefulsets(namespace, labels)

    # ── PVCs ────────────────────────────────────────────────────

    def create_pvc(self, namespace: str, body: dict[str, Any]) -> dict[str, Any]:
        n = body.get("metadata", {}).get("name", "")
        return _wrap(self._inner.create_pvc, (namespace, body), "PVC", namespace, n)

    def get_pvc(self, namespace: str, name: str) -> dict[str, Any]:
        return _wrap(self._inner.get_pvc, (namespace, name), "PVC", namespace, name)

    def delete_pvc(self, namespace: str, name: str) -> None:
        _wrap_void(self._inner.delete_pvc, (namespace, name), "PVC", namespace, name)

    def list_pvcs(
        self, namespace: str, labels: dict[str, str] | None = None
    ) -> list[dict[str, Any]]:
        return self._inner.list_pvcs(namespace, labels)

    # ── Jobs ────────────────────────────────────────────────────

    def create_job(self, namespace: str, body: dict[str, Any]) -> dict[str, Any]:
        n = body.get("metadata", {}).get("name", "")
        return _wrap(self._inner.create_job, (namespace, body), "Job", namespace, n)

    def wait_for_job(self, namespace: str, name: str, timeout: int = 300) -> dict[str, Any]:
        return _wrap(self._inner.wait_for_job, (namespace, name, timeout), "Job", namespace, name)

    def delete_job(self, namespace: str, name: str) -> None:
        _wrap_void(self._inner.delete_job, (namespace, name), "Job", namespace, name)

    # ── HPA ─────────────────────────────────────────────────────

    def create_hpa(self, namespace: str, body: dict[str, Any]) -> dict[str, Any]:
        n = body.get("metadata", {}).get("name", "")
        return _wrap(self._inner.create_hpa, (namespace, body), "HPA", namespace, n)

    def get_hpa(self, namespace: str, name: str) -> dict[str, Any]:
        return _wrap(self._inner.get_hpa, (namespace, name), "HPA", namespace, name)

    def update_hpa(self, namespace: str, name: str, body: dict[str, Any]) -> dict[str, Any]:
        return _wrap(self._inner.update_hpa, (namespace, name, body), "HPA", namespace, name)

    def delete_hpa(self, namespace: str, name: str) -> None:
        _wrap_void(self._inner.delete_hpa, (namespace, name), "HPA", namespace, name)

    # ── NetworkPolicies ────────────────────────────────────────

    def create_network_policy(self, namespace: str, body: dict[str, Any]) -> dict[str, Any]:
        n = body.get("metadata", {}).get("name", "")
        return _wrap(
            self._inner.create_network_policy,
            (namespace, body),
            "NetworkPolicy",
            namespace,
            n,
        )

    def get_network_policy(self, namespace: str, name: str) -> dict[str, Any]:
        return _wrap(
            self._inner.get_network_policy,
            (namespace, name),
            "NetworkPolicy",
            namespace,
            name,
        )

    def update_network_policy(
        self, namespace: str, name: str, body: dict[str, Any]
    ) -> dict[str, Any]:
        return _wrap(
            self._inner.update_network_policy,
            (namespace, name, body),
            "NetworkPolicy",
            namespace,
            name,
        )

    def delete_network_policy(self, namespace: str, name: str) -> None:
        _wrap_void(
            self._inner.delete_network_policy,
            (namespace, name),
            "NetworkPolicy",
            namespace,
            name,
        )

    def list_network_policies(
        self, namespace: str, labels: dict[str, str] | None = None
    ) -> list[dict[str, Any]]:
        return self._inner.list_network_policies(namespace, labels)

    # ── Cluster info ───────────────────────────────────────────

    @property
    def cluster_endpoint(self) -> str:
        return self._inner.cluster_endpoint

    # ── Auth ────────────────────────────────────────────────────

    def can_i(self, verb: str, resource: str, namespace: str = "") -> bool:
        return self._inner.can_i(verb, resource, namespace)

    # ── StorageClasses ────────────────────────────────────────

    def list_storage_classes(self) -> list[dict[str, Any]]:
        return self._inner.list_storage_classes()
