import json
from pathlib import Path
from typing import Any

from typer.testing import CliRunner

from k1link.device_plugins.xgrids_k1 import cli
from k1link.device_plugins.xgrids_k1.cli import app

runner = CliRunner()


def test_help() -> None:
    result = runner.invoke(app, ["--help"])
    assert result.exit_code == 0
    assert "evidence-led" in result.stdout


def test_doctor_json() -> None:
    result = runner.invoke(app, ["doctor", "--json"])
    assert result.exit_code == 0
    payload = json.loads(result.stdout)
    assert payload["k1link_version"] == "0.1.0"
    assert isinstance(payload["tools"], list)
    assert isinstance(payload["network"], dict)
    assert any(item["name"] == "tcpdump" for item in payload["tools"])


def test_serve_resolves_frontend_from_repository_root(monkeypatch: Any) -> None:
    captured: dict[str, object] = {}

    def fake_run(application: str, **kwargs: object) -> None:
        captured.update({"application": application, **kwargs})

    monkeypatch.setattr(cli.uvicorn, "run", fake_run)

    result = runner.invoke(app, ["serve"])

    assert result.exit_code == 0
    assert captured == {
        "application": "k1link.web.app:app",
        "host": "127.0.0.1",
        "port": 8000,
        "log_level": "info",
        "access_log": True,
    }


def test_authority_provision_requires_explicit_reviewed_value_confirmation() -> None:
    result = runner.invoke(app, ["authority", "provision"])

    assert result.exit_code == 2
    assert "provisioning not confirmed" in result.stdout


def test_authority_provision_never_accepts_the_secret_as_a_cli_value(monkeypatch: Any) -> None:
    calls = 0

    class FakeSnapshot:
        service = "fixed-service"
        account = "fixed-account"

    class FakeProvisioner:
        def provision_interactively(self) -> FakeSnapshot:
            nonlocal calls
            calls += 1
            return FakeSnapshot()

    monkeypatch.setattr(
        "k1link.device_plugins.xgrids_k1.cli.MacOSKeychainApplicationAuthorityProvisioner",
        FakeProvisioner,
    )
    result = runner.invoke(
        app,
        ["authority", "provision", "--confirm-reviewed-authority"],
    )

    assert result.exit_code == 0
    assert calls == 1
    assert "Keychain item validated" in result.stdout
    assert "No K1 command was sent" in " ".join(result.stdout.split())


def test_mqtt_capture_requires_owned_device_confirmation(tmp_path: Path) -> None:
    result = runner.invoke(
        app,
        [
            "net",
            "mqtt-capture",
            "--host",
            "192.168.1.20",
            "--out",
            str(tmp_path / "capture"),
        ],
    )
    assert result.exit_code == 2
    assert "ownership not confirmed" in result.stdout
    assert not (tmp_path / "capture").exists()


def test_mqtt_capture_cli_uses_bounded_read_only_capture(
    monkeypatch: Any,
    tmp_path: Path,
) -> None:
    captured: dict[str, object] = {}

    def fake_capture(host: str, out: Path, **kwargs: object) -> dict[str, object]:
        on_ready = kwargs.pop("on_ready")
        assert callable(on_ready)
        on_ready()
        captured.update({"host": host, "out": out, **kwargs})
        return {
            "stop_reason": "duration_elapsed",
            "message_count": 2,
            "payload_bytes": 128,
        }

    monkeypatch.setattr("k1link.device_plugins.xgrids_k1.cli.capture_mqtt", fake_capture)
    out = tmp_path / "capture"
    result = runner.invoke(
        app,
        [
            "net",
            "mqtt-capture",
            "--host",
            "10.0.0.42",
            "--out",
            str(out),
            "--duration",
            "5",
            "--max-message-bytes",
            "1024",
            "--confirm-owned-device",
        ],
    )

    assert result.exit_code == 0
    assert captured == {
        "host": "10.0.0.42",
        "out": out,
        "port": 1883,
        "duration_seconds": 5.0,
        "max_message_bytes": 1024,
    }
    assert "messages: 2" in result.stdout
    assert "subscriptions active" in result.stdout
