<?php
/**
 * Spaced-repetition scheduling for Study Log topics.
 *
 * Every time a student logs a study session they must say what they
 * studied (the "topic"). We use that text to build/advance a per-topic
 * review schedule using a classic expanding spaced-repetition interval
 * sequence, then surface anything that's due on the Study Log page and
 * as a "Reviews Due" summary on the Dashboard.
 */

// ── Self-migrating table (safe to call on every request) ──
function ensureTopicReviewsTable($pdo) {
    try {
        $pdo->exec("CREATE TABLE IF NOT EXISTS `topic_reviews` (
          `id` INT AUTO_INCREMENT PRIMARY KEY,
          `user_id` INT NOT NULL,
          `subject_id` INT NOT NULL,
          `topic` VARCHAR(255) NOT NULL,
          `topic_key` VARCHAR(255) NOT NULL,
          `stage` INT DEFAULT 0,
          `times_reviewed` INT DEFAULT 1,
          `last_studied_date` DATE NOT NULL,
          `next_review_date` DATE NOT NULL,
          `status` VARCHAR(20) NOT NULL DEFAULT 'active',
          `created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
          `updated_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
          UNIQUE KEY `uniq_user_subject_topic` (`user_id`,`subject_id`,`topic_key`),
          KEY `idx_due` (`user_id`,`status`,`next_review_date`)
        ) ENGINE=InnoDB;");
    } catch (Exception $e) {
        // non-fatal — page can still render without the widget
    }
}

// Days-until-next-review at each stage. Widely-used expanding
// spaced-repetition schedule (roughly: tomorrow, this week, ~2 weeks,
// ~1 month, ~1 month+ for anything already well retained).
function topicReviewIntervals() {
    return [1, 3, 7, 16, 35];
}

function topicKeyFor($topic) {
    return mb_strtolower(trim(substr($topic, 0, 255)));
}

/**
 * Called whenever a study session is saved with a topic/notes value.
 * Creates a new review schedule the first time a topic is studied, or
 * advances an existing one to the next interval (treats re-studying the
 * same topic as a natural "review").
 */
function scheduleTopicReview($pdo, $uid, $subjectId, $topic, $studiedDate) {
    $topic = trim($topic);
    if ($topic === '') return;
    try {
        $topicKey  = topicKeyFor($topic);
        $intervals = topicReviewIntervals();

        $stmt = $pdo->prepare("SELECT id, stage FROM topic_reviews WHERE user_id=? AND subject_id=? AND topic_key=?");
        $stmt->execute([$uid, $subjectId, $topicKey]);
        $row = $stmt->fetch();

        if ($row) {
            $stage    = min((int)$row['stage'] + 1, count($intervals) - 1);
            $nextDate = date('Y-m-d', strtotime($studiedDate . " +{$intervals[$stage]} days"));
            $pdo->prepare("UPDATE topic_reviews SET stage=?, times_reviewed=times_reviewed+1, last_studied_date=?, next_review_date=?, status='active' WHERE id=?")
                ->execute([$stage, $studiedDate, $nextDate, $row['id']]);
        } else {
            $nextDate = date('Y-m-d', strtotime($studiedDate . " +{$intervals[0]} days"));
            $pdo->prepare("INSERT INTO topic_reviews (user_id,subject_id,topic,topic_key,stage,times_reviewed,last_studied_date,next_review_date,status) VALUES (?,?,?,?,0,1,?,?,'active')")
                ->execute([$uid, $subjectId, substr($topic, 0, 255), $topicKey, $studiedDate, $nextDate]);
        }
    } catch (Exception $e) {
        // non-fatal — the study session itself is already saved either way
    }
}

/**
 * "Mark Reviewed" — advance a due topic to the next interval without
 * requiring a full study session log.
 */
function advanceTopicReview($pdo, $uid, $id) {
    try {
        $intervals = topicReviewIntervals();
        $stmt = $pdo->prepare("SELECT stage FROM topic_reviews WHERE id=? AND user_id=?");
        $stmt->execute([$id, $uid]);
        $row = $stmt->fetch();
        if (!$row) return false;

        $stage    = min((int)$row['stage'] + 1, count($intervals) - 1);
        $today    = date('Y-m-d');
        $nextDate = date('Y-m-d', strtotime("+{$intervals[$stage]} days"));
        $pdo->prepare("UPDATE topic_reviews SET stage=?, times_reviewed=times_reviewed+1, last_studied_date=?, next_review_date=?, status='active' WHERE id=?")
            ->execute([$stage, $today, $nextDate, $id]);
        return true;
    } catch (Exception $e) {
        return false;
    }
}

/** "I know this well" — stop reminding about a topic. */
function markTopicMastered($pdo, $uid, $id) {
    try {
        $pdo->prepare("UPDATE topic_reviews SET status='mastered' WHERE id=? AND user_id=?")->execute([$id, $uid]);
        return true;
    } catch (Exception $e) {
        return false;
    }
}

/** Count of topics due for review right now (used by dashboard summary). */
function countDueTopicReviews($pdo, $uid) {
    try {
        $stmt = $pdo->prepare("SELECT COUNT(*) FROM topic_reviews WHERE user_id=? AND status='active' AND next_review_date <= CURDATE()");
        $stmt->execute([$uid]);
        return (int)$stmt->fetchColumn();
    } catch (Exception $e) {
        return 0;
    }
}

/** Due (and optionally soon-due) topics, joined with subject info. */
function getDueTopicReviews($pdo, $uid, $limit = null) {
    try {
        $sql = "SELECT tr.*, s.name AS subject_name, s.color AS subject_color
                FROM topic_reviews tr JOIN subjects s ON tr.subject_id = s.id
                WHERE tr.user_id=? AND tr.status='active' AND tr.next_review_date <= CURDATE()
                ORDER BY tr.next_review_date ASC";
        if ($limit) $sql .= " LIMIT " . (int)$limit;
        $stmt = $pdo->prepare($sql);
        $stmt->execute([$uid]);
        return $stmt->fetchAll();
    } catch (Exception $e) {
        return [];
    }
}

function getUpcomingTopicReviews($pdo, $uid, $days = 3, $limit = 5) {
    try {
        $stmt = $pdo->prepare("SELECT tr.*, s.name AS subject_name, s.color AS subject_color
                FROM topic_reviews tr JOIN subjects s ON tr.subject_id = s.id
                WHERE tr.user_id=? AND tr.status='active'
                  AND tr.next_review_date > CURDATE() AND tr.next_review_date <= DATE_ADD(CURDATE(), INTERVAL ? DAY)
                ORDER BY tr.next_review_date ASC LIMIT ?");
        $stmt->bindValue(1, $uid, PDO::PARAM_INT);
        $stmt->bindValue(2, $days, PDO::PARAM_INT);
        $stmt->bindValue(3, $limit, PDO::PARAM_INT);
        $stmt->execute();
        return $stmt->fetchAll();
    } catch (Exception $e) {
        return [];
    }
}
