from __future__ import annotations

import json
from pathlib import Path
from types import SimpleNamespace

import yaml
from typer.testing import CliRunner

import omni.cli.main as cli_main
from omni.cli.main import app

runner = CliRunner()


def test_cli_config_info(tmp_path):
    cfg = {
        "default_instance": "default",
        "instances": {"default": {"url": "https://omni.example"}},
    }
    path = tmp_path / "config.yml"
    path.write_text(yaml.safe_dump(cfg), encoding="utf-8")

    result = runner.invoke(app, ["--config", str(path), "config", "info"])
    assert result.exit_code == 0
    assert "default_instance" in result.output
    assert "https://omni.example" in result.output


def test_cli_config_info_redacts_service_account_key(tmp_path):
    cfg = {
        "default_instance": "default",
        "instances": {
            "default": {
                "url": "https://omni.example",
                "auth": {
                    "service_account_key": "super-secret-key-value",
                    "service_account_env_aliases": ["OMNI_SERVICE_ACCOUNT_KEY"],
                },
            }
        },
    }
    path = tmp_path / "config.yml"
    path.write_text(yaml.safe_dump(cfg), encoding="utf-8")

    result = runner.invoke(app, ["--config", str(path), "config", "info"])
    assert result.exit_code == 0
    assert "service_account_key" in result.output
    assert "<redacted>" in result.output
    assert "super-secret-key-value" not in result.output


class _StubManagement:
    def __init__(self) -> None:
        self.create_join_token_requests: list[dict] = []
        self.read_audit_log_requests: list[dict] = []
        self.get_support_bundle_requests: list[dict] = []
        self.kubeconfig_requests: list[tuple[dict, dict | None]] = []
        self.talosconfig_requests: list[tuple[dict, dict | None]] = []
        self.omniconfig_requests: list[tuple[dict, dict | None]] = []
        self.upgrade_pre_checks_requests: list[tuple[dict, dict | None]] = []
        self.manifest_sync_requests: list[tuple[dict, dict | None]] = []

    def create_join_token(self, request: dict) -> dict:
        self.create_join_token_requests.append(request)
        return {"id": "jt-123"}

    def read_audit_log(self, request: dict) -> list[dict]:
        self.read_audit_log_requests.append(request)
        return [{"audit_log": "aGVsbG8K"}]

    def get_support_bundle(self, request: dict) -> list[dict]:
        self.get_support_bundle_requests.append(request)
        return [
            {"progress": {"source": "node-a", "state": "collecting", "total": 10, "value": 4}},
            {"bundle_data": "emlwLWRhdGE="},
        ]

    def kubeconfig(self, request: dict, metadata: dict | None = None) -> dict:
        self.kubeconfig_requests.append((request, metadata))
        return {"kubeconfig": "YXBpVmVyc2lvbjogdjE="}

    def talosconfig(self, request: dict, metadata: dict | None = None) -> dict:
        self.talosconfig_requests.append((request, metadata))
        return {"talosconfig": "Y29udGV4dHM6IFtd"}

    def omniconfig(self, request: dict, metadata: dict | None = None) -> dict:
        self.omniconfig_requests.append((request, metadata))
        return {"omniconfig": "Y29udGV4dDoKICBkZWZhdWx0OiB7fQ=="}

    def kubernetes_upgrade_pre_checks(self, request: dict, metadata: dict | None = None) -> dict:
        self.upgrade_pre_checks_requests.append((request, metadata))
        return {"ok": True, "reason": ""}

    def kubernetes_sync_manifests(self, request: dict, metadata: dict | None = None) -> list[dict]:
        self.manifest_sync_requests.append((request, metadata))
        return [
            {"response_type": 1, "path": "manifests/coredns.yaml", "diff": "-old\n+new", "skipped": False},
            {"response_type": 2, "path": "deployment/coredns"},
        ]


class _StubResources:
    def __init__(self) -> None:
        self.get_requests: list[dict] = []
        self.list_requests: list[dict] = []
        self.create_requests: list[dict] = []
        self.update_requests: list[dict] = []
        self.teardown_requests: list[dict] = []

    def get(self, request: dict) -> dict:
        self.get_requests.append(request)
        if request["type"] == "Identities.omni.sidero.dev":
            raise cli_main.OmniHTTPError("not found", status_code=404)
        if request["type"] == "FeaturesConfigs.omni.sidero.dev":
            body = {"metadata": {"id": "features-config"}, "spec": {"imageFactoryBaseUrl": "https://omni.example"}}
            return {"body": json.dumps(body)}
        if request["type"] == "Clusters.omni.sidero.dev":
            body = {
                "metadata": {
                    "namespace": request.get("namespace", "default"),
                    "type": "Clusters.omni.sidero.dev",
                    "id": request.get("id", "cluster-a"),
                    "version": "11",
                    "annotations": {
                        "omni.sidero.dev/cluster-locked": "",
                        "omni.sidero.dev/cluster-import-is-in-progress": "",
                        "note": "keep",
                    },
                },
                "spec": {},
            }
            return {"body": json.dumps(body)}
        if request["type"] == "MachineSetNodes.omni.sidero.dev":
            body = {
                "metadata": {
                    "namespace": request.get("namespace", "default"),
                    "type": "MachineSetNodes.omni.sidero.dev",
                    "id": request.get("id", "machine-a"),
                    "version": "7",
                    "annotations": {
                        "omni.sidero.dev/locked": "",
                    },
                },
                "spec": {},
            }
            return {"body": json.dumps(body)}
        return {"body": '{"metadata":{"id":"ok"},"spec":{}}'}

    def list(self, request: dict) -> dict:
        self.list_requests.append(request)
        if request["type"] == "InfraProviderCombinedStatuses.omni.sidero.dev":
            item = {
                "metadata": {"id": "ip-1"},
                "spec": {
                    "name": "provider-one",
                    "description": "dev provider",
                    "health": {"connected": True, "error": ""},
                },
            }
            return {"items": [json.dumps(item)]}
        if request["type"] == "InstallationMedias.omni.sidero.dev":
            item = {
                "metadata": {"id": "metal-amd64"},
                "spec": {
                    "name": "Installer ISO",
                    "profile": "iso",
                    "architecture": "amd64",
                    "overlay": "",
                    "extension": "iso",
                    "destFilePrefix": "talos-metal",
                },
            }
            return {"items": [json.dumps(item)]}
        return {"items": []}

    def create(self, request: dict) -> dict:
        self.create_requests.append(request)
        return {}

    def update(self, request: dict) -> dict:
        self.update_requests.append(request)
        return {}

    def teardown(self, request: dict) -> dict:
        self.teardown_requests.append(request)
        return {}


class _StubClient:
    def __init__(self) -> None:
        self.management = _StubManagement()
        self.resources = _StubResources()


def test_jointoken_create_invokes_management(monkeypatch):
    client = _StubClient()
    monkeypatch.setattr(cli_main, "get_sync_client", lambda **_: client)

    result = runner.invoke(app, ["jointoken", "create", "worker-bootstrap", "--ttl", "300"])
    assert result.exit_code == 0
    assert "jt-123" in result.output

    assert len(client.management.create_join_token_requests) == 1
    req = client.management.create_join_token_requests[0]
    assert req["name"] == "worker-bootstrap"
    assert "expiration_time" in req


def test_audit_log_prints_stream_output(monkeypatch):
    client = _StubClient()
    monkeypatch.setattr(cli_main, "get_sync_client", lambda **_: client)

    result = runner.invoke(app, ["audit-log", "2025-01-01", "2025-01-02"])
    assert result.exit_code == 0
    assert "hello" in result.output
    assert client.management.read_audit_log_requests == [
        {"start_time": "2025-01-01", "end_time": "2025-01-02"}
    ]


def test_user_create_creates_user_and_identity(monkeypatch):
    client = _StubClient()
    monkeypatch.setattr(cli_main, "get_sync_client", lambda **_: client)

    result = runner.invoke(app, ["user", "create", "dev@example.com", "--role", "Operator"])
    assert result.exit_code == 0
    assert len(client.resources.create_requests) == 2
    assert client.resources.create_requests[0]["resource"]["metadata"]["type"] == "Users.omni.sidero.dev"
    assert client.resources.create_requests[1]["resource"]["metadata"]["type"] == "Identities.omni.sidero.dev"


def test_infraprovider_list_outputs_table(monkeypatch):
    client = _StubClient()
    monkeypatch.setattr(cli_main, "get_sync_client", lambda **_: client)

    result = runner.invoke(app, ["infraprovider", "list"])
    assert result.exit_code == 0
    assert "provider-one" in result.output


def test_support_bundle_writes_output(tmp_path, monkeypatch):
    client = _StubClient()
    monkeypatch.setattr(cli_main, "get_sync_client", lambda **_: client)

    output = tmp_path / "support.zip"
    result = runner.invoke(app, ["support", "--cluster", "cluster-a", "--output", str(output)])
    assert result.exit_code == 0
    assert output.read_bytes() == b"zip-data"
    assert client.management.get_support_bundle_requests == [{"cluster": "cluster-a"}]


def test_download_dry_run_outputs_request(monkeypatch):
    client = _StubClient()
    monkeypatch.setattr(cli_main, "get_sync_client", lambda **_: client)

    result = runner.invoke(app, ["download", "iso", "--dry-run", "--talos-version", "v1.9.0"])
    assert result.exit_code == 0
    assert "create_schematic_request" in result.output


def test_cluster_alias_c_routes_to_cluster_commands(monkeypatch):
    client = _StubClient()
    monkeypatch.setattr(cli_main, "get_sync_client", lambda **_: client)

    result = runner.invoke(app, ["c", "status", "cluster-a"])
    assert result.exit_code == 0
    assert client.resources.get_requests[-1]["type"] == "ClusterStatuses.omni.sidero.dev"


def test_kubeconfig_cluster_and_service_account_options(monkeypatch):
    client = _StubClient()
    monkeypatch.setattr(cli_main, "get_sync_client", lambda **_: client)

    result = runner.invoke(
        app,
        [
            "kubeconfig",
            "--cluster",
            "cluster-a",
            "--service-account",
            "--user",
            "robot@cluster-a",
            "--groups",
            "system:masters",
            "--ttl",
            "600",
        ],
    )
    assert result.exit_code == 0
    assert "apiVersion: v1" in result.output
    req, md = client.management.kubeconfig_requests[0]
    assert req["service_account"] is True
    assert req["service_account_user"] == "robot@cluster-a"
    assert req["service_account_ttl"] == "600s"
    assert md == {"cluster": "cluster-a"}


def test_omniconfig_outputs_decoded_config(monkeypatch):
    client = _StubClient()
    monkeypatch.setattr(cli_main, "get_sync_client", lambda **_: client)

    result = runner.invoke(app, ["omniconfig"])
    assert result.exit_code == 0
    assert "context:" in result.output


def test_cluster_kubernetes_upgrade_pre_checks(monkeypatch):
    client = _StubClient()
    monkeypatch.setattr(cli_main, "get_sync_client", lambda **_: client)

    result = runner.invoke(
        app,
        ["cluster", "kubernetes", "upgrade-pre-checks", "cluster-a", "--to", "1.33.0"],
    )
    assert result.exit_code == 0
    req, md = client.management.upgrade_pre_checks_requests[0]
    assert req == {"new_version": "1.33.0"}
    assert md == {"cluster": "cluster-a"}


def test_cluster_kubernetes_manifest_sync(monkeypatch):
    client = _StubClient()
    monkeypatch.setattr(cli_main, "get_sync_client", lambda **_: client)

    result = runner.invoke(
        app,
        ["cluster", "kubernetes", "manifest-sync", "cluster-a", "--no-dry-run"],
    )
    assert result.exit_code == 0
    assert "processing manifest manifests/coredns.yaml" in result.output
    assert "applied successfully" in result.output
    req, md = client.management.manifest_sync_requests[0]
    assert req == {"dry_run": False}
    assert md == {"cluster": "cluster-a"}


def test_cluster_lock_sets_cluster_annotation(monkeypatch):
    client = _StubClient()
    monkeypatch.setattr(cli_main, "get_sync_client", lambda **_: client)

    result = runner.invoke(app, ["cluster", "lock", "cluster-a"])
    assert result.exit_code == 0
    assert len(client.resources.update_requests) == 1
    metadata = client.resources.update_requests[0]["resource"]["metadata"]
    assert metadata["type"] == "Clusters.omni.sidero.dev"
    assert metadata["id"] == "cluster-a"
    assert metadata["annotations"]["omni.sidero.dev/cluster-locked"] == ""
    assert metadata["annotations"]["note"] == "keep"


def test_cluster_unlock_removes_lock_annotations(monkeypatch):
    client = _StubClient()
    monkeypatch.setattr(cli_main, "get_sync_client", lambda **_: client)

    result = runner.invoke(app, ["cluster", "unlock", "cluster-a"])
    assert result.exit_code == 0
    metadata = client.resources.update_requests[0]["resource"]["metadata"]
    assert "omni.sidero.dev/cluster-locked" not in metadata["annotations"]
    assert "omni.sidero.dev/cluster-import-is-in-progress" not in metadata["annotations"]
    assert metadata["annotations"]["note"] == "keep"


def test_cluster_machine_lock_targets_machine_set_nodes(monkeypatch):
    client = _StubClient()
    monkeypatch.setattr(cli_main, "get_sync_client", lambda **_: client)

    result = runner.invoke(app, ["cluster", "machine", "lock", "machine-a"])
    assert result.exit_code == 0
    metadata = client.resources.update_requests[0]["resource"]["metadata"]
    assert metadata["type"] == "MachineSetNodes.omni.sidero.dev"
    assert metadata["id"] == "machine-a"
    assert metadata["annotations"]["omni.sidero.dev/locked"] == ""


def test_talos_proxy_injects_managed_flags(monkeypatch):
    class _Manager:
        def __init__(self) -> None:
            self.ensure_calls: list[dict] = []

        async def ensure(self, **kwargs):
            self.ensure_calls.append(kwargs)
            return SimpleNamespace(
                path=Path("/tmp/managed-talosconfig.yaml"),
                context="omni/default/cluster-a",
                cluster="cluster-a",
                refreshed=True,
            )

        def remember_cluster(self, cluster: str) -> None:
            self.cluster = cluster

        def set_last_targets(
            self,
            *,
            cluster: str | None,
            nodes: str | None = None,
            endpoints: str | None = None,
        ) -> None:
            self.last_targets = (cluster, nodes, endpoints)

        def get_last_targets(self, *, cluster: str | None) -> tuple[str | None, str | None]:
            return ("10.0.0.1", "https://omni.example")

        def service_account_key_b64(self) -> str | None:
            return "base64-service-account"

    manager = _Manager()
    monkeypatch.setattr(cli_main, "_talos_manager", lambda _ctx: manager)
    monkeypatch.setattr(cli_main.shutil, "which", lambda _: "/usr/bin/talosctl")
    captured: dict[str, list[str]] = {}

    def _run(cmd, check=False, env=None):
        captured["cmd"] = cmd
        captured["env"] = env
        return SimpleNamespace(returncode=0)

    monkeypatch.setattr(cli_main.subprocess, "run", _run)

    result = runner.invoke(app, ["talos", "--cluster", "cluster-a", "get", "members"])
    assert result.exit_code == 0

    assert manager.ensure_calls[0]["cluster"] == "cluster-a"
    cmd = captured["cmd"]
    assert cmd[0] == "/usr/bin/talosctl"
    assert "--talosconfig" in cmd
    assert "--context" in cmd
    assert "--nodes" in cmd
    assert "--endpoints" in cmd
    assert cmd[-2:] == ["get", "members"]
    assert captured["env"]["OMNI_SERVICE_ACCOUNT_KEY"] == "base64-service-account"


def test_talos_proxy_respects_user_context_and_talosconfig(monkeypatch):
    class _Manager:
        def __init__(self) -> None:
            self.service_account_calls = 0

        async def ensure(self, **kwargs):
            return SimpleNamespace(
                path=Path("/tmp/managed-talosconfig.yaml"),
                context="omni/default/cluster-a",
                cluster="cluster-a",
                refreshed=True,
            )

        def remember_cluster(self, cluster: str) -> None:
            pass

        def set_last_targets(
            self,
            *,
            cluster: str | None,
            nodes: str | None = None,
            endpoints: str | None = None,
        ) -> None:
            pass

        def get_last_targets(self, *, cluster: str | None) -> tuple[str | None, str | None]:
            return (None, None)

        def service_account_key_b64(self) -> str | None:
            self.service_account_calls += 1
            return "base64-service-account"

    manager = _Manager()
    monkeypatch.setattr(cli_main, "_talos_manager", lambda _ctx: manager)
    monkeypatch.setattr(cli_main.shutil, "which", lambda _: "/usr/bin/talosctl")

    captured: dict[str, list[str]] = {}

    def _run(cmd, check=False, env=None):
        captured["cmd"] = cmd
        captured["env"] = env
        return SimpleNamespace(returncode=0)

    monkeypatch.setattr(cli_main.subprocess, "run", _run)

    result = runner.invoke(
        app,
        [
            "t",
            "--cluster",
            "cluster-a",
            "--talosconfig",
            "/tmp/custom.yaml",
            "--context",
            "custom",
            "--siderov1-keys-dir",
            "/tmp/custom-keys",
            "version",
        ],
    )
    assert result.exit_code == 0
    cmd = captured["cmd"]
    assert cmd.count("--talosconfig") == 1
    assert cmd.count("--context") == 1
    assert cmd.count("--siderov1-keys-dir") == 1
    assert manager.service_account_calls == 0
    assert captured["env"] is None
    assert cmd[-1] == "version"


def test_talos_proxy_maps_node_hostname_to_id(monkeypatch):
    node_id = "03ebd680-b6a5-11ed-9210-d2dfd04d4a00"

    class _Manager:
        def __init__(self) -> None:
            self.saved_nodes: str | None = None
            self.saved_endpoints: str | None = None
            self.resolve_calls: list[tuple[str, str | None]] = []

        async def ensure(self, **kwargs):
            return SimpleNamespace(
                path=Path("/tmp/managed-talosconfig.yaml"),
                context="omni/default/cluster-a",
                cluster="cluster-a",
                refreshed=True,
            )

        def remember_cluster(self, cluster: str) -> None:
            pass

        def set_last_targets(
            self,
            *,
            cluster: str | None,
            nodes: str | None = None,
            endpoints: str | None = None,
        ) -> None:
            if nodes:
                self.saved_nodes = nodes
            if endpoints:
                self.saved_endpoints = endpoints

        def get_last_targets(self, *, cluster: str | None) -> tuple[str | None, str | None]:
            return (self.saved_nodes, self.saved_endpoints)

        async def resolve_nodes(self, nodes: str, *, cluster: str | None = None) -> str:
            self.resolve_calls.append((nodes, cluster))
            return node_id

        def service_account_key_b64(self) -> str | None:
            return None

    manager = _Manager()
    monkeypatch.setattr(cli_main, "_talos_manager", lambda _ctx: manager)
    monkeypatch.setattr(cli_main.shutil, "which", lambda _: "/usr/bin/talosctl")

    captured: dict[str, list[str]] = {}

    def _run(cmd, check=False, env=None):
        captured["cmd"] = cmd
        return SimpleNamespace(returncode=0)

    monkeypatch.setattr(cli_main.subprocess, "run", _run)

    result = runner.invoke(
        app,
        ["talos", "--cluster", "cluster-a", "get", "members", "--nodes", "metal-a8c64g-mfum690s-001"],
    )
    assert result.exit_code == 0
    assert manager.resolve_calls == [("metal-a8c64g-mfum690s-001", "cluster-a")]
    cmd = captured["cmd"]
    assert "--nodes" in cmd
    assert node_id in cmd


def test_talos_proxy_nodes_flag_without_value_uses_saved_node(monkeypatch):
    node_id = "03ebd680-b6a5-11ed-9210-d2dfd04d4a00"

    class _Manager:
        def __init__(self) -> None:
            self.saved_nodes = node_id
            self.resolve_calls = 0

        async def ensure(self, **kwargs):
            return SimpleNamespace(
                path=Path("/tmp/managed-talosconfig.yaml"),
                context="omni/default/cluster-a",
                cluster="cluster-a",
                refreshed=True,
            )

        def remember_cluster(self, cluster: str) -> None:
            pass

        def set_last_targets(
            self,
            *,
            cluster: str | None,
            nodes: str | None = None,
            endpoints: str | None = None,
        ) -> None:
            pass

        def get_last_targets(self, *, cluster: str | None) -> tuple[str | None, str | None]:
            return (self.saved_nodes, None)

        async def resolve_nodes(self, nodes: str, *, cluster: str | None = None) -> str:
            self.resolve_calls += 1
            return nodes

        def service_account_key_b64(self) -> str | None:
            return None

    manager = _Manager()
    monkeypatch.setattr(cli_main, "_talos_manager", lambda _ctx: manager)
    monkeypatch.setattr(cli_main.shutil, "which", lambda _: "/usr/bin/talosctl")

    captured: dict[str, list[str]] = {}

    def _run(cmd, check=False, env=None):
        captured["cmd"] = cmd
        return SimpleNamespace(returncode=0)

    monkeypatch.setattr(cli_main.subprocess, "run", _run)

    result = runner.invoke(app, ["talos", "--cluster", "cluster-a", "get", "members", "--nodes"])
    assert result.exit_code == 0
    assert manager.resolve_calls == 0
    cmd = captured["cmd"]
    assert "--nodes" in cmd
    assert node_id in cmd


def test_talos_proxy_nodes_flag_without_value_requires_saved_node(monkeypatch):
    class _Manager:
        async def ensure(self, **kwargs):
            return SimpleNamespace(
                path=Path("/tmp/managed-talosconfig.yaml"),
                context="omni/default/cluster-a",
                cluster="cluster-a",
                refreshed=True,
            )

        def remember_cluster(self, cluster: str) -> None:
            pass

        def set_last_targets(
            self,
            *,
            cluster: str | None,
            nodes: str | None = None,
            endpoints: str | None = None,
        ) -> None:
            pass

        def get_last_targets(self, *, cluster: str | None) -> tuple[str | None, str | None]:
            return (None, None)

        async def resolve_nodes(self, nodes: str, *, cluster: str | None = None) -> str:
            return nodes

        def service_account_key_b64(self) -> str | None:
            return None

    monkeypatch.setattr(cli_main, "_talos_manager", lambda _ctx: _Manager())
    monkeypatch.setattr(cli_main.shutil, "which", lambda _: "/usr/bin/talosctl")
    monkeypatch.setattr(
        cli_main.subprocess,
        "run",
        lambda cmd, check=False, env=None: SimpleNamespace(returncode=0),
    )

    result = runner.invoke(app, ["talos", "--cluster", "cluster-a", "get", "members", "--nodes"])
    assert result.exit_code != 0
    assert (
        "--nodes was provided without a value" in result.output
        or "requires an argument" in result.output
        or "No such option: --nodes" in result.output
    )


def test_config_talos_info_prints_summary(monkeypatch):
    class _Manager:
        def summary(self) -> dict:
            return {
                "instance": "default",
                "default_ttl_seconds": 300,
                "default_cluster": "cluster-a",
                "last_cluster_for_instance": "cluster-a",
                "effective_cluster": "cluster-a",
                "talosconfig_path_for_instance": "/tmp/managed-talosconfig.yaml",
            }

    monkeypatch.setattr(cli_main, "_talos_manager", lambda _ctx: _Manager())
    result = runner.invoke(app, ["config", "talos", "info"])
    assert result.exit_code == 0
    assert "managed-talosconfig.yaml" in result.output


def test_crd_list_json_output() -> None:
    result = runner.invoke(app, ["crd", "list", "--query", "cluster", "--output", "json"])
    assert result.exit_code == 0
    assert "Clusters.omni.sidero.dev" in result.output


def test_crd_show_resolves_alias(monkeypatch):
    client = _StubClient()
    monkeypatch.setattr(cli_main, "get_sync_client", lambda **_: client)
    result = runner.invoke(app, ["crd", "show", "cluster", "--output", "json"])
    assert result.exit_code == 0
    assert "Clusters.omni.sidero.dev" in result.output


def test_crd_explain_outputs_description(monkeypatch):
    client = _StubClient()
    monkeypatch.setattr(cli_main, "get_sync_client", lambda **_: client)
    result = runner.invoke(app, ["crd", "explain", "clusterstatus"])
    assert result.exit_code == 0
    assert "ClusterStatuses.omni.sidero.dev" in result.output


def test_get_with_explain_outputs_crd_description(monkeypatch):
    client = _StubClient()
    monkeypatch.setattr(cli_main, "get_sync_client", lambda **_: client)
    result = runner.invoke(
        app,
        ["get", "Clusters.omni.sidero.dev", "cluster-a", "--explain", "--output", "json"],
    )
    assert result.exit_code == 0
    assert "Description:" in result.output
    assert "Clusters.omni.sidero.dev" in result.output


def test_config_history_info_and_clear(monkeypatch):
    class _State:
        def __init__(self) -> None:
            self.cleared = False

        def history_count(self) -> int:
            return 5

        def history_clear(self) -> None:
            self.cleared = True

    class _Manager:
        def __init__(self) -> None:
            self.state = _State()

    manager = _Manager()
    monkeypatch.setattr(cli_main, "_talos_manager", lambda _ctx: manager)
    result = runner.invoke(app, ["config", "history", "info"])
    assert result.exit_code == 0
    assert "max_entries: 2000" in result.output
    assert "count: 5" in result.output

    result = runner.invoke(app, ["config", "history", "clear"])
    assert result.exit_code == 0
    assert manager.state.cleared is True


def test_history_recording_redacts_sensitive_values(monkeypatch):
    class _State:
        def __init__(self) -> None:
            self.calls: list[dict] = []

        def history_add(self, **kwargs) -> None:
            self.calls.append(kwargs)

    class _Async:
        def __init__(self, state: _State) -> None:
            self.state = state
            self.instance_name = "default"
            self.cluster = "cluster-a"

    class _Client:
        def __init__(self, state: _State) -> None:
            self._async = _Async(state)

    class _Manager:
        async def ensure(self, **kwargs):
            return SimpleNamespace(
                path=Path("/tmp/managed-talosconfig.yaml"),
                context="omni/default/cluster-a",
                cluster="cluster-a",
                refreshed=True,
            )

        def remember_cluster(self, cluster: str) -> None:
            pass

        def set_last_targets(
            self,
            *,
            cluster: str | None,
            nodes: str | None = None,
            endpoints: str | None = None,
        ) -> None:
            pass

        def get_last_targets(self, *, cluster: str | None) -> tuple[str | None, str | None]:
            return (None, None)

        def service_account_key_b64(self) -> str | None:
            return None

    state = _State()
    client = _Client(state)
    monkeypatch.setattr(cli_main, "get_sync_client", lambda **_: client)
    monkeypatch.setattr(cli_main, "_talos_manager", lambda _ctx: _Manager())
    monkeypatch.setattr(cli_main.shutil, "which", lambda _: "/usr/bin/talosctl")
    monkeypatch.setattr(
        cli_main.subprocess,
        "run",
        lambda cmd, check=False, env=None: SimpleNamespace(returncode=0),
    )

    result = runner.invoke(app, ["talos", "--token", "super-secret-token", "version"])
    assert result.exit_code == 0
    assert len(state.calls) >= 1
    commands = [str(call["command"]) for call in state.calls]
    assert all("super-secret-token" not in command for command in commands)
    assert any("<redacted>" in command for command in commands)


def test_resource_type_completion_uses_history(monkeypatch):
    class _State:
        def history_suggest(self, prefix: str, limit: int = 200) -> list[str]:
            return ["omnipy get CustomResources.example.dev --namespace default"]

    class _Async:
        def __init__(self) -> None:
            self.state = _State()

    class _Client:
        def __init__(self) -> None:
            self._async = _Async()

    monkeypatch.setattr(cli_main, "get_sync_client", lambda **_: _Client())
    ctx = SimpleNamespace(obj=cli_main.CLIContext())
    suggestions = cli_main._complete_resource_types(ctx, "Custom")
    assert "CustomResources.example.dev" in suggestions
