"""Contract tests: ConfigMap CRUD.

These tests run identically on FakeK8sClient and the real K8s cluster,
proving the fake matches real K8s behavior for ConfigMap operations.
"""

from __future__ import annotations

import pytest

from tests.backends.fake import FakeConflictError, FakeNotFoundError


class TestConfigMapCRUD:
    """ConfigMap create / get / update / delete contract."""

    def test_create_and_get(self, k8s_client, tmp_namespace):
        body = {
            "apiVersion": "v1",
            "kind": "ConfigMap",
            "metadata": {"name": "test-cm"},
            "data": {"key1": "value1", "key2": "value2"},
        }
        created = k8s_client.create_configmap(tmp_namespace, body)
        assert created["metadata"]["name"] == "test-cm"
        assert "resourceVersion" in created["metadata"]

        fetched = k8s_client.get_configmap(tmp_namespace, "test-cm")
        assert fetched["data"]["key1"] == "value1"
        assert fetched["data"]["key2"] == "value2"
        assert fetched["metadata"]["name"] == "test-cm"

    def test_create_already_exists_raises_conflict(self, k8s_client, tmp_namespace):
        body = {
            "apiVersion": "v1",
            "kind": "ConfigMap",
            "metadata": {"name": "dup-cm"},
            "data": {"a": "1"},
        }
        k8s_client.create_configmap(tmp_namespace, body)
        with pytest.raises(FakeConflictError):
            k8s_client.create_configmap(tmp_namespace, body)

    def test_get_not_found_raises(self, k8s_client, tmp_namespace):
        with pytest.raises(FakeNotFoundError):
            k8s_client.get_configmap(tmp_namespace, "no-such-cm")

    def test_update_changes_data(self, k8s_client, tmp_namespace):
        body = {
            "apiVersion": "v1",
            "kind": "ConfigMap",
            "metadata": {"name": "upd-cm"},
            "data": {"key": "old"},
        }
        created = k8s_client.create_configmap(tmp_namespace, body)
        rv = created["metadata"]["resourceVersion"]

        updated_body = {
            "apiVersion": "v1",
            "kind": "ConfigMap",
            "metadata": {"name": "upd-cm", "resourceVersion": rv},
            "data": {"key": "new"},
        }
        updated = k8s_client.update_configmap(tmp_namespace, "upd-cm", updated_body)
        assert updated["data"]["key"] == "new"
        assert updated["metadata"]["resourceVersion"] != rv

        fetched = k8s_client.get_configmap(tmp_namespace, "upd-cm")
        assert fetched["data"]["key"] == "new"

    def test_update_not_found_raises(self, k8s_client, tmp_namespace):
        body = {
            "apiVersion": "v1",
            "kind": "ConfigMap",
            "metadata": {"name": "ghost-cm"},
            "data": {"x": "y"},
        }
        with pytest.raises(FakeNotFoundError):
            k8s_client.update_configmap(tmp_namespace, "ghost-cm", body)

    def test_update_stale_resource_version_raises_conflict(self, k8s_client, tmp_namespace):
        body = {
            "apiVersion": "v1",
            "kind": "ConfigMap",
            "metadata": {"name": "conflict-cm"},
            "data": {"v": "1"},
        }
        created = k8s_client.create_configmap(tmp_namespace, body)
        stale_rv = created["metadata"]["resourceVersion"]

        # Do a valid update to advance the resourceVersion
        fresh_body = {
            "apiVersion": "v1",
            "kind": "ConfigMap",
            "metadata": {"name": "conflict-cm", "resourceVersion": stale_rv},
            "data": {"v": "2"},
        }
        k8s_client.update_configmap(tmp_namespace, "conflict-cm", fresh_body)

        # Now try with the stale resourceVersion
        stale_body = {
            "apiVersion": "v1",
            "kind": "ConfigMap",
            "metadata": {"name": "conflict-cm", "resourceVersion": stale_rv},
            "data": {"v": "3"},
        }
        with pytest.raises(FakeConflictError):
            k8s_client.update_configmap(tmp_namespace, "conflict-cm", stale_body)

    def test_delete_then_get_raises(self, k8s_client, tmp_namespace):
        body = {
            "apiVersion": "v1",
            "kind": "ConfigMap",
            "metadata": {"name": "del-cm"},
            "data": {"k": "v"},
        }
        k8s_client.create_configmap(tmp_namespace, body)
        k8s_client.delete_configmap(tmp_namespace, "del-cm")
        with pytest.raises(FakeNotFoundError):
            k8s_client.get_configmap(tmp_namespace, "del-cm")

    def test_delete_not_found_raises(self, k8s_client, tmp_namespace):
        with pytest.raises(FakeNotFoundError):
            k8s_client.delete_configmap(tmp_namespace, "never-existed")
