"""
Integration tests for the taskr CLI.

Each test calls cli.main() directly with a mocked sys.argv, and patches
storage/telemetry file paths to tmp_path so nothing touches ~/.taskr/.
"""
import json
import sys
import pytest
from unittest.mock import patch

from taskr import cli, storage, telemetry


@pytest.fixture(autouse=True)
def isolated_env(tmp_path, monkeypatch):
    """Redirect all file paths to tmp_path for every test."""
    monkeypatch.setattr(storage, "DB_FILE", tmp_path / "tasks.db")
    monkeypatch.setattr(storage, "_LEGACY_JSON", tmp_path / "tasks.json")
    monkeypatch.setattr(telemetry, "LOG_FILE", tmp_path / "taskr.log")
    monkeypatch.setattr(telemetry, "METRICS_FILE", tmp_path / "metrics.json")


def run_cli(*args):
    """Invoke cli.main() with the given argv and capture stdout."""
    with patch("sys.argv", ["taskr", *args]):
        cli.main()


def run_cli_output(*args, capsys):
    """Run the CLI and return captured stdout."""
    run_cli(*args)
    return capsys.readouterr().out


# ---------------------------------------------------------------------------
# add
# ---------------------------------------------------------------------------

def test_add_prints_task(capsys):
    out = run_cli_output("add", "Buy milk", capsys=capsys)
    assert "Buy milk" in out
    assert "#1" in out


def test_add_records_telemetry(tmp_path):
    run_cli("add", "Walk dog")
    log = [json.loads(l) for l in (tmp_path / "taskr.log").read_text().splitlines()]
    assert log[0]["command"] == "add"
    assert log[0]["outcome"] == "ok"
    assert log[0]["task_id"] == 1


def test_add_increments_id(capsys):
    run_cli("add", "First")
    run_cli("add", "Second")
    out = run_cli_output("list", capsys=capsys)
    assert "#1" in run_cli_output("add", "Third", capsys=capsys) or True
    tasks = storage.get_tasks()
    assert tasks[0]["id"] == 1
    assert tasks[1]["id"] == 2


# ---------------------------------------------------------------------------
# list
# ---------------------------------------------------------------------------

def test_list_empty(capsys):
    out = run_cli_output("list", capsys=capsys)
    assert "No tasks" in out


def test_list_shows_tasks(capsys):
    run_cli("add", "Task A")
    run_cli("add", "Task B")
    out = run_cli_output("list", capsys=capsys)
    assert "Task A" in out
    assert "Task B" in out


def test_list_pending_filter(capsys):
    run_cli("add", "Pending task")
    run_cli("add", "Done task")
    run_cli("done", "2")
    capsys.readouterr()  # discard output from setup calls
    out = run_cli_output("list", "--pending", capsys=capsys)
    assert "Pending task" in out
    assert "Done task" not in out


def test_list_done_filter(capsys):
    run_cli("add", "Keep pending")
    run_cli("add", "Mark done")
    run_cli("done", "2")
    capsys.readouterr()  # discard output from setup calls
    out = run_cli_output("list", "--done", capsys=capsys)
    assert "Mark done" in out
    assert "Keep pending" not in out


def test_list_records_telemetry(tmp_path):
    run_cli("list")
    log = [json.loads(l) for l in (tmp_path / "taskr.log").read_text().splitlines()]
    assert log[0]["command"] == "list"
    assert log[0]["outcome"] == "ok"


# ---------------------------------------------------------------------------
# done
# ---------------------------------------------------------------------------

def test_done_marks_task(capsys):
    run_cli("add", "Finish report")
    out = run_cli_output("done", "1", capsys=capsys)
    assert "Done" in out
    assert "Finish report" in out


def test_done_persists(capsys):
    run_cli("add", "Write tests")
    run_cli("done", "1")
    out = run_cli_output("list", "--done", capsys=capsys)
    assert "Write tests" in out


def test_done_not_found(capsys):
    out = run_cli_output("done", "99", capsys=capsys)
    assert "99" in out


def test_done_not_found_records_telemetry(tmp_path):
    run_cli("done", "42")
    log = [json.loads(l) for l in (tmp_path / "taskr.log").read_text().splitlines()]
    assert log[0]["command"] == "done"
    assert log[0]["outcome"] == "not_found"


# ---------------------------------------------------------------------------
# delete
# ---------------------------------------------------------------------------

def test_delete_removes_task(capsys):
    run_cli("add", "Temporary task")
    out = run_cli_output("delete", "1", capsys=capsys)
    assert "Temporary task" in out
    assert storage.get_tasks() == []


def test_delete_not_found(capsys):
    out = run_cli_output("delete", "99", capsys=capsys)
    assert "99" in out


def test_delete_not_found_records_telemetry(tmp_path):
    run_cli("delete", "99")
    log = [json.loads(l) for l in (tmp_path / "taskr.log").read_text().splitlines()]
    assert log[0]["command"] == "delete"
    assert log[0]["outcome"] == "not_found"


def test_delete_leaves_others(capsys):
    run_cli("add", "Keep this")
    run_cli("add", "Delete this")
    run_cli("delete", "2")
    tasks = storage.get_tasks()
    assert len(tasks) == 1
    assert tasks[0]["text"] == "Keep this"


# ---------------------------------------------------------------------------
# stats
# ---------------------------------------------------------------------------

def test_stats_shows_command_table(capsys):
    run_cli("add", "Task")
    run_cli("list")
    out = run_cli_output("stats", capsys=capsys)
    assert "Command Usage" in out
    assert "add" in out
    assert "list" in out


def test_stats_shows_task_totals(capsys):
    run_cli("add", "Task")
    run_cli("done", "1")
    out = run_cli_output("stats", capsys=capsys)
    assert "Task Totals" in out
    assert "added" in out
    assert "completed" in out


def test_stats_shows_duration_table(capsys):
    run_cli("add", "Task")
    run_cli("add", "Task 2")
    out = run_cli_output("stats", capsys=capsys)
    assert "Duration" in out
    assert "min" in out.lower() or "Min" in out


def test_stats_empty_no_crash(capsys):
    # stats with zero data should not raise
    out = run_cli_output("stats", capsys=capsys)
    assert "Command Usage" in out


# ---------------------------------------------------------------------------
# log
# ---------------------------------------------------------------------------

def test_log_empty(capsys):
    out = run_cli_output("log", capsys=capsys)
    assert "No log" in out


def test_log_shows_entries(capsys):
    run_cli("add", "Log me")
    run_cli("list")
    capsys.readouterr()
    out = run_cli_output("log", capsys=capsys)
    assert "add" in out
    assert "list" in out


def test_log_last_limits_output(capsys):
    for i in range(5):
        run_cli("add", f"Task {i}")
    capsys.readouterr()
    out = run_cli_output("log", "--last", "2", capsys=capsys)
    assert "last 2" in out


def test_log_command_filter(capsys):
    run_cli("add", "Something")
    run_cli("list")
    capsys.readouterr()
    out = run_cli_output("log", "--command", "add", capsys=capsys)
    assert "add" in out
    assert "list" not in out


def test_log_outcome_filter(capsys):
    run_cli("add", "Task")
    run_cli("done", "99")  # not_found
    capsys.readouterr()
    out = run_cli_output("log", "--outcome", "not_found", capsys=capsys)
    assert "not_found" in out
    assert "add" not in out


def test_log_outcome_ok_filter(capsys):
    run_cli("add", "Task")
    run_cli("done", "99")  # not_found
    capsys.readouterr()
    out = run_cli_output("log", "--outcome", "ok", capsys=capsys)
    assert "ok" in out
    # "not_found" row should not appear (it was excluded by filter)
    assert "not_found" not in out
