"""Contract tests: PVC CRUD + list on fake (and real with --backend=real)."""

from __future__ import annotations

import pytest

from tests.backends.fake import FakeK8sClient, FakeNotFoundError
from tests.e2e.helpers import poll_until


def _make_pvc(name: str = "my-pvc") -> dict[str, object]:
    return {
        "apiVersion": "v1",
        "kind": "PersistentVolumeClaim",
        "metadata": {
            "name": name,
            "labels": {"app": "test"},
        },
        "spec": {
            "accessModes": ["ReadWriteOnce"],
            "resources": {"requests": {"storage": "1Gi"}},
        },
    }


def test_create_pvc(k8s_client: FakeK8sClient, tmp_namespace: str) -> None:
    result = k8s_client.create_pvc(tmp_namespace, _make_pvc())
    assert result["metadata"]["name"] == "my-pvc"


def test_get_pvc(k8s_client: FakeK8sClient, tmp_namespace: str) -> None:
    k8s_client.create_pvc(tmp_namespace, _make_pvc())
    pvc = k8s_client.get_pvc(tmp_namespace, "my-pvc")
    assert pvc["metadata"]["name"] == "my-pvc"


def test_get_pvc_not_found(k8s_client: FakeK8sClient, tmp_namespace: str) -> None:
    with pytest.raises(FakeNotFoundError):
        k8s_client.get_pvc(tmp_namespace, "nonexistent")


def test_delete_pvc(k8s_client: FakeK8sClient, tmp_namespace: str) -> None:
    k8s_client.create_pvc(tmp_namespace, _make_pvc())
    k8s_client.delete_pvc(tmp_namespace, "my-pvc")

    # Real K8s PVC deletion is async (finalizers keep the resource alive with a
    # deletionTimestamp until the volume is released).  Poll until the PVC is
    # either truly gone (FakeNotFoundError / 404) or marked for deletion.
    def _pvc_gone_or_deleting() -> bool:
        try:
            pvc = k8s_client.get_pvc(tmp_namespace, "my-pvc")
        except FakeNotFoundError:
            return True  # PVC fully removed
        # If deletionTimestamp is set, deletion is in progress — that counts.
        return bool(pvc.get("metadata", {}).get("deletionTimestamp"))

    poll_until(
        fn=_pvc_gone_or_deleting,
        predicate=lambda gone: gone,
        timeout=30,
        interval=0.5,
        message="PVC my-pvc still exists after delete",
    )


def test_list_pvcs(k8s_client: FakeK8sClient, tmp_namespace: str) -> None:
    k8s_client.create_pvc(tmp_namespace, _make_pvc("pvc-1"))
    k8s_client.create_pvc(tmp_namespace, _make_pvc("pvc-2"))
    result = k8s_client.list_pvcs(tmp_namespace)
    assert len(result) >= 2


def test_list_pvcs_with_labels(k8s_client: FakeK8sClient, tmp_namespace: str) -> None:
    k8s_client.create_pvc(tmp_namespace, _make_pvc())
    # Real K8s may have a brief delay before label index is queryable
    result = poll_until(
        fn=lambda: k8s_client.list_pvcs(tmp_namespace, labels={"app": "test"}),
        predicate=lambda r: len(r) >= 1,
        timeout=10,
        interval=0.5,
        message="PVC with label app=test not found",
    )
    assert len(result) == 1
    result_empty = k8s_client.list_pvcs(tmp_namespace, labels={"app": "other"})
    assert len(result_empty) == 0
