# ruff: noqa: SIM105, SIM117
"""Tests for CLI UX v0.14.0 — toggle, shell alias, quiet flag, help structure,
session stats, and human-in-loop session control."""

import sys
import time
from unittest.mock import patch

import pytest

from auto_yes import __version__
from auto_yes.cli import (
    _handle_continue,
    _handle_ls,
    _handle_pause,
    _handle_status,
    _handle_toggle,
    main,
)
from auto_yes.runner import Runner

# ==================================================================
# 1. Version check
# ==================================================================


class TestVersion:
    def test_version_is_014(self):
        assert __version__ == "0.15.0"

    def test_version_flag(self, capsys):
        main(["--version"])
        out = capsys.readouterr().out
        assert "0.15.0" in out

    def test_version_short_flag(self, capsys):
        main(["-V"])
        out = capsys.readouterr().out
        assert "0.15.0" in out


# ==================================================================
# 2. --help structure
# ==================================================================


class TestHelpStructure:
    def test_help_contains_quick_start_section(self, capsys):
        main([])
        out = capsys.readouterr().out
        assert "QUICK START" in out

    def test_help_contains_session_control_section(self, capsys):
        main([])
        out = capsys.readouterr().out
        assert "SESSION CONTROL" in out

    def test_help_contains_toggle_command(self, capsys):
        main([])
        out = capsys.readouterr().out
        assert "toggle" in out

    def test_help_contains_shell_alias(self, capsys):
        main([])
        out = capsys.readouterr().out
        assert "shell" in out

    def test_help_contains_quiet_flag(self, capsys):
        main([])
        out = capsys.readouterr().out
        assert "--quiet" in out or "-q" in out

    def test_help_contains_examples_section(self, capsys):
        main([])
        out = capsys.readouterr().out
        assert "EXAMPLES" in out

    def test_help_contains_options_section(self, capsys):
        main([])
        out = capsys.readouterr().out
        assert "OPTIONS" in out

    def test_explicit_help_flag(self, capsys):
        main(["-h"])
        out = capsys.readouterr().out
        assert "auto-yes" in out
        assert "QUICK START" in out


# ==================================================================
# 3. shell alias (maps to --on / shell session)
# ==================================================================


class TestShellAlias:
    def test_shell_in_dispatch(self):
        """'shell' is a recognised command (doesn't print 'unknown command')."""
        with patch("auto_yes.cli._handle_on") as mock_on:
            with patch("sys.argv", ["auto-yes", "shell"]):
                try:
                    main(["shell"])
                except SystemExit:
                    pass
            mock_on.assert_called_once_with([])

    def test_shell_with_options_passed_through(self):
        with patch("auto_yes.cli._handle_on") as mock_on:
            try:
                main(["shell", "--cli", "claude"])
            except SystemExit:
                pass
            mock_on.assert_called_once_with(["--cli", "claude"])


# ==================================================================
# 4. toggle command
# ==================================================================


# Toggle tests are implemented as module-level functions below (pytest-native)


# Rewrite toggle tests as plain pytest functions for cleaner execution:

def test_toggle_no_args_exits(capsys):
    import pytest
    with pytest.raises(SystemExit):
        _handle_toggle([])
    assert "usage" in capsys.readouterr().err


def test_toggle_pauses_active(capsys):
    fake = [(42, {"profile": "claude"}, False)]
    with patch("auto_yes.cli._cfg.list_sessions", return_value=fake):
        with patch("auto_yes.cli._cfg.set_paused") as mock_set:
            _handle_toggle(["42"])
            mock_set.assert_called_once_with(42, True)
    assert "paused" in capsys.readouterr().out


def test_toggle_resumes_paused(capsys):
    fake = [(42, {"profile": "claude"}, True)]
    with patch("auto_yes.cli._cfg.list_sessions", return_value=fake):
        with patch("auto_yes.cli._cfg.set_paused") as mock_set:
            _handle_toggle(["42"])
            mock_set.assert_called_once_with(42, False)
    assert "resumed" in capsys.readouterr().out


def test_toggle_all_mixed(capsys):
    fake = [(1, {}, False), (2, {}, True), (3, {}, False)]
    with patch("auto_yes.cli._cfg.list_sessions", return_value=fake):
        with patch("auto_yes.cli._cfg.set_paused") as mock_set:
            _handle_toggle(["all"])
            calls = [c[0] for c in mock_set.call_args_list]
            assert (1, True) in calls
            assert (2, False) in calls
            assert (3, True) in calls


def test_toggle_no_sessions(capsys):
    with patch("auto_yes.cli._cfg.list_sessions", return_value=[]):
        _handle_toggle(["all"])
    assert "no running" in capsys.readouterr().out


def test_toggle_unknown_pid(capsys):
    import pytest
    with patch("auto_yes.cli._cfg.list_sessions", return_value=[]), pytest.raises(SystemExit):
        _handle_toggle(["99999"])
    assert "no running" in capsys.readouterr().err


def test_toggle_invalid_pid(capsys):
    import pytest
    with pytest.raises(SystemExit):
        _handle_toggle(["abc"])
    assert "valid PID" in capsys.readouterr().err


# ==================================================================
# 5. --quiet flag
# ==================================================================


class TestQuietFlag:
    def test_runner_quiet_suppresses_verbose(self):
        """quiet=True forces verbose=False regardless of verbose param."""
        r = Runner.__new__(Runner)
        r.response = "y"
        r.cooldown = 0.5
        r.verbose = False
        r.delay = 0.0
        r.profile = None
        r._log_fh = None
        r._response_count = 0
        r._start_time = None
        r._last_response_time = 0.0
        r._last_match_time = 0.0
        r._last_user_input = 0.0
        r._pid = 1
        # quiet mode should force verbose off
        r2 = Runner(response="y", verbose=True, quiet=True)
        assert r2.verbose is False

    def test_runner_quiet_false_preserves_verbose(self):
        r = Runner(response="y", verbose=True, quiet=False)
        assert r.verbose is True

    def test_cli_quiet_flag_via_run(self):
        """--quiet in 'run' mode is parsed without error."""
        import subprocess as _sp
        result = _sp.run(
            [sys.executable, "-m", "auto_yes", "run", "--quiet", "--help"],
            capture_output=True, text=True, timeout=5
        )
        # Should not crash (--help exits 0 or shows help text)
        # The important thing is --quiet is not "unrecognized"
        assert "unrecognized" not in result.stderr


# ==================================================================
# 6. Runner stats tracking
# ==================================================================


class TestRunnerStats:
    def test_response_count_starts_at_zero(self):
        r = Runner(response="y")
        assert r._response_count == 0

    def test_start_time_initially_none(self):
        r = Runner(response="y")
        assert r._start_time is None

    def test_pid_property(self):
        import os
        r = Runner(response="y")
        assert r.pid == os.getpid()

    @pytest.mark.skipif(sys.platform == "win32", reason="pty not available on Windows")
    def test_response_count_increments(self):
        """_response_count increments when _send_response_unix is called."""
        import os
        import pty
        r = Runner(response="y", verbose=False)
        master_fd, slave_fd = pty.openpty()
        try:
            initial = r._response_count
            r._send_response_unix(master_fd, slave_fd, "y", "test-pattern")
            assert r._response_count == initial + 1
            r._send_response_unix(master_fd, slave_fd, "y", "test-pattern")
            assert r._response_count == initial + 2
        finally:
            os.close(master_fd)
            os.close(slave_fd)


# ==================================================================
# 7. pause / continue / ls commands
# ==================================================================


def test_ls_no_sessions(capsys):
    with patch("auto_yes.cli._cfg.list_sessions", return_value=[]):
        _handle_ls()
    assert "no running" in capsys.readouterr().out


def test_ls_shows_sessions(capsys):
    fake = [(999, {"profile": "claude", "command": "claude fix", "started": time.time()}, False)]
    with patch("auto_yes.cli._cfg.list_sessions", return_value=fake):
        _handle_ls()
    out = capsys.readouterr().out
    assert "999" in out
    assert "claude" in out
    assert "active" in out


def test_pause_all(capsys):
    fake = [(1, {}, False), (2, {}, False)]
    with patch("auto_yes.cli._cfg.list_sessions", return_value=fake):
        with patch("auto_yes.cli._cfg.set_paused") as mock_set:
            _handle_pause(["all"])
            assert mock_set.call_count == 2
    assert "paused" in capsys.readouterr().out


def test_continue_all(capsys):
    fake = [(1, {}, True), (2, {}, True)]
    with patch("auto_yes.cli._cfg.list_sessions", return_value=fake):
        with patch("auto_yes.cli._cfg.set_paused") as mock_set:
            _handle_continue(["all"])
            assert mock_set.call_count == 2
    assert "resumed" in capsys.readouterr().out


def test_status_inactive(capsys):
    with patch("auto_yes.cli._is_active", return_value=False):
        with patch("auto_yes.cli._cfg.list_sessions", return_value=[]):
            _handle_status()
    out = capsys.readouterr().out
    assert "inactive" in out


def test_status_active(capsys):
    with patch("auto_yes.cli._is_active", return_value=True):
        with patch("auto_yes.cli._cfg.list_sessions", return_value=[]):
            _handle_status()
    out = capsys.readouterr().out
    assert "active" in out


# ==================================================================
# 8. main() dispatch — unknown command
# ==================================================================


def test_main_unknown_command_exits(capsys):
    import pytest
    with pytest.raises(SystemExit) as exc:
        main(["definitely-not-a-command"])
    assert exc.value.code == 1
    assert "unknown command" in capsys.readouterr().err


def test_main_shell_dispatches_to_on():
    with patch("auto_yes.cli._handle_on") as mock_on:
        try:
            main(["shell"])
        except SystemExit:
            pass
    mock_on.assert_called_once_with([])


def test_main_toggle_dispatches():
    with patch("auto_yes.cli._handle_toggle") as mock_toggle:
        try:
            main(["toggle", "all"])
        except SystemExit:
            pass
    mock_toggle.assert_called_once_with(["all"])
