"""Tests for ReleasesService.create_release."""

from __future__ import annotations

import pytest

from kuberoku.factory import KuberokuFactory
from kuberoku.k8s.resources import safe_name
from kuberoku.models import ProcessFormation


def test_create_first_release(app_factory: KuberokuFactory) -> None:
    formation = {"web": ProcessFormation(1, None, "default")}
    release = app_factory.releases.create_release(
        "myapp",
        images={"web": "myapp:v1"},
        formation=formation,
        description="Deploy myapp:v1",
    )
    assert release.version == 1
    assert release.app == "myapp"
    assert release.description == "Deploy myapp:v1"
    assert release.images == {"web": "myapp:v1"}


def test_create_increments_version(app_factory: KuberokuFactory) -> None:
    formation = {"web": ProcessFormation(1, None, "default")}
    r1 = app_factory.releases.create_release(
        "myapp", images={"web": "v1"}, formation=formation, description="v1"
    )
    r2 = app_factory.releases.create_release(
        "myapp", images={"web": "v2"}, formation=formation, description="v2"
    )
    assert r1.version == 1
    assert r2.version == 2


def test_release_stores_configmap(app_factory: KuberokuFactory) -> None:
    formation = {"web": ProcessFormation(1, None, "default")}
    app_factory.releases.create_release(
        "myapp",
        images={"web": "v1"},
        formation=formation,
        description="test",
    )
    # Verify ConfigMap exists
    cm_name = safe_name(app_factory.prefix, "release", "myapp-v1")
    cm = app_factory.k8s.get_configmap(app_factory.namespace, cm_name)
    assert cm["data"]["version"] == "1"


def test_release_records_images(app_factory: KuberokuFactory) -> None:
    formation = {
        "web": ProcessFormation(1, None, "default"),
        "worker": ProcessFormation(2, None, "default"),
    }
    release = app_factory.releases.create_release(
        "myapp",
        images={"web": "myapp:v1", "worker": "myworker:v1"},
        formation=formation,
        description="test",
    )
    assert release.images == {"web": "myapp:v1", "worker": "myworker:v1"}


def test_release_records_formation(app_factory: KuberokuFactory) -> None:
    formation = {"web": ProcessFormation(3, "python app.py", "manual")}
    release = app_factory.releases.create_release(
        "myapp", images={"web": "v1"}, formation=formation, description="test"
    )
    assert release.formation["web"].replicas == 3
    assert release.formation["web"].command == "python app.py"
    assert release.formation["web"].command_source == "manual"


def test_release_records_env_diff(app_factory: KuberokuFactory) -> None:
    formation = {"web": ProcessFormation(1, None, "default")}
    release = app_factory.releases.create_release(
        "myapp",
        images={"web": "v1"},
        formation=formation,
        description="Set KEY",
        env_diff={"KEY": "val"},
    )
    assert release.env_diff == {"KEY": "val"}


def test_release_records_commit_and_ref(app_factory: KuberokuFactory) -> None:
    formation = {"web": ProcessFormation(1, None, "default")}
    release = app_factory.releases.create_release(
        "myapp",
        images={"web": "v1"},
        formation=formation,
        description="test",
        commit="abc1234",
        ref="main",
    )
    assert release.commit == "abc1234"
    assert release.ref == "main"


def test_release_has_created_by(app_factory: KuberokuFactory) -> None:
    formation = {"web": ProcessFormation(1, None, "default")}
    release = app_factory.releases.create_release(
        "myapp", images={"web": "v1"}, formation=formation, description="test"
    )
    assert release.created_by != ""
    assert "@" in release.created_by


def test_release_frozen_dataclass(app_factory: KuberokuFactory) -> None:
    formation = {"web": ProcessFormation(1, None, "default")}
    release = app_factory.releases.create_release(
        "myapp", images={"web": "v1"}, formation=formation, description="test"
    )
    with pytest.raises(AttributeError):
        release.version = 99  # type: ignore[misc]


def test_release_retry_on_conflict(app_factory: KuberokuFactory) -> None:
    """Version counter update retries on 409."""
    manifest_name = safe_name(app_factory.prefix, "app", "myapp")
    # Inject 1 conflict on the manifest update
    assert isinstance(app_factory.k8s, object)
    app_factory.k8s.inject_conflict(  # type: ignore[attr-defined]
        "ConfigMap",
        app_factory.namespace,
        manifest_name,
        count=1,
    )
    formation = {"web": ProcessFormation(1, None, "default")}
    release = app_factory.releases.create_release(
        "myapp", images={"web": "v1"}, formation=formation, description="test"
    )
    assert release.version == 1


def test_release_on_step_callback(app_factory: KuberokuFactory) -> None:
    steps: list[str] = []
    formation = {"web": ProcessFormation(1, None, "default")}
    app_factory.releases.create_release(
        "myapp",
        images={"web": "v1"},
        formation=formation,
        description="test",
        on_step=steps.append,
    )
    assert any("v1" in s for s in steps)


def test_release_app_not_found(app_factory: KuberokuFactory) -> None:
    formation = {"web": ProcessFormation(1, None, "default")}
    with pytest.raises(Exception, match="not found"):
        app_factory.releases.create_release(
            "nonexistent",
            images={"web": "v1"},
            formation=formation,
            description="test",
        )
