"""Tests for services:maintenance:on/off — SDK + CLI."""

from __future__ import annotations

import pytest
from click.testing import CliRunner

from kuberoku.cli.main import cli
from kuberoku.exceptions import ProcessTypeNotFoundError
from kuberoku.factory import KuberokuFactory
from kuberoku.k8s import resources


class TestServicesMaintenanceSDK:
    """SDK-level tests for ServicesService.maintenance_on/off()."""

    def test_on_single_process(self, factory: KuberokuFactory) -> None:
        factory.apps.create("myapp")
        factory.deploy.deploy("myapp", image="nginx:1.27", wait=False)
        factory.services.maintenance_on("myapp", "web")
        dep_name = resources.safe_name(factory.prefix, "myapp", "web")
        dep = factory.k8s.get_deployment(factory.namespace, dep_name)
        assert dep["spec"]["replicas"] == 0

    def test_off_single_process(self, factory: KuberokuFactory) -> None:
        factory.apps.create("myapp")
        factory.deploy.deploy("myapp", image="nginx:1.27", wait=False)
        # Scale to 3 via SDK (handles 409 retries on real K8s)
        factory.ps.scale("myapp", {"web": 3})
        factory.services.maintenance_on("myapp", "web")
        factory.services.maintenance_off("myapp", "web")
        dep_name = resources.safe_name(factory.prefix, "myapp", "web")
        dep = factory.k8s.get_deployment(factory.namespace, dep_name)
        assert dep["spec"]["replicas"] == 3

    def test_preserves_other_processes(self, factory: KuberokuFactory) -> None:
        factory.apps.create("myapp")
        factory.deploy.deploy("myapp", image="nginx:1.27", wait=False)
        factory.deploy.deploy(
            "myapp",
            image="worker:v1",
            process_type="worker",
            ports=None,
            wait=False,
        )
        factory.services.maintenance_on("myapp", "web")
        # Worker should still be at original replicas
        worker_dep_name = resources.safe_name(factory.prefix, "myapp", "worker")
        worker_dep = factory.k8s.get_deployment(factory.namespace, worker_dep_name)
        assert worker_dep["spec"]["replicas"] == 1

    def test_multiple_services_independently(self, factory: KuberokuFactory) -> None:
        factory.apps.create("myapp")
        factory.deploy.deploy("myapp", image="nginx:1.27", wait=False)
        factory.deploy.deploy(
            "myapp",
            image="worker:v1",
            process_type="worker",
            ports=None,
            wait=False,
        )
        factory.services.maintenance_on("myapp", "web")
        factory.services.maintenance_on("myapp", "worker")
        # Both should be at 0
        for ptype in ["web", "worker"]:
            dep_name = resources.safe_name(factory.prefix, "myapp", ptype)
            dep = factory.k8s.get_deployment(factory.namespace, dep_name)
            assert dep["spec"]["replicas"] == 0
        # Restore web only
        factory.services.maintenance_off("myapp", "web")
        web_dep = factory.k8s.get_deployment(
            factory.namespace, resources.safe_name(factory.prefix, "myapp", "web")
        )
        assert web_dep["spec"]["replicas"] == 1
        # Worker still at 0
        worker_dep = factory.k8s.get_deployment(
            factory.namespace, resources.safe_name(factory.prefix, "myapp", "worker")
        )
        assert worker_dep["spec"]["replicas"] == 0

    def test_clears_flag_when_last_service_restored(self, factory: KuberokuFactory) -> None:
        factory.apps.create("myapp")
        factory.deploy.deploy("myapp", image="nginx:1.27", wait=False)
        factory.services.maintenance_on("myapp", "web")
        maint = factory.apps.maintenance_status("myapp")
        assert maint.enabled is True
        factory.services.maintenance_off("myapp", "web")
        maint = factory.apps.maintenance_status("myapp")
        assert maint.enabled is False

    def test_process_not_found(self, factory: KuberokuFactory) -> None:
        factory.apps.create("myapp")
        with pytest.raises(ProcessTypeNotFoundError):
            factory.services.maintenance_on("myapp", "nope")

    def test_on_step_callbacks(self, factory: KuberokuFactory) -> None:
        factory.apps.create("myapp")
        factory.deploy.deploy("myapp", image="nginx:1.27", wait=False)
        steps: list[str] = []
        factory.services.maintenance_on("myapp", "web", on_step=steps.append)
        assert len(steps) >= 2

    def test_per_service_maintenance_info(self, factory: KuberokuFactory) -> None:
        factory.apps.create("myapp")
        factory.deploy.deploy("myapp", image="nginx:1.27", wait=False)
        factory.services.maintenance_on("myapp", "web")
        maint = factory.apps.maintenance_status("myapp")
        assert maint.enabled is True
        assert maint.app_wide is False
        assert "web" in maint.services


class TestServicesMaintenanceCLI:
    """CLI-level tests for services:maintenance commands."""

    def test_maintenance_on_cli(self, cli_runner: CliRunner, factory: KuberokuFactory) -> None:
        factory.apps.create("myapp")
        factory.deploy.deploy("myapp", image="nginx:1.27", wait=False)
        result = cli_runner.invoke(
            cli,
            ["services", "maintenance", "on", "web", "-a", "myapp"],
            obj={"factory": factory},
        )
        assert result.exit_code == 0
        assert "enabled" in result.output.lower()

    def test_maintenance_off_cli(self, cli_runner: CliRunner, factory: KuberokuFactory) -> None:
        factory.apps.create("myapp")
        factory.deploy.deploy("myapp", image="nginx:1.27", wait=False)
        factory.services.maintenance_on("myapp", "web")
        result = cli_runner.invoke(
            cli,
            ["services", "maintenance", "off", "web", "-a", "myapp"],
            obj={"factory": factory},
        )
        assert result.exit_code == 0
        assert "disabled" in result.output.lower()

    def test_colon_syntax(self, cli_runner: CliRunner, factory: KuberokuFactory) -> None:
        factory.apps.create("myapp")
        factory.deploy.deploy("myapp", image="nginx:1.27", wait=False)
        result = cli_runner.invoke(
            cli,
            ["services:maintenance:on", "web", "-a", "myapp"],
            obj={"factory": factory},
        )
        assert result.exit_code == 0
        assert "enabled" in result.output.lower()
