from unittest.mock import patch, MagicMock

from click.testing import CliRunner
from onako.cli import main


def test_version():
    runner = CliRunner()
    result = runner.invoke(main, ["version"])
    assert result.exit_code == 0
    assert "onako" in result.output


def test_default_help():
    runner = CliRunner()
    result = runner.invoke(main, ["--help"])
    assert result.exit_code == 0
    assert "--session" in result.output
    assert "--host" in result.output
    assert "--port" in result.output


def test_serve_help():
    runner = CliRunner()
    result = runner.invoke(main, ["serve", "--help"])
    assert result.exit_code == 0
    assert "--host" in result.output
    assert "--port" in result.output
    assert "--session" in result.output
    assert "--dir" in result.output


def test_skip_permissions_flag_in_help():
    runner = CliRunner()
    result = runner.invoke(main, ["--help"])
    assert "--dangerously-skip-permissions" in result.output


def test_serve_skip_permissions_flag_in_help():
    runner = CliRunner()
    result = runner.invoke(main, ["serve", "--help"])
    assert "--dangerously-skip-permissions" in result.output


def test_task_help():
    runner = CliRunner()
    result = runner.invoke(main, ["task", "--help"])
    assert result.exit_code == 0
    assert "PROMPT" in result.output
    assert "--dir" in result.output
    assert "--dangerously-skip-permissions" in result.output
    assert "--branch" in result.output
    assert "--base-branch" in result.output


def test_task_requires_prompt():
    runner = CliRunner()
    result = runner.invoke(main, ["task"])
    assert result.exit_code != 0
    assert "Missing argument" in result.output


def test_task_creates_task_with_mock_orch():
    """Test that `onako task` calls the service and prints the task ID."""
    mock_create = MagicMock(return_value={"id": "task-test123", "status": "running"})

    with patch("onako.cli.subprocess") as mock_subprocess:
        # Make tmux session check pass (has-session returns 0)
        mock_subprocess.run.return_value = MagicMock(returncode=0, stdout="onako\n")
        with patch("onako.tmux_orchestrator.TmuxOrchestrator") as mock_orch_cls:
            with patch("onako.task_service.create_task", mock_create):
                runner = CliRunner()
                result = runner.invoke(main, ["task", "fix the bug"])

    assert result.exit_code == 0, f"CLI failed with: {result.output}"
    assert "task-test123" in result.output
    assert "fix the bug" in result.output


def test_clean_help():
    runner = CliRunner()
    result = runner.invoke(main, ["clean", "--help"])
    assert result.exit_code == 0
    assert "worktree" in result.output.lower()


def test_clean_removes_finished_worktrees(tmp_path):
    """Clean removes worktrees for done/hidden tasks."""
    import sqlite3

    db_path = tmp_path / "onako.db"
    conn = sqlite3.connect(db_path)
    conn.execute("""
        CREATE TABLE tasks (
            id TEXT PRIMARY KEY, prompt TEXT, status TEXT, started_at TEXT,
            origin TEXT, last_activity TEXT, claude_session_id TEXT,
            branch TEXT, worktree_path TEXT, last_output TEXT
        )
    """)
    # A done task with a worktree
    wt_dir = tmp_path / "repo--feat-done"
    wt_dir.mkdir()
    conn.execute(
        "INSERT INTO tasks VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
        ("task-done1", "prompt", "done", None, "managed", None, None, "feat/done", str(wt_dir), None),
    )
    # A running task with a worktree (should NOT be cleaned)
    wt_running = tmp_path / "repo--feat-running"
    wt_running.mkdir()
    conn.execute(
        "INSERT INTO tasks VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
        ("task-run1", "prompt", "running", None, "managed", None, None, "feat/running", str(wt_running), None),
    )
    conn.commit()
    conn.close()

    runner = CliRunner()
    with patch("onako.cli.ONAKO_DIR", tmp_path), \
         patch("onako.cli._clean_worktree") as mock_clean:
        result = runner.invoke(main, ["clean"])

    assert result.exit_code == 0
    # Should only clean the done task's worktree
    mock_clean.assert_called_once()
    assert "repo--feat-done" in mock_clean.call_args[0][0]


def test_clean_nothing_to_clean(tmp_path):
    """Clean prints message when no worktrees to clean."""
    import sqlite3

    db_path = tmp_path / "onako.db"
    conn = sqlite3.connect(db_path)
    conn.execute("""
        CREATE TABLE tasks (
            id TEXT PRIMARY KEY, prompt TEXT, status TEXT, started_at TEXT,
            origin TEXT, last_activity TEXT, claude_session_id TEXT,
            branch TEXT, worktree_path TEXT, last_output TEXT
        )
    """)
    conn.commit()
    conn.close()

    runner = CliRunner()
    with patch("onako.cli.ONAKO_DIR", tmp_path):
        result = runner.invoke(main, ["clean"])

    assert result.exit_code == 0
    assert "No worktrees to clean up" in result.output


def test_purge_removed():
    """The purge command should no longer exist."""
    runner = CliRunner()
    result = runner.invoke(main, ["purge"])
    assert result.exit_code != 0


def test_reset_help():
    runner = CliRunner()
    result = runner.invoke(main, ["reset", "--help"])
    assert result.exit_code == 0


def test_reset_stops_server_and_cleans_db(tmp_path):
    """Reset marks running tasks as done and removes all worktrees."""
    import sqlite3

    db_path = tmp_path / "onako.db"
    conn = sqlite3.connect(db_path)
    conn.execute("""
        CREATE TABLE tasks (
            id TEXT PRIMARY KEY, prompt TEXT, status TEXT, started_at TEXT,
            origin TEXT, last_activity TEXT, claude_session_id TEXT,
            branch TEXT, worktree_path TEXT, last_output TEXT
        )
    """)
    wt1 = tmp_path / "repo--feat-a"
    wt1.mkdir()
    wt2 = tmp_path / "repo--feat-b"
    wt2.mkdir()
    conn.execute(
        "INSERT INTO tasks VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
        ("task-1", "prompt", "running", None, "managed", None, None, "feat/a", str(wt1), None),
    )
    conn.execute(
        "INSERT INTO tasks VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
        ("task-2", "prompt", "done", None, "managed", None, None, "feat/b", str(wt2), None),
    )
    conn.commit()
    conn.close()

    # No PID file, no tmux session — just test DB + worktree cleanup
    pid_file = tmp_path / "onako.pid"

    runner = CliRunner()
    with patch("onako.cli.ONAKO_DIR", tmp_path), \
         patch("onako.cli.PID_FILE", pid_file), \
         patch("onako.cli.DEV_MARKER", tmp_path / "onako.dev"), \
         patch("onako.cli.subprocess") as mock_sub:
        mock_sub.run.return_value = MagicMock(returncode=1, stdout="", stderr="")
        with patch("onako.cli._clean_worktree") as mock_clean:
            result = runner.invoke(main, ["reset"])

    assert result.exit_code == 0
    # DB should have tasks marked as done
    conn = sqlite3.connect(db_path)
    statuses = conn.execute("SELECT status FROM tasks").fetchall()
    conn.close()
    assert all(s[0] == "done" for s in statuses)
    # Both worktrees should be cleaned (reset cleans ALL, not just finished)
    assert mock_clean.call_count == 2
