"""Tests for CLI commands (cli.py). Uses click.testing.CliRunner."""

import json
from pathlib import Path
from unittest.mock import patch

import pytest
from click.testing import CliRunner

import noisegate.config as config_module
from noisegate.cli import cli
from noisegate.models import Program, Verdict
from noisegate.program import save_program
from tests.conftest import make_checks_result


@pytest.fixture(autouse=True)
def isolated_config(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> None:
    config_dir = tmp_path / "noisegate"
    programs_dir = config_dir / "programs"
    monkeypatch.setattr(config_module, "_CONFIG_DIR", config_dir)
    monkeypatch.setattr(config_module, "_CONFIG_FILE", config_dir / "config.json")
    monkeypatch.setattr(config_module, "_POLICY_FILE", config_dir / "policy.yaml")
    monkeypatch.setattr(config_module, "_PROGRAMS_DIR", programs_dir)


@pytest.fixture
def runner() -> CliRunner:
    return CliRunner()


@pytest.fixture
def report_file(tmp_path: Path) -> str:
    f = tmp_path / "report.md"
    f.write_text("# XSS\n\nDetails here.")
    return str(f)


@pytest.fixture
def saved_program() -> None:
    prog = Program(name="Test Program", platform="HackerOne", source="https://example.com")
    prog_path = config_module._PROGRAMS_DIR / "test-program.yaml"
    save_program(prog, prog_path)
    config_module.set_default_program("test-program")


def test_version(runner: CliRunner) -> None:
    result = runner.invoke(cli, ["--version"])
    assert result.exit_code == 0
    assert "0.1.0" in result.output


def test_triage_pass_exit_code(runner: CliRunner, report_file: str, saved_program: None) -> None:
    with patch("noisegate.cli.run_triage", return_value=make_checks_result(Verdict.PASS)):
        result = runner.invoke(cli, ["triage", report_file])
    assert result.exit_code == 0


def test_triage_revise_exit_code(runner: CliRunner, report_file: str, saved_program: None) -> None:
    with patch("noisegate.cli.run_triage", return_value=make_checks_result(Verdict.WARN)):
        result = runner.invoke(cli, ["triage", report_file])
    assert result.exit_code == 1


def test_triage_fail_exit_code(runner: CliRunner, report_file: str, saved_program: None) -> None:
    with patch("noisegate.cli.run_triage", return_value=make_checks_result(Verdict.FAIL)):
        result = runner.invoke(cli, ["triage", report_file])
    assert result.exit_code == 2


def test_triage_json_output(runner: CliRunner, report_file: str, saved_program: None) -> None:
    with patch("noisegate.cli.run_triage", return_value=make_checks_result(Verdict.PASS)):
        result = runner.invoke(cli, ["triage", report_file, "--json"])
    assert result.exit_code == 0
    parsed = json.loads(result.output)
    assert parsed["verdict"] == "PASS"



def test_triage_no_report_file(runner: CliRunner, saved_program: None) -> None:
    result = runner.invoke(cli, ["triage", "/nonexistent/report.md"])
    assert result.exit_code == 3


def test_triage_no_default_program(runner: CliRunner, report_file: str) -> None:
    result = runner.invoke(cli, ["triage", report_file])
    assert result.exit_code == 3


def test_triage_named_program(runner: CliRunner, report_file: str) -> None:
    prog = Program(name="Named Program", platform="HackerOne", source="https://example.com")
    save_program(prog, config_module._PROGRAMS_DIR / "named.yaml")
    with patch("noisegate.cli.run_triage", return_value=make_checks_result(Verdict.PASS)):
        result = runner.invoke(cli, ["triage", report_file, "--program", "named"])
    assert result.exit_code == 0



def test_program_list(runner: CliRunner) -> None:
    for name in ("alpha", "beta"):
        prog = Program(name=name.title(), platform="HackerOne", source="https://example.com")
        save_program(prog, config_module._PROGRAMS_DIR / f"{name}.yaml")
    result = runner.invoke(cli, ["program", "list"])
    assert "alpha" in result.output
    assert "beta" in result.output


def test_program_use(runner: CliRunner) -> None:
    prog = Program(name="My Program", platform="HackerOne", source="https://example.com")
    save_program(prog, config_module._PROGRAMS_DIR / "my-program.yaml")
    result = runner.invoke(cli, ["program", "use", "my-program"])
    assert result.exit_code == 0
    assert config_module.get_default_program_name() == "my-program"


def test_program_show(runner: CliRunner, saved_program: None) -> None:
    result = runner.invoke(cli, ["program", "show", "test-program"])
    assert result.exit_code == 0
    assert "Test Program" in result.output


def test_program_remove(runner: CliRunner) -> None:
    prog = Program(name="To Delete", platform="HackerOne", source="https://example.com")
    save_program(prog, config_module._PROGRAMS_DIR / "to-delete.yaml")
    result = runner.invoke(cli, ["program", "remove", "to-delete"], input="y\n")
    assert result.exit_code == 0
    assert "to-delete" not in [p.stem for p in config_module._PROGRAMS_DIR.glob("*.yaml")]
