import sqlite3
from pathlib import Path
from unittest.mock import patch

import pytest


@pytest.fixture
def db_path(tmp_path):
    return tmp_path / "test.db"


@pytest.fixture
def make_orchestrator(db_path):
    """Factory that creates a TmuxOrchestrator with mocked tmux calls."""
    def _make():
        with patch("onako.tmux_orchestrator.TmuxOrchestrator._ensure_session"), \
             patch("onako.tmux_orchestrator.TmuxOrchestrator.rediscover_tasks"):
            from onako.tmux_orchestrator import TmuxOrchestrator
            orch = TmuxOrchestrator(session_name="test", db_path=db_path)
            return orch
    return _make


def test_events_table_created(make_orchestrator, db_path):
    """Events table should be created on init."""
    make_orchestrator()
    conn = sqlite3.connect(db_path)
    cursor = conn.execute("SELECT name FROM sqlite_master WHERE type='table' AND name='events'")
    assert cursor.fetchone() is not None
    conn.close()


def test_events_table_columns(make_orchestrator, db_path):
    """Events table should have correct columns."""
    make_orchestrator()
    conn = sqlite3.connect(db_path)
    cursor = conn.execute("PRAGMA table_info(events)")
    columns = {row[1] for row in cursor.fetchall()}
    assert columns == {"id", "event_type", "task_id", "timestamp", "metadata"}
    conn.close()


def test_backfill_creates_events_from_existing_tasks(db_path, make_orchestrator):
    """Backfill should create events from pre-existing tasks."""
    # Pre-populate tasks table
    conn = sqlite3.connect(db_path)
    conn.execute("""
        CREATE TABLE IF NOT EXISTS tasks (
            id TEXT PRIMARY KEY, prompt TEXT, status TEXT, started_at TEXT,
            origin TEXT DEFAULT 'managed', last_activity TEXT,
            claude_session_id TEXT, branch TEXT, worktree_path TEXT
        )
    """)
    conn.execute(
        "INSERT INTO tasks VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)",
        ("task-old1", "do stuff", "done", "2026-01-15T10:00:00+00:00", "managed",
         "2026-01-15T11:00:00+00:00", None, None, None),
    )
    conn.execute(
        "INSERT INTO tasks VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)",
        ("task-old2", "more stuff", "running", "2026-01-16T10:00:00+00:00", "managed",
         "2026-01-16T10:30:00+00:00", None, None, None),
    )
    conn.commit()
    conn.close()

    make_orchestrator()

    conn = sqlite3.connect(db_path)
    events = conn.execute("SELECT event_type, task_id, timestamp FROM events ORDER BY id").fetchall()
    conn.close()

    # task-old1: should have task_created + task_completed
    # task-old2: should have task_created only (still running)
    created = [e for e in events if e[0] == "task_created"]
    completed = [e for e in events if e[0] == "task_completed"]
    assert len(created) == 2
    assert len(completed) == 1
    assert completed[0][1] == "task-old1"


def test_backfill_skips_if_events_already_exist(db_path, make_orchestrator):
    """Backfill should not run if events table already has data."""
    # Pre-populate tasks and events
    conn = sqlite3.connect(db_path)
    conn.execute("""
        CREATE TABLE IF NOT EXISTS tasks (
            id TEXT PRIMARY KEY, prompt TEXT, status TEXT, started_at TEXT,
            origin TEXT DEFAULT 'managed', last_activity TEXT,
            claude_session_id TEXT, branch TEXT, worktree_path TEXT
        )
    """)
    conn.execute(
        "INSERT INTO tasks VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)",
        ("task-old1", "do stuff", "done", "2026-01-15T10:00:00+00:00", "managed",
         "2026-01-15T11:00:00+00:00", None, None, None),
    )
    conn.execute("""
        CREATE TABLE IF NOT EXISTS events (
            id INTEGER PRIMARY KEY AUTOINCREMENT,
            event_type TEXT NOT NULL, task_id TEXT,
            timestamp TEXT NOT NULL, metadata TEXT
        )
    """)
    conn.execute(
        "INSERT INTO events (event_type, task_id, timestamp) VALUES (?, ?, ?)",
        ("task_created", "task-old1", "2026-01-15T10:00:00+00:00"),
    )
    conn.commit()
    conn.close()

    make_orchestrator()

    conn = sqlite3.connect(db_path)
    count = conn.execute("SELECT COUNT(*) FROM events").fetchone()[0]
    conn.close()
    # Should still be 1, no duplicates from backfill
    assert count == 1


def test_create_task_logs_event(make_orchestrator, db_path):
    """Creating a task should log a task_created event."""
    orch = make_orchestrator()
    with patch.object(orch, "_run_tmux"):
        orch.create_task(command="echo hi", prompt="test prompt")
    conn = sqlite3.connect(db_path)
    events = conn.execute(
        "SELECT event_type, task_id FROM events WHERE event_type='task_created'"
    ).fetchall()
    conn.close()
    assert len(events) == 1
    assert events[0][1].startswith("task-")


def test_kill_task_logs_event(make_orchestrator, db_path):
    """Killing a task should log a task_killed event."""
    orch = make_orchestrator()
    with patch.object(orch, "_run_tmux"):
        task = orch.create_task(command="echo hi", prompt="test")
    with patch.object(orch, "_run_tmux"):
        orch.kill_task(task["id"])
    conn = sqlite3.connect(db_path)
    events = conn.execute(
        "SELECT event_type, task_id FROM events WHERE event_type='task_killed'"
    ).fetchall()
    conn.close()
    assert len(events) == 1
    assert events[0][1] == task["id"]


def test_send_message_logs_event(make_orchestrator, db_path):
    """Sending a message should log a message_sent event."""
    orch = make_orchestrator()
    with patch.object(orch, "_run_tmux"):
        task = orch.create_task(command="echo hi", prompt="test")
    with patch.object(orch, "_run_tmux"):
        orch.send_message(task["id"], "hello")
    conn = sqlite3.connect(db_path)
    events = conn.execute(
        "SELECT event_type, task_id FROM events WHERE event_type='message_sent'"
    ).fetchall()
    conn.close()
    assert len(events) == 1
    assert events[0][1] == task["id"]


def test_send_interrupt_logs_event(make_orchestrator, db_path):
    """Interrupting a task should log a task_interrupted event."""
    orch = make_orchestrator()
    with patch.object(orch, "_run_tmux"):
        task = orch.create_task(command="echo hi", prompt="test")
    with patch.object(orch, "_run_tmux"):
        orch.send_interrupt(task["id"])
    conn = sqlite3.connect(db_path)
    events = conn.execute(
        "SELECT event_type, task_id FROM events WHERE event_type='task_interrupted'"
    ).fetchall()
    conn.close()
    assert len(events) == 1


def test_resume_task_logs_event(make_orchestrator, db_path):
    """Resuming a task should log a task_resumed event."""
    orch = make_orchestrator()
    with patch.object(orch, "_run_tmux"):
        task = orch.create_task(command="echo hi", prompt="test", claude_session_id="fake-sid")
    # Mark task as done so it can be resumed
    orch.tasks[task["id"]]["status"] = "done"
    orch._save_task(orch.tasks[task["id"]])
    with patch.object(orch, "_run_tmux"):
        orch.resume_task(task["id"])
    conn = sqlite3.connect(db_path)
    events = conn.execute(
        "SELECT event_type, task_id FROM events WHERE event_type='task_resumed'"
    ).fetchall()
    conn.close()
    assert len(events) == 1


def test_task_completed_logged_on_status_change(make_orchestrator, db_path):
    """When _sync_task_status detects a task is done, it should log task_completed."""
    orch = make_orchestrator()
    with patch.object(orch, "_run_tmux"):
        task = orch.create_task(command="echo hi", prompt="test")
    # Simulate window disappearing (task completed)
    mock_result = type("R", (), {"stdout": "", "returncode": 0})()
    with patch.object(orch, "_run_tmux", return_value=mock_result):
        orch._sync_task_status()
    conn = sqlite3.connect(db_path)
    events = conn.execute(
        "SELECT event_type, task_id FROM events WHERE event_type='task_completed'"
    ).fetchall()
    conn.close()
    assert len(events) == 1
    assert events[0][1] == task["id"]
