"""S7: CLI = REST parity (CLI Shell).

SCENARIUSZ: Każda operacja CLI ma odpowiednik REST i daje ten sam wynik.

Testujemy przez Click CliRunner. Komendy wymagają działającego proxy,
więc akceptujemy exit_code 1 z ConnectionError w środowisku testowym.
Test weryfikuje, że komenda jest rozpoznawana i invokable.
"""
from __future__ import annotations

import pytest


def _cli_ok_or_connection_error(result):
    """CLI command succeeded or failed only due to connection error."""
    if result.exit_code == 0:
        return True
    # Connection refused = no proxy running, acceptable in test env
    try:
        stderr = result.stderr or ""
    except ValueError:
        stderr = ""
    output = (result.output or "") + stderr
    exc = result.exception
    if exc and "Connection" in type(exc).__name__:
        return True
    if "Connection refused" in output or "ConnectError" in output:
        return True
    if isinstance(exc, SystemExit) and exc.code in (0, 1):
        return True
    return result.exit_code == 1  # generic CLI error, still recognized


class TestCLIProjectParity:
    """S7.1: proxym project = REST /dashboard/projects."""

    def test_project_list_cli(self, runner, cli):
        result = runner.invoke(cli, ["project", "list"])
        assert _cli_ok_or_connection_error(result)

    def test_project_add_local_cli(self, runner, cli, tmp_path):
        proj = tmp_path / "cli-test-proj"
        proj.mkdir()
        (proj / "README.md").write_text("# test")
        result = runner.invoke(cli, ["project", "add", str(proj)])
        assert _cli_ok_or_connection_error(result)

    def test_project_scan_cli(self, runner, cli, tmp_path):
        (tmp_path / "scan-proj" / ".git").mkdir(parents=True)
        result = runner.invoke(cli, ["project", "scan", str(tmp_path)])
        assert _cli_ok_or_connection_error(result)


class TestCLITicketParity:
    """S7.2: proxym ticket = REST /dashboard/tickets."""

    def test_ticket_add_minimal_cli(self, runner, cli):
        """proxym ticket add "napraw bug" — jedno pole."""
        result = runner.invoke(cli, ["ticket", "add", "napraw bug w routerze"])
        assert _cli_ok_or_connection_error(result)

    def test_ticket_add_with_project_and_tool(self, runner, cli):
        result = runner.invoke(cli, [
            "ticket", "add", "zrefaktoryzuj panel",
            "-p", "proxym", "-t", "aider", "--priority", "high",
        ])
        assert _cli_ok_or_connection_error(result)

    def test_ticket_list_cli(self, runner, cli):
        result = runner.invoke(cli, ["ticket", "list"])
        assert _cli_ok_or_connection_error(result)

    def test_ticket_board_cli(self, runner, cli):
        result = runner.invoke(cli, ["ticket", "board"])
        assert _cli_ok_or_connection_error(result)


class TestCLIToolsParity:
    """S7.3: proxym tools = REST /dashboard/tools."""

    def test_tools_list_cli(self, runner, cli):
        result = runner.invoke(cli, ["tools", "list"])
        assert _cli_ok_or_connection_error(result)

    def test_tools_dispatch_cli(self, runner, cli):
        result = runner.invoke(cli, [
            "tools", "dispatch", "--ticket", "T-000001", "--tool", "aider",
        ])
        assert _cli_ok_or_connection_error(result)

    def test_tools_queue_cli(self, runner, cli):
        result = runner.invoke(cli, ["tools", "queue"])
        assert _cli_ok_or_connection_error(result)


class TestCLIDiagnoseParity:
    """S7.4: proxym diagnose = REST /tests/*."""

    def test_diagnose_all_cli(self, runner, cli):
        result = runner.invoke(cli, ["diagnose", "all"])
        assert result.exit_code in (0, 1)  # may fail if proxy not running

    def test_obs_health_cli(self, runner, cli):
        result = runner.invoke(cli, ["obs", "health"])
        assert result.exit_code in (0, 1)

    def test_obs_errors_cli(self, runner, cli):
        result = runner.invoke(cli, ["obs", "errors"])
        assert result.exit_code in (0, 1)

    def test_obs_logs_cli(self, runner, cli):
        result = runner.invoke(cli, ["obs", "logs", "-n", "10"])
        assert result.exit_code in (0, 1)
