"""Tests for ``jarvis init`` next-steps guidance."""

from __future__ import annotations

from pathlib import Path
from unittest import mock

from click.testing import CliRunner

from openjarvis.cli import cli
from openjarvis.cli.init_cmd import _next_steps_text

_NO_DL = "--no-download"


class TestInitShowsNextSteps:
    def test_init_shows_next_steps(self, tmp_path: Path) -> None:
        """Init command prints next-steps panel after writing config."""
        config_dir = tmp_path / ".openjarvis"
        config_path = config_dir / "config.toml"
        with (
            mock.patch("openjarvis.cli.init_cmd.DEFAULT_CONFIG_DIR", config_dir),
            mock.patch("openjarvis.cli.init_cmd.DEFAULT_CONFIG_PATH", config_path),
            mock.patch("openjarvis.cli.init_cmd.PrivacyScanner"),
        ):
            result = CliRunner().invoke(cli, ["init", "--engine", "llamacpp", _NO_DL])
        assert result.exit_code == 0
        assert "Getting Started" in result.output
        assert "jarvis ask" in result.output
        assert "jarvis doctor" in result.output

    def test_init_output_shows_toml_sections_literally(self, tmp_path: Path) -> None:
        """Init output should render TOML section headers like [engine] literally."""
        config_dir = tmp_path / ".openjarvis"
        config_path = config_dir / "config.toml"
        with (
            mock.patch("openjarvis.cli.init_cmd.DEFAULT_CONFIG_DIR", config_dir),
            mock.patch("openjarvis.cli.init_cmd.DEFAULT_CONFIG_PATH", config_path),
            mock.patch("openjarvis.cli.init_cmd.PrivacyScanner"),
        ):
            result = CliRunner().invoke(cli, ["init", "--engine", "llamacpp", _NO_DL])
        assert result.exit_code == 0
        assert "[engine]" in result.output
        assert "[intelligence]" in result.output


class TestNextStepsOllama:
    def test_next_steps_ollama(self) -> None:
        text = _next_steps_text("ollama")
        assert "ollama serve" in text
        assert "ollama pull" in text
        assert "jarvis ask" in text
        assert "jarvis doctor" in text

    def test_next_steps_ollama_with_model(self) -> None:
        text = _next_steps_text("ollama", "qwen3.5:27b")
        assert "ollama pull qwen3.5:27b" in text

    def test_next_steps_ollama_default_model(self) -> None:
        text = _next_steps_text("ollama")
        assert "ollama pull qwen3.5:2b" in text


class TestNextStepsVllm:
    def test_next_steps_vllm(self) -> None:
        text = _next_steps_text("vllm")
        assert "pip install vllm" in text
        assert "vllm serve" in text
        assert "jarvis ask" in text
        assert "jarvis doctor" in text


class TestNextStepsLlamacpp:
    def test_next_steps_llamacpp(self) -> None:
        text = _next_steps_text("llamacpp")
        assert "brew install llama.cpp" in text
        assert "llama-server" in text
        assert "jarvis ask" in text
        assert "jarvis doctor" in text


class TestNextStepsMlx:
    def test_next_steps_mlx(self) -> None:
        text = _next_steps_text("mlx")
        assert "pip install mlx-lm" in text
        assert "mlx_lm.server" in text
        assert "jarvis ask" in text
        assert "jarvis doctor" in text


class TestMinimalConfig:
    def test_init_generates_minimal_by_default(self, tmp_path: Path) -> None:
        """Default jarvis init produces a short config."""
        config_dir = tmp_path / ".openjarvis"
        config_path = config_dir / "config.toml"
        with (
            mock.patch("openjarvis.cli.init_cmd.DEFAULT_CONFIG_DIR", config_dir),
            mock.patch("openjarvis.cli.init_cmd.DEFAULT_CONFIG_PATH", config_path),
            mock.patch("openjarvis.cli.init_cmd.PrivacyScanner"),
        ):
            result = CliRunner().invoke(cli, ["init", "--engine", "ollama", _NO_DL])
        assert result.exit_code == 0
        content = config_path.read_text()
        # Minimal config should be short
        lines = [ln for ln in content.splitlines() if ln.strip()]
        assert len(lines) <= 30
        # Should have the reference hint
        assert "jarvis init --full" in content

    def test_init_full_generates_verbose_config(self, tmp_path: Path) -> None:
        """jarvis init --full produces the full reference config."""
        config_dir = tmp_path / ".openjarvis"
        config_path = config_dir / "config.toml"
        with (
            mock.patch("openjarvis.cli.init_cmd.DEFAULT_CONFIG_DIR", config_dir),
            mock.patch("openjarvis.cli.init_cmd.DEFAULT_CONFIG_PATH", config_path),
            mock.patch("openjarvis.cli.init_cmd.PrivacyScanner"),
        ):
            result = CliRunner().invoke(
                cli,
                ["init", "--full", "--engine", "ollama", _NO_DL],
            )
        assert result.exit_code == 0
        content = config_path.read_text()
        # Full config should have many sections
        assert "[engine.ollama]" in content
        assert "[server]" in content
        assert "[security]" in content


class TestInitDownloadPrompt:
    def test_init_shows_download_prompt(self, tmp_path: Path) -> None:
        config_dir = tmp_path / ".openjarvis"
        config_path = config_dir / "config.toml"
        with (
            mock.patch("openjarvis.cli.init_cmd.DEFAULT_CONFIG_DIR", config_dir),
            mock.patch("openjarvis.cli.init_cmd.DEFAULT_CONFIG_PATH", config_path),
            mock.patch("openjarvis.cli.init_cmd.PrivacyScanner"),
        ):
            result = CliRunner().invoke(
                cli, ["init", "--engine", "ollama"], input="n\n"
            )
        assert result.exit_code == 0
        assert "Download" in result.output
        assert "now?" in result.output

    def test_init_no_download_flag_skips_prompt(self, tmp_path: Path) -> None:
        config_dir = tmp_path / ".openjarvis"
        config_path = config_dir / "config.toml"
        with (
            mock.patch("openjarvis.cli.init_cmd.DEFAULT_CONFIG_DIR", config_dir),
            mock.patch("openjarvis.cli.init_cmd.DEFAULT_CONFIG_PATH", config_path),
            mock.patch("openjarvis.cli.init_cmd.PrivacyScanner"),
        ):
            result = CliRunner().invoke(cli, ["init", "--engine", "ollama", _NO_DL])
        assert result.exit_code == 0
        assert "Download" not in result.output


class TestInitEmptyModelFallback:
    def test_init_no_model_shows_warning(self, tmp_path: Path) -> None:
        config_dir = tmp_path / ".openjarvis"
        config_path = config_dir / "config.toml"
        with (
            mock.patch("openjarvis.cli.init_cmd.DEFAULT_CONFIG_DIR", config_dir),
            mock.patch("openjarvis.cli.init_cmd.DEFAULT_CONFIG_PATH", config_path),
            mock.patch("openjarvis.cli.init_cmd.recommend_model", return_value=""),
            mock.patch("openjarvis.cli.init_cmd.PrivacyScanner"),
        ):
            result = CliRunner().invoke(cli, ["init", "--engine", "llamacpp"])
        assert result.exit_code == 0
        assert (
            "Not enough memory" in result.output or "not enough memory" in result.output
        )


class TestNextStepsExoNexa:
    def test_next_steps_exo(self) -> None:
        text = _next_steps_text("exo")
        assert "exo" in text.lower()
        assert "jarvis ask" in text
        assert "ollama" not in text.lower()

    def test_next_steps_nexa(self) -> None:
        text = _next_steps_text("nexa")
        assert "nexa" in text.lower()
        assert "jarvis ask" in text
        assert "ollama" not in text.lower()


class TestInitDownloadDispatch:
    def test_init_ollama_download_calls_ollama_pull(self, tmp_path: Path) -> None:
        config_dir = tmp_path / ".openjarvis"
        config_path = config_dir / "config.toml"
        with (
            mock.patch("openjarvis.cli.init_cmd.DEFAULT_CONFIG_DIR", config_dir),
            mock.patch("openjarvis.cli.init_cmd.DEFAULT_CONFIG_PATH", config_path),
            mock.patch(
                "openjarvis.cli.init_cmd.ollama_pull",
                return_value=True,
            ) as mock_pull,
            mock.patch("openjarvis.cli.init_cmd.PrivacyScanner"),
        ):
            result = CliRunner().invoke(
                cli, ["init", "--engine", "ollama"], input="y\n"
            )
        assert result.exit_code == 0
        mock_pull.assert_called_once()

    def test_init_vllm_shows_auto_download_message(self, tmp_path: Path) -> None:
        config_dir = tmp_path / ".openjarvis"
        config_path = config_dir / "config.toml"
        with (
            mock.patch("openjarvis.cli.init_cmd.DEFAULT_CONFIG_DIR", config_dir),
            mock.patch("openjarvis.cli.init_cmd.DEFAULT_CONFIG_PATH", config_path),
            mock.patch("openjarvis.cli.init_cmd.PrivacyScanner"),
        ):
            result = CliRunner().invoke(cli, ["init", "--engine", "vllm"], input="y\n")
        assert result.exit_code == 0
        assert "automatically" in result.output


class TestInitPrivacyHook:
    def test_init_shows_privacy_summary(self, tmp_path: Path) -> None:
        config_dir = tmp_path / ".openjarvis"
        config_path = config_dir / "config.toml"
        with (
            mock.patch("openjarvis.cli.init_cmd.DEFAULT_CONFIG_DIR", config_dir),
            mock.patch("openjarvis.cli.init_cmd.DEFAULT_CONFIG_PATH", config_path),
            mock.patch("openjarvis.cli.init_cmd.PrivacyScanner") as MockScanner,
        ):
            from openjarvis.cli.scan_cmd import ScanResult

            instance = MockScanner.return_value
            instance.run_quick.return_value = [
                ScanResult("FileVault", "ok", "FileVault enabled", "darwin"),
            ]
            result = CliRunner().invoke(cli, ["init", "--engine", "llamacpp", _NO_DL])
        assert result.exit_code == 0
        assert "jarvis scan" in result.output
