"""Tests for config loading and the `sanicode config` CLI command."""

from __future__ import annotations

import sys
from pathlib import Path

import pytest
from typer.testing import CliRunner

from sanicode.cli import app
from sanicode.config import SanicodeConfig, load_config

if sys.version_info >= (3, 11):
    import tomllib
else:
    import tomli as tomllib  # type: ignore[no-redef]

runner = CliRunner()

# ---------------------------------------------------------------------------
# Unit tests for load_config()
# ---------------------------------------------------------------------------


def test_load_config_defaults(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> None:
    """load_config() with no file present returns defaults."""
    monkeypatch.chdir(tmp_path)
    cfg = load_config()
    assert isinstance(cfg, SanicodeConfig)
    assert cfg._source_path is None
    assert cfg.scan.include_extensions == [".py"]
    assert cfg.scan.max_file_size_kb == 512
    assert "owasp-asvs" in cfg.compliance.profiles
    assert cfg.llm.fast.endpoint == ""
    assert cfg.output.formats == ["markdown", "sarif"]


def test_load_config_from_file(tmp_path: Path) -> None:
    """load_config() with an explicit TOML populates fields correctly."""
    toml_content = """\
[llm.fast]
endpoint = "http://localhost:11434/v1"
model = "granite3-dense:2b"

[scan]
include_extensions = [".py", ".js"]
max_file_size_kb = 256

[output]
formats = ["sarif"]
output_dir = "my-reports"

[compliance]
profiles = ["owasp-asvs"]
"""
    cfg_file = tmp_path / "sanicode.toml"
    cfg_file.write_text(toml_content, encoding="utf-8")

    cfg = load_config(cfg_file)

    assert cfg._source_path == cfg_file
    assert cfg.llm.fast.endpoint == "http://localhost:11434/v1"
    assert cfg.llm.fast.model == "granite3-dense:2b"
    assert cfg.llm.analysis.endpoint == ""  # not set in file
    assert cfg.scan.include_extensions == [".py", ".js"]
    assert cfg.scan.max_file_size_kb == 256
    assert cfg.output.formats == ["sarif"]
    assert cfg.output.output_dir == "my-reports"
    assert cfg.compliance.profiles == ["owasp-asvs"]


def test_load_config_explicit_missing(tmp_path: Path) -> None:
    """load_config() raises FileNotFoundError when explicit path doesn't exist."""
    missing = tmp_path / "nonexistent.toml"
    with pytest.raises(FileNotFoundError, match="nonexistent.toml"):
        load_config(missing)


# ---------------------------------------------------------------------------
# CLI tests for `sanicode config`
# ---------------------------------------------------------------------------


def test_config_show_defaults(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> None:
    """config --show with no config file shows defaults section headers."""
    monkeypatch.chdir(tmp_path)
    result = runner.invoke(app, ["config", "--show"])
    assert result.exit_code == 0, result.output
    assert "defaults" in result.output
    assert "Scan" in result.output
    assert "LLM" in result.output


def test_config_no_flags_shows_config(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> None:
    """config with no flags also displays the resolved configuration."""
    monkeypatch.chdir(tmp_path)
    result = runner.invoke(app, ["config"])
    assert result.exit_code == 0, result.output
    assert "Scan" in result.output
    assert "LLM" in result.output


def test_config_show_with_file(tmp_path: Path) -> None:
    """config --show --config <path> displays the configured LLM endpoint."""
    toml_content = """\
[llm.analysis]
endpoint = "http://granite.example.com/v1"
model = "granite-code:8b"
"""
    cfg_file = tmp_path / "sanicode.toml"
    cfg_file.write_text(toml_content, encoding="utf-8")

    result = runner.invoke(app, ["config", "--show", "--config", str(cfg_file)])
    assert result.exit_code == 0, result.output
    assert "http://granite.example.com/v1" in result.output
    assert "granite-code:8b" in result.output


def test_config_init_creates_file(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> None:
    """config --init writes sanicode.toml with valid TOML content."""
    monkeypatch.chdir(tmp_path)
    result = runner.invoke(app, ["config", "--init"])
    assert result.exit_code == 0, result.output

    dest = tmp_path / "sanicode.toml"
    assert dest.exists(), "sanicode.toml was not created"

    # Must be parseable TOML.
    with open(dest, "rb") as fh:
        parsed = tomllib.load(fh)

    # Template has scan and output sections uncommented.
    assert "scan" in parsed
    assert "output" in parsed
    assert "compliance" in parsed


def test_config_init_refuses_overwrite(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> None:
    """config --init exits 1 and warns when sanicode.toml already exists."""
    monkeypatch.chdir(tmp_path)
    existing = tmp_path / "sanicode.toml"
    existing.write_text("[scan]\n", encoding="utf-8")

    result = runner.invoke(app, ["config", "--init"])
    assert result.exit_code == 1, result.output
    assert "already exists" in result.output


@pytest.mark.parametrize(
    ("endpoint", "model"),
    [
        ("http://localhost:11434/v1", "granite3-dense:2b"),
        ("http://custom.host/v1", "llama3.1:70b"),
    ],
)
def test_config_show_llm_tier_values(tmp_path: Path, endpoint: str, model: str) -> None:
    """config --show reflects LLM tier endpoint and model from the config file."""
    toml_content = f"""\
[llm.fast]
endpoint = "{endpoint}"
model = "{model}"
"""
    cfg_file = tmp_path / "sanicode.toml"
    cfg_file.write_text(toml_content, encoding="utf-8")

    result = runner.invoke(app, ["config", "--config", str(cfg_file)])
    assert result.exit_code == 0, result.output
    assert endpoint in result.output
    assert model in result.output


def test_config_show_missing_explicit_file(tmp_path: Path) -> None:
    """config --config <nonexistent> exits 1 with an error message."""
    missing = tmp_path / "nope.toml"
    result = runner.invoke(app, ["config", "--config", str(missing)])
    assert result.exit_code == 1, result.output
    assert "nope.toml" in result.output
