"""Tests for config (list) — SDK + CLI."""

from __future__ import annotations

import json

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.config import ConfigService


class TestConfigListSDK:
    """SDK-level tests for ConfigService.list()."""

    def test_list_empty(self, config_service: ConfigService, app_name: str) -> None:
        result = config_service.list(app_name)
        assert result == {}

    def test_list_configmap_only(self, config_service: ConfigService, app_name: str) -> None:
        config_service.set(app_name, {"A": "1", "B": "2"})
        result = config_service.list(app_name)
        assert result == {"A": "1", "B": "2"}

    def test_list_mixed_configmap_and_secret(
        self, config_service: ConfigService, app_name: str
    ) -> None:
        config_service.set(app_name, {"PUBLIC": "value"})
        config_service.set(app_name, {"PRIVATE": "secret"}, secret=True)
        result = config_service.list(app_name)
        assert result["PUBLIC"] == "value"
        assert result["PRIVATE"] == "secret"

    def test_list_secret_overrides_configmap(
        self, config_service: ConfigService, app_name: str
    ) -> None:
        """If same key in both CM and Secret, Secret wins."""
        config_service.set(app_name, {"KEY": "cm"})
        config_service.set(app_name, {"KEY": "secret"}, secret=True)
        result = config_service.list(app_name)
        assert result["KEY"] == "secret"

    def test_list_app_not_found(self, config_service: ConfigService) -> None:
        with pytest.raises(AppNotFoundError, match="nonexistent"):
            config_service.list("nonexistent")

    def test_list_sources(self, config_service: ConfigService, app_name: str) -> None:
        """list_with_sources returns (value, source) tuples."""
        config_service.set(app_name, {"PUBLIC": "val"})
        config_service.set(app_name, {"PRIVATE": "sec"}, secret=True)
        result = config_service.list_with_sources(app_name)
        assert result["PUBLIC"] == ("val", "configmap")
        assert result["PRIVATE"] == ("sec", "secret")


class TestConfigListCLI:
    """CLI-level tests for config (list)."""

    def test_list_cli_empty(self, cli_runner: CliRunner, factory: KuberokuFactory) -> None:
        factory.apps.create("myapp")
        result = cli_runner.invoke(cli, ["config", "--app", "myapp"], obj={"factory": factory})
        assert result.exit_code == 0

    def test_list_cli_with_vars(self, cli_runner: CliRunner, factory: KuberokuFactory) -> None:
        factory.apps.create("myapp")
        factory.config.set("myapp", {"FOO": "bar", "BAZ": "qux"})
        result = cli_runner.invoke(cli, ["config", "--app", "myapp"], obj={"factory": factory})
        assert result.exit_code == 0
        assert "FOO" in result.output
        assert "BAZ" in result.output

    def test_list_cli_secret_masked(self, cli_runner: CliRunner, factory: KuberokuFactory) -> None:
        factory.apps.create("myapp")
        factory.config.set("myapp", {"TOKEN": "supersecret"}, secret=True)
        result = cli_runner.invoke(cli, ["config", "--app", "myapp"], obj={"factory": factory})
        assert result.exit_code == 0
        assert "supersecret" not in result.output
        assert "********" in result.output

    def test_list_cli_reveal(self, cli_runner: CliRunner, factory: KuberokuFactory) -> None:
        factory.apps.create("myapp")
        factory.config.set("myapp", {"TOKEN": "supersecret"}, secret=True)
        result = cli_runner.invoke(
            cli, ["config", "--reveal", "--app", "myapp"], obj={"factory": factory}
        )
        assert result.exit_code == 0
        assert "supersecret" in result.output

    def test_list_cli_reveal_warning(
        self, cli_runner: CliRunner, factory: KuberokuFactory
    ) -> None:
        """--reveal prints a warning to stderr when secrets exist."""
        factory.apps.create("myapp")
        factory.config.set("myapp", {"TOKEN": "supersecret"}, secret=True)
        result = cli_runner.invoke(
            cli, ["config", "--reveal", "--app", "myapp"], obj={"factory": factory}
        )
        assert result.exit_code == 0
        # Warning goes to stderr, which CliRunner captures in output by default
        assert "WARNING" in result.output or "Revealing" in result.output

    def test_list_cli_shell_format(self, cli_runner: CliRunner, factory: KuberokuFactory) -> None:
        factory.apps.create("myapp")
        factory.config.set("myapp", {"FOO": "bar", "BAZ": "qux"})
        result = cli_runner.invoke(
            cli, ["config", "--shell", "--app", "myapp"], obj={"factory": factory}
        )
        assert result.exit_code == 0
        assert "FOO=bar" in result.output
        assert "BAZ=qux" in result.output

    def test_list_cli_json_format(self, cli_runner: CliRunner, factory: KuberokuFactory) -> None:
        factory.apps.create("myapp")
        factory.config.set("myapp", {"FOO": "bar"})
        result = cli_runner.invoke(
            cli, ["config", "--json", "--app", "myapp"], obj={"factory": factory}
        )
        assert result.exit_code == 0
        data = json.loads(result.output)
        assert data["FOO"] == "bar"

    def test_list_cli_reveal_no_secrets(
        self, cli_runner: CliRunner, factory: KuberokuFactory
    ) -> None:
        """--reveal does NOT show warning when there are no secrets."""
        factory.apps.create("myapp")
        factory.config.set("myapp", {"PUBLIC": "value"})
        result = cli_runner.invoke(
            cli, ["config", "--reveal", "--app", "myapp"], obj={"factory": factory}
        )
        assert result.exit_code == 0
        assert "WARNING" not in result.output

    def test_list_cli_shell_secret_masked(
        self, cli_runner: CliRunner, factory: KuberokuFactory
    ) -> None:
        """--shell masks secret values by default."""
        factory.apps.create("myapp")
        factory.config.set("myapp", {"TOKEN": "supersecret"}, secret=True)
        result = cli_runner.invoke(
            cli, ["config", "--shell", "--app", "myapp"], obj={"factory": factory}
        )
        assert result.exit_code == 0
        assert "TOKEN=********" in result.output
        assert "supersecret" not in result.output

    def test_list_cli_shell_reveal(self, cli_runner: CliRunner, factory: KuberokuFactory) -> None:
        """--shell --reveal shows actual secret values."""
        factory.apps.create("myapp")
        factory.config.set("myapp", {"TOKEN": "supersecret"}, secret=True)
        result = cli_runner.invoke(
            cli,
            ["config", "--shell", "--reveal", "--app", "myapp"],
            obj={"factory": factory},
        )
        assert result.exit_code == 0
        assert "TOKEN=supersecret" in result.output

    def test_list_cli_json_secret_masked(
        self, cli_runner: CliRunner, factory: KuberokuFactory
    ) -> None:
        """--json masks secret values by default."""
        factory.apps.create("myapp")
        factory.config.set("myapp", {"TOKEN": "supersecret"}, secret=True)
        result = cli_runner.invoke(
            cli, ["config", "--json", "--app", "myapp"], obj={"factory": factory}
        )
        assert result.exit_code == 0
        data = json.loads(result.output)
        assert data["TOKEN"] == "********"

    def test_list_cli_json_reveal(self, cli_runner: CliRunner, factory: KuberokuFactory) -> None:
        """--json --reveal shows actual secret values."""
        factory.apps.create("myapp")
        factory.config.set("myapp", {"TOKEN": "supersecret"}, secret=True)
        result = cli_runner.invoke(
            cli,
            ["config", "--json", "--reveal", "--app", "myapp"],
            obj={"factory": factory},
        )
        assert result.exit_code == 0
        # WARNING goes to stderr which CliRunner mixes into output; strip it
        json_start = result.output.index("{")
        data = json.loads(result.output[json_start:])
        assert data["TOKEN"] == "supersecret"

    def test_list_cli_app_not_found(self, cli_runner: CliRunner, factory: KuberokuFactory) -> None:
        result = cli_runner.invoke(
            cli, ["config", "--app", "nonexistent"], obj={"factory": factory}
        )
        assert result.exit_code != 0
