"""End-to-end CLI tests for the Phase 2 commands.

The commands hit real on-disk paths (tmp_path) so the assertions run
the production code paths verbatim.
"""

from __future__ import annotations

from datetime import UTC, datetime
from pathlib import Path

from click.testing import CliRunner

from cerbero_bite.cli import main as cli_main
from cerbero_bite.safety import AuditLog
from cerbero_bite.state import Repository, connect, run_migrations, transaction


def _seed_state(db_path: Path) -> None:
    conn = connect(db_path)
    try:
        run_migrations(conn)
        with transaction(conn):
            Repository().init_system_state(
                conn,
                config_version="1.0.0",
                now=datetime(2026, 4, 27, 14, 0, tzinfo=UTC),
            )
    finally:
        conn.close()


def test_audit_verify_reports_ok_on_clean_chain(tmp_path: Path) -> None:
    audit = AuditLog(tmp_path / "audit.log")
    audit.append(event="A", payload={}, now=datetime(2026, 4, 27, 14, 0, tzinfo=UTC))
    audit.append(event="B", payload={}, now=datetime(2026, 4, 27, 14, 1, tzinfo=UTC))

    result = CliRunner().invoke(
        cli_main, ["audit", "verify", "--file", str(tmp_path / "audit.log")]
    )
    assert result.exit_code == 0, result.output
    assert "ok" in result.output
    assert "2" in result.output


def test_audit_verify_handles_empty_file(tmp_path: Path) -> None:
    target = tmp_path / "audit.log"
    target.write_text("", encoding="utf-8")
    result = CliRunner().invoke(cli_main, ["audit", "verify", "--file", str(target)])
    assert result.exit_code == 0
    assert "empty" in result.output


def test_audit_verify_exits_nonzero_on_tampering(tmp_path: Path) -> None:
    target = tmp_path / "audit.log"
    audit = AuditLog(target)
    audit.append(event="A", payload={}, now=datetime(2026, 4, 27, 14, 0, tzinfo=UTC))
    target.write_text(
        target.read_text(encoding="utf-8").replace('"event":"A"', '"event":"X"'),
        encoding="utf-8",
    )
    # NB: we mutated the JSON payload, but the actual line still has event=A.
    # Force tampering by editing the literal "A" in the line text.
    raw = target.read_text(encoding="utf-8")
    target.write_text(raw.replace("|A|", "|X|", 1), encoding="utf-8")

    result = CliRunner().invoke(cli_main, ["audit", "verify", "--file", str(target)])
    assert result.exit_code == 2
    assert "TAMPERED" in result.output


def test_kill_switch_status_prints_disarmed(tmp_path: Path) -> None:
    db = tmp_path / "state.sqlite"
    _seed_state(db)
    result = CliRunner().invoke(cli_main, ["kill-switch", "status", "--db", str(db)])
    assert result.exit_code == 0
    assert "disarmed" in result.output


def test_kill_switch_arm_then_status_shows_armed(tmp_path: Path) -> None:
    db = tmp_path / "state.sqlite"
    audit = tmp_path / "audit.log"
    runner = CliRunner()
    arm = runner.invoke(
        cli_main,
        [
            "kill-switch",
            "arm",
            "--reason",
            "manual smoke",
            "--db",
            str(db),
            "--audit",
            str(audit),
        ],
    )
    assert arm.exit_code == 0, arm.output
    status = runner.invoke(cli_main, ["kill-switch", "status", "--db", str(db)])
    assert status.exit_code == 0
    assert "ARMED" in status.output


def test_kill_switch_status_handles_missing_db(tmp_path: Path) -> None:
    result = CliRunner().invoke(
        cli_main, ["kill-switch", "status", "--db", str(tmp_path / "absent.sqlite")]
    )
    assert result.exit_code == 0
    assert "not found" in result.output


def test_state_inspect_shows_no_open_positions(tmp_path: Path) -> None:
    db = tmp_path / "state.sqlite"
    _seed_state(db)
    result = CliRunner().invoke(cli_main, ["state", "inspect", "--db", str(db)])
    assert result.exit_code == 0
    assert "no open positions" in result.output


def test_state_inspect_handles_missing_db(tmp_path: Path) -> None:
    result = CliRunner().invoke(
        cli_main, ["state", "inspect", "--db", str(tmp_path / "absent.sqlite")]
    )
    assert result.exit_code == 0
    assert "not found" in result.output


def test_config_hash_matches_loader(tmp_path: Path) -> None:
    target = tmp_path / "strategy.yaml"
    target.write_text(
        'config_version: "1.0.0"\nconfig_hash: "0000"\nasset:\n  symbol: ETH\n',
        encoding="utf-8",
    )
    result = CliRunner().invoke(cli_main, ["config", "hash", "--file", str(target)])
    assert result.exit_code == 0
    assert len(result.output.strip()) == 64  # sha256 hex


def test_config_validate_repo_strategy_yaml() -> None:
    repo_root = Path(__file__).resolve().parents[2]
    yaml_path = repo_root / "strategy.yaml"
    result = CliRunner().invoke(
        cli_main, ["config", "validate", "--file", str(yaml_path)]
    )
    assert result.exit_code == 0
    assert "ok" in result.output


def test_config_validate_with_no_enforce_hash_skips_check(tmp_path: Path) -> None:
    target = tmp_path / "strategy.yaml"
    target.write_text(
        'config_version: "1.0.0"\nconfig_hash: "wrong"\n'
        'last_review: "2026-04-26"\nlast_reviewer: "test"\n',
        encoding="utf-8",
    )
    result = CliRunner().invoke(
        cli_main,
        ["config", "validate", "--file", str(target), "--no-enforce-hash"],
    )
    assert result.exit_code == 0
    assert "ok" in result.output
