"""Tests for db.py — SQLite database layer with FSRS integration."""

import os
import sys
import tempfile
from pathlib import Path
from unittest.mock import patch

import pytest

# Add project root to path
sys.path.insert(0, str(Path(__file__).parent.parent))

import fsrs


@pytest.fixture(autouse=True)
def temp_db(tmp_path):
    """Use a temporary database for each test."""
    import db as db_mod

    db_mod._conn = None
    db_mod.DB_PATH = tmp_path / "test.db"
    db_mod.init_db()
    yield db_mod
    db_mod.close()


def test_init_db_creates_tables(temp_db):
    """init_db should create all required tables."""
    conn = temp_db.get_connection()
    tables = conn.execute(
        "SELECT name FROM sqlite_master WHERE type='table'"
    ).fetchall()
    table_names = {row["name"] for row in tables}
    assert "word_progress" in table_names
    assert "quiz_sessions" in table_names
    assert "essays" in table_names
    assert "tutor_sessions" in table_names


def test_get_word_progress_nonexistent(temp_db):
    """Should return None for a word that hasn't been reviewed."""
    assert temp_db.get_word_progress("nonexistent") is None


def test_update_and_get_word_progress(temp_db):
    """update_word_progress should create and update progress."""
    card = temp_db.update_word_progress("verb_go", fsrs.Rating.Good)
    assert card is not None
    assert card.stability is not None

    progress = temp_db.get_word_progress("verb_go")
    assert progress is not None
    assert progress["word_id"] == "verb_go"
    assert progress["reps"] == 1
    assert progress["fsrs_state"] is not None


def test_update_word_progress_increments_reps(temp_db):
    """Reviewing the same word multiple times should increment reps."""
    temp_db.update_word_progress("verb_go", fsrs.Rating.Good)
    temp_db.update_word_progress("verb_go", fsrs.Rating.Easy)
    progress = temp_db.get_word_progress("verb_go")
    assert progress["reps"] == 2


def test_get_due_words(temp_db):
    """get_due_words should return words that are due for review."""
    # A newly reviewed word with Rating.Again should be due soon
    temp_db.update_word_progress("verb_go", fsrs.Rating.Again)
    # An easy word should have a later due date
    temp_db.update_word_progress("verb_eat", fsrs.Rating.Easy)

    # Due words depend on timing; at minimum both should be in the system
    all_progress = temp_db.get_connection().execute(
        "SELECT word_id FROM word_progress"
    ).fetchall()
    assert len(all_progress) == 2


def test_get_word_counts(temp_db):
    """get_word_counts should return correct counts."""
    counts = temp_db.get_word_counts(total_vocab_size=100)
    assert counts["total"] == 100
    assert counts["seen"] == 0
    assert counts["mastered"] == 0
    assert counts["due"] == 0

    temp_db.update_word_progress("verb_go", fsrs.Rating.Good)
    counts = temp_db.get_word_counts(total_vocab_size=100)
    assert counts["seen"] == 1


def test_record_quiz_session(temp_db):
    """record_quiz_session should insert a quiz record."""
    temp_db.record_quiz_session("Common verbs", 10, 7, 120)
    rows = temp_db.get_connection().execute(
        "SELECT * FROM quiz_sessions"
    ).fetchall()
    assert len(rows) == 1
    assert rows[0]["correct"] == 7
    assert rows[0]["total_questions"] == 10


def test_save_essay(temp_db):
    """save_essay should store the essay and feedback."""
    temp_db.save_essay("متن آزمایشی", "B1", "Good effort!", "Identity and culture")
    essays = temp_db.get_recent_essays()
    assert len(essays) == 1
    assert essays[0]["grade"] == "B1"


def test_save_tutor_session(temp_db):
    """save_tutor_session should store the conversation."""
    messages = [
        {"role": "user", "content": "سلام"},
        {"role": "assistant", "content": "سلام! حالت چطوره؟"},
    ]
    temp_db.save_tutor_session("Identity and culture", messages, 300)
    rows = temp_db.get_connection().execute(
        "SELECT * FROM tutor_sessions"
    ).fetchall()
    assert len(rows) == 1
    assert rows[0]["theme"] == "Identity and culture"


def test_get_stats(temp_db):
    """get_stats should return aggregated stats."""
    stats = temp_db.get_stats()
    assert stats["total_reviews"] == 0
    assert stats["total_quizzes"] == 0
    assert stats["streak"] == 0
    assert isinstance(stats["recent_quizzes"], list)


def test_close_and_reopen(temp_db):
    """Closing and reopening should preserve data."""
    temp_db.update_word_progress("verb_go", fsrs.Rating.Good)
    db_path = temp_db.DB_PATH

    temp_db.close()

    # Reopen
    temp_db._conn = None
    temp_db.DB_PATH = db_path
    temp_db.init_db()

    progress = temp_db.get_word_progress("verb_go")
    assert progress is not None
    assert progress["reps"] == 1
