"""CLI tests for `attractor validate`.

Both happy-path (valid file → exit 0) and the line:col error path
(invalid file → exit 2 with `<file>:<line>:<col>: <msg>` on stderr).
"""

from __future__ import annotations

from pathlib import Path

from click.testing import CliRunner

from attractor.cli.main import cli

_VALID = """\
digraph V {
    start [shape=Mdiamond, label="S"]
    exit  [shape=Msquare,  label="E"]
    start -> exit
}
"""


_INVALID_PARSE = """\
digraph
"""


_INVALID_STRUCTURE = """\
digraph M {
    a [shape=Mdiamond, label="A"]
    b [shape=box, label="B"]
    a -> b
}
"""


# [unit->REQ-CLI-SCAFFOLD]
# [int->REQ-DOD-VALIDATE-ERRORS]
def test_validate_valid_workflow_exits_zero(tmp_path: Path) -> None:
    """Happy path: prints `valid: N nodes, M edges` and exits 0."""
    wf = tmp_path / "wf.dot"
    wf.write_text(_VALID, encoding="utf-8")
    runner = CliRunner()
    result = runner.invoke(cli, ["validate", str(wf)])
    assert result.exit_code == 0
    assert "valid:" in result.output
    assert "2 nodes" in result.output
    assert "1 edges" in result.output


# [unit->REQ-CLI-SCAFFOLD]
# [int->REQ-DOD-VALIDATE-ERRORS]
def test_validate_parse_error_prints_line_col(tmp_path: Path) -> None:
    """Parse error: exit 2 with `<file>:<line>:<col>: <message>`."""
    wf = tmp_path / "wf.dot"
    wf.write_text(_INVALID_PARSE, encoding="utf-8")
    runner = CliRunner()
    result = runner.invoke(cli, ["validate", str(wf)])
    assert result.exit_code == 2
    # The error format is `<file>:line:col: message` — assert structure.
    stderr_lines = (result.stderr or "").strip().splitlines()
    assert stderr_lines, "expected at least one error line on stderr"
    assert ":" in stderr_lines[0]


# [unit->REQ-CLI-SCAFFOLD]
# [int->REQ-DOD-VALIDATE-ERRORS]
def test_validate_structural_error_prints_line_col(tmp_path: Path) -> None:
    """Validation error (missing exit): exit 2 with line:col error."""
    wf = tmp_path / "wf.dot"
    wf.write_text(_INVALID_STRUCTURE, encoding="utf-8")
    runner = CliRunner()
    result = runner.invoke(cli, ["validate", str(wf)])
    assert result.exit_code == 2
    assert "exit node" in (result.stderr or "").lower()


# [unit->REQ-CLI-SCAFFOLD]
def test_validate_missing_file_exits_two(tmp_path: Path) -> None:
    """File-not-found maps to exit 2 with a clear message."""
    runner = CliRunner()
    result = runner.invoke(cli, ["validate", str(tmp_path / "missing.dot")])
    assert result.exit_code == 2
    assert "not found" in (result.stderr or "").lower()
