"""Tests for apps:info — SDK + CLI."""

from __future__ import annotations

from unittest.mock import patch

import pytest
from click.testing import CliRunner

from kuberoku.cli.main import cli
from kuberoku.exceptions import AppNotFoundError
from kuberoku.factory import KuberokuFactory
from kuberoku.sdk.apps import AppsService, _get_identity


class TestAppsInfoSDK:
    """SDK-level tests for AppsService.info()."""

    def test_info_happy_path(self, apps_service: AppsService) -> None:
        apps_service.create("myapi")
        app = apps_service.info("myapi")
        assert app.name == "myapi"
        assert app.release_version == 0
        assert app.created_by != ""

    def test_info_not_found(self, apps_service: AppsService) -> None:
        with pytest.raises(AppNotFoundError, match="myapi"):
            apps_service.info("myapi")

    def test_info_preserves_created_at(self, apps_service: AppsService) -> None:
        apps_service.create("myapi")
        app = apps_service.info("myapi")
        assert app.created_at is not None

    def test_info_with_formation_data(
        self, apps_service: AppsService, factory: KuberokuFactory
    ) -> None:
        """info() parses formation JSON data into ProcessFormation."""
        apps_service.create("myapi")
        factory.deploy.deploy("myapi", image="nginx:1.27", wait=False)
        # Use SDK methods (handles 409 retries on real K8s)
        factory.ps.scale("myapi", {"web": 3})
        factory.ps.set_commands("myapi", {"web": "gunicorn app:app"}, no_restart=True)
        app = apps_service.info("myapi")
        assert "web" in app.process_types
        assert app.process_types["web"].replicas == 3
        assert app.process_types["web"].command == "gunicorn app:app"

    def test_info_formation_invalid_json_skipped(
        self, apps_service: AppsService, factory: KuberokuFactory
    ) -> None:
        """Invalid JSON in formation is silently skipped."""
        apps_service.create("myapi")
        k8s = factory.k8s
        ns = factory.namespace
        p = factory.prefix
        cm = k8s.get_configmap(ns, f"{p}-formation-myapi")
        cm["data"] = {"web": "not-valid-json"}
        k8s.update_configmap(ns, f"{p}-formation-myapi", cm)
        app = apps_service.info("myapi")
        assert app.process_types == {}

    def test_info_bad_created_at_falls_back(
        self, apps_service: AppsService, factory: KuberokuFactory
    ) -> None:
        """Invalid created-at annotation falls back to now()."""
        apps_service.create("myapi")
        k8s = factory.k8s
        ns = factory.namespace
        p = factory.prefix
        cm = k8s.get_configmap(ns, f"{p}-app-myapi")
        cm["metadata"]["annotations"][f"{factory.domain}/created-at"] = "not-a-date"
        k8s.update_configmap(ns, f"{p}-app-myapi", cm)
        app = apps_service.info("myapi")
        assert app.created_at is not None


class TestGetIdentity:
    """Tests for the _get_identity helper."""

    def test_identity_returns_user_at_host(self) -> None:
        result = _get_identity()
        assert "@" in result

    def test_identity_fallback_on_error(self) -> None:
        with patch("kuberoku.sdk.apps.getpass.getuser", side_effect=Exception("no user")):
            assert _get_identity() == "unknown"


class TestAppsInfoCLI:
    """CLI-level tests for apps:info."""

    def test_info_cli_by_argument(self, cli_runner: CliRunner, factory: KuberokuFactory) -> None:
        cli_runner.invoke(cli, ["apps:create", "myapi"], obj={"factory": factory})
        result = cli_runner.invoke(cli, ["apps:info", "myapi"], obj={"factory": factory})
        assert result.exit_code == 0
        assert "myapi" in result.output

    def test_info_cli_not_found(self, cli_runner: CliRunner, factory: KuberokuFactory) -> None:
        result = cli_runner.invoke(cli, ["apps:info", "nope"], obj={"factory": factory})
        assert result.exit_code != 0

    def test_info_cli_help(self, cli_runner: CliRunner) -> None:
        result = cli_runner.invoke(cli, ["apps:info", "--help"])
        assert result.exit_code == 0
        assert "Show detailed app info" in result.output
