<?php
// ── Timezone — MUST be set first (fixes password reset expiry bug) ──
date_default_timezone_set('Asia/Colombo');


define('DB_HOST', 'localhost');
define('DB_USER', 'edurnxco_lms');
define('DB_PASS', 'Sasindu.0918@');
define('DB_NAME', 'edurnxco_studytrack');

define('SITE_NAME', 'StudyTrack');
define('SITE_URL', 'https://studytrack.edurx.icu/studytrack');
define('APP_URL',  'https://studytrack.edurx.icu/studytrack'); // alias for functions.php


// AI Study Tips - Anthropic API
define('GROQ_API_KEY', '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');
define('OPENAI_API_KEY', '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');

// Session lifetime (7 days)
define('SESSION_LIFETIME', 604800);

// Brevo (Sendinblue) SMTP settings via PHPMailer
define('SMTP_HOST', 'smtp-relay.brevo.com');
define('SMTP_PORT', 587);
define('SMTP_USER', 'a2ac10001@smtp-brevo.com');
define('SMTP_PASS', 'xsmtpsib-3ff1c786f9adf7935a82bf3c9006512077ef37a58b55b81316eec83bcd32b14a-YYZOz4y7WLj7YmWN');
define('SMTP_FROM', 'edurx@edurx.icu');
define('SMTP_FROM_NAME', 'StudyTrack');

// Brevo — Second Account (නව notifications)
define('SMTP_HOST2',      'smtp-relay.brevo.com');
define('SMTP_PORT2',      587);
define('SMTP_USER2',      'a47641001@smtp-brevo.com');
define('SMTP_PASS2',      'xsmtpsib-6667abe7a360893cea2d991c1f0c0786e6908e9f24d5ababfa87d5421d7060d2-mwqfsath9B8VUuL5');
define('SMTP_FROM2',      'edurx@edurx.icu');
define('SMTP_FROM_NAME2', 'StudyTrack');

// Mail aliases used by functions.php sendEmail()
define('MAIL_HOST',       SMTP_HOST);
define('MAIL_PORT',       SMTP_PORT);
define('MAIL_USERNAME',   SMTP_USER);
define('MAIL_PASSWORD',   SMTP_PASS);
define('MAIL_FROM_EMAIL', SMTP_FROM);
define('MAIL_FROM_NAME',  SMTP_FROM_NAME);

define('OTP_EXPIRY_MINUTES', 10);
define('RESET_EXPIRY_HOURS', 1);

// ── Google OAuth 2.0 Credentials ──────────────────────────────────
// Get these from: https://console.cloud.google.com → APIs & Services → Credentials
define('GOOGLE_CLIENT_ID',     '282195289868-grd5c91o5h6sig4nd6nu0kc5bsst81jt.apps.googleusercontent.com');      // e.g. 123456789-abc.apps.googleusercontent.com
define('GOOGLE_CLIENT_SECRET', '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');  // e.g. GOCSPX-xxxxxxxxxxxxxxxx
define('GOOGLE_REDIRECT_URI',  SITE_URL . '/google-auth.php'); // Must match Google Console exactly



// ── Facebook OAuth Credentials ─────────────────────────────────────
// Get these from: https://developers.facebook.com → Your App → Settings → Basic
define('FB_APP_ID',       '1969909801074008');       // e.g. 1234567890123456
define('FB_APP_SECRET',   'e5298305ded81374bd6ada4abf7f776d');   // e.g. abc123def456...
define('FB_REDIRECT_URI', SITE_URL . '/fb-auth.php');    // Must match Facebook App Dashboard exactly


// ── YouTube Data API v3 Key (used by music.php — search + embeds) ──
// Get this from: https://console.cloud.google.com → APIs & Services → Credentials
// → Create Credentials → API key, then enable "YouTube Data API v3" for the project.
// (API key only — no OAuth/redirect URI needed for public search & embeds)
define('YOUTUBE_API_KEY', 'AIzaSyCO8VJL81mePv5QFQvobc2vNiIV064RYUI');   // e.g. AIzaSyD-XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

// ── Web Push VAPID Keys ────────────────────────────────────────────
// Generated for studytrack.edurx.icu
define('VAPID_PUBLIC_KEY',  'BH-w1I5264Gix5czNGwQ8mygYpJ8qbmGfopwXXzy5BFugsFSJx_isPwiqt8_3l43y8qM9ubf2fpCPK4pzXbfdGw');
define('VAPID_PRIVATE_KEY', 'rmeXBXzbWklNbpPdTqml_gRcWJ4O3A0GHIKQpE-VEVE');
define('VAPID_SUBJECT',     'mailto:edurx@edurx.icu');

// ── Cron security key (for push-send.php?cron_key=xxx) ────────────
define('CRON_KEY', '11bb27b6dabd387e25c368a8483d26e9ed842561000f254284ac68ad0be426e6');

// ── PayHere Payment Gateway (Pro subscriptions) ─────────────────────
// Get these from: https://www.payhere.lk → Merchant Dashboard → Integrations
// Use the SANDBOX merchant id/secret while testing (sandbox.payhere.lk account),
// then switch PAYHERE_MODE to 'live' and swap in your live merchant id/secret.
define('PAYHERE_MODE', 'sandbox'); // 'sandbox' or 'live'
define('PAYHERE_MERCHANT_ID', '1XXXXX');            // TODO: replace with your Merchant ID
define('PAYHERE_MERCHANT_SECRET', 'YOUR_MERCHANT_SECRET'); // TODO: replace with your Merchant Secret
define('PAYHERE_CHECKOUT_URL', PAYHERE_MODE === 'live'
    ? 'https://www.payhere.lk/pay/checkout'
    : 'https://sandbox.payhere.lk/pay/checkout');

// ── Pro plan pricing (fallback if not present in site_settings table) ──
define('PRO_PRICE_MONTHLY_DEFAULT', 500);   // LKR
define('PRO_PRICE_YEARLY_DEFAULT', 5000);   // LKR
define('FREE_AI_DAILY_LIMIT_DEFAULT', 3);   // free AI calls/day (ai-tips + ai-analysis combined)
define('FREE_SUBJECT_LIMIT_DEFAULT', 5);    // max subjects a free user can create
define('FREE_MUSIC_SEARCH_DAILY_LIMIT_DEFAULT', 10); // free YouTube music searches/day

// ── Remember-me cookie name (separate from PHP session cookie) ──
define('REMEMBER_COOKIE', 'st_remember');

define('BOT_TOKEN',  '8600643569:AAHquV7kNofsBeLCBAgyiyCgmHlumJwYbXw');   // BotFather ගෙ token
define('BOT_SECRET', 'abc123');  // API secure කරන්න

if (session_status() === PHP_SESSION_NONE) {
    ini_set('session.gc_maxlifetime', SESSION_LIFETIME);
    session_set_cookie_params([
        'lifetime' => SESSION_LIFETIME,
        'path'     => '/',
        'secure'   => true,
        'httponly' => true,
        'samesite' => 'Lax'
    ]);
    session_start();
}

// ── PDO connection (used by register/login/forgot-password pages) ──
$pdo = null;
try {
    $pdo = new PDO("mysql:host=".DB_HOST.";dbname=".DB_NAME.";charset=utf8mb4", DB_USER, DB_PASS, [
        PDO::ATTR_ERRMODE            => PDO::ERRMODE_EXCEPTION,
        PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
        PDO::ATTR_EMULATE_PREPARES   => false,
    ]);
    // Sync MySQL session timezone with PHP timezone
    $pdo->exec("SET time_zone = '+05:30'");
} catch(PDOException $e) {
    header('Content-Type: application/json');
    die(json_encode(['success'=>false,'message'=>'Database connection failed. Check config.php credentials.']));
}

// ── MySQLi connection + getDB() used by functions.php & student pages ──
$_mysqli_instance = null;
function getDB() {
    global $_mysqli_instance;
    if ($_mysqli_instance === null) {
        $_mysqli_instance = new mysqli(DB_HOST, DB_USER, DB_PASS, DB_NAME);
        if ($_mysqli_instance->connect_error) {
            header('Content-Type: application/json');
            die(json_encode(['success'=>false,'message'=>'Database connection failed: '.$_mysqli_instance->connect_error]));
        }
        $_mysqli_instance->set_charset('utf8mb4');
    }
    return $_mysqli_instance;
}

// ── Auth helpers (PDO-based for register/login pages) ──

/**
 * Save a 7-day remember-me token to the database and set a cookie.
 * Call this right after setting $_SESSION['user_id'] on login.
 */
function createDbSession($userId) {
    global $pdo;
    // Generate a cryptographically random 32-byte token → 64 hex chars
    $token     = bin2hex(random_bytes(32));
    $expiresAt = date('Y-m-d H:i:s', time() + SESSION_LIFETIME);
    $ip        = $_SERVER['REMOTE_ADDR'] ?? null;
    $ua        = isset($_SERVER['HTTP_USER_AGENT']) ? substr($_SERVER['HTTP_USER_AGENT'], 0, 512) : null;

    // Clean up expired sessions for this user first
    $pdo->prepare("DELETE FROM user_sessions WHERE user_id=? AND expires_at < NOW()")
        ->execute([$userId]);

    // Insert new session row
    $pdo->prepare(
        "INSERT INTO user_sessions (user_id, token, ip_address, user_agent, expires_at)
         VALUES (?, ?, ?, ?, ?)"
    )->execute([$userId, $token, $ip, $ua, $expiresAt]);

    // Store token in session so isLoggedIn() can validate it against DB
    $_SESSION['db_token']       = $token;
    $_SESSION['_token_checked'] = time();

    // Set a long-lived HttpOnly cookie with the token
    setcookie(REMEMBER_COOKIE, $token, [
        'expires'  => time() + SESSION_LIFETIME,
        'path'     => '/',
        'secure'   => true,
        'httponly' => true,
        'samesite' => 'Lax'
    ]);
}

/**
 * Check the remember-me cookie against the database.
 * If valid, restore the PHP session automatically.
 * Returns true if session was restored, false otherwise.
 */
function restoreDbSession() {
    global $pdo;
    if (isset($_COOKIE[REMEMBER_COOKIE])) {
        $token = $_COOKIE[REMEMBER_COOKIE];
        $stmt  = $pdo->prepare(
            "SELECT s.user_id, u.name, u.email
             FROM user_sessions s
             JOIN users u ON u.id = s.user_id
             WHERE s.token = ?
               AND s.expires_at > NOW()
               AND u.is_disabled = 0"
        );
        $stmt->execute([$token]);
        $row = $stmt->fetch();
        if ($row) {
            // Valid DB session — restore PHP session
            session_regenerate_id(true);
            $_SESSION['user_id']    = $row['user_id'];
            $_SESSION['user_name']  = $row['name'];
            $_SESSION['user_email'] = $row['email'];
            $_SESSION['login_time']      = time();
            $_SESSION['db_token']         = $token;
            $_SESSION['_token_checked']   = time();

            // Slide expiry: update expires_at + refresh cookie
            $newExpires = date('Y-m-d H:i:s', time() + SESSION_LIFETIME);
            $pdo->prepare("UPDATE user_sessions SET expires_at=? WHERE token=?")
                ->execute([$newExpires, $token]);
            setcookie(REMEMBER_COOKIE, $token, [
                'expires'  => time() + SESSION_LIFETIME,
                'path'     => '/',
                'secure'   => true,
                'httponly' => true,
                'samesite' => 'Lax'
            ]);
            return true;
        }
        // Invalid/expired token — delete cookie and destroy session (forced logout from other device)
        setcookie(REMEMBER_COOKIE, '', ['expires' => time() - 3600, 'path' => '/']);
        session_unset();
        session_destroy();
    }
    return false;
}

/**
 * Delete the current user's DB session row and clear the cookie.
 */
function destroyDbSession() {
    global $pdo;
    if (isset($_COOKIE[REMEMBER_COOKIE])) {
        $pdo->prepare("DELETE FROM user_sessions WHERE token=?")
            ->execute([$_COOKIE[REMEMBER_COOKIE]]);
        setcookie(REMEMBER_COOKIE, '', ['expires' => time() - 3600, 'path' => '/']);
    }
}

/**
 * Check if the user is logged in.
 * Always re-validates the DB token so a new login on another device
 * immediately invalidates this session even if $_SESSION is still set.
 */
function isLoggedIn() {
    global $pdo;

    if (isset($_SESSION['user_id'], $_SESSION['db_token'])) {
        // Skip DB hit if checked within last 30 seconds (performance)
        $lastCheck = $_SESSION['_token_checked'] ?? 0;
        if (time() - $lastCheck < 30) {
            return true;
        }
        // Re-validate token against DB
        try {
            $stmt = $pdo->prepare(
                "SELECT id FROM user_sessions WHERE user_id=? AND token=? AND expires_at > NOW()"
            );
            $stmt->execute([$_SESSION['user_id'], $_SESSION['db_token']]);
            if ($stmt->fetch()) {
                $_SESSION['_token_checked'] = time();
                return true;
            }
        } catch (Exception $e) { return false; }
        // Token gone from DB — another device logged in
        session_unset();
        session_destroy();
        setcookie(REMEMBER_COOKIE, '', ['expires' => time() - 3600, 'path' => '/']);
        return false;
    }

    // No valid session — try remember-me cookie
    return restoreDbSession();
}

function requireLogin() {
    global $pdo;

    // ── Step 1: Must have a user_id in session ────────────────────────
    if (!isset($_SESSION['user_id']) || empty($_SESSION['user_id'])) {
        if (!restoreDbSession()) {
            header('Location: ' . SITE_URL . '/login.php');
            exit;
        }
    }

    // ── Step 2: Validate DB session every 30 seconds ─────────────────
    $lastCheck = $_SESSION['_token_checked'] ?? 0;
    if (time() - $lastCheck >= 30) {
        if (!empty($_SESSION['db_token'])) {
            $stmt = $pdo->prepare(
                "SELECT id FROM user_sessions WHERE user_id=? AND token=? AND expires_at > NOW()"
            );
            $stmt->execute([$_SESSION['user_id'], $_SESSION['db_token']]);
            if ($stmt->fetch()) {
                $_SESSION['_token_checked'] = time();
            } else {
                // This specific session token is gone (manual logout / expired)
                session_unset();
                session_destroy();
                setcookie(REMEMBER_COOKIE, '', ['expires' => time() - 3600, 'path' => '/']);
                header('Location: ' . SITE_URL . '/login.php');
                exit;
            }
        } else {
            // No db_token yet (old session) — just mark as checked
            $_SESSION['_token_checked'] = time();
        }
    }

    // ── Step 3: Check if user has been disabled by admin (cached 10s) ─
    if (!isset($_SESSION['_disabled_checked']) || $_SESSION['_disabled_checked'] < time() - 10) {
        $chk = $pdo->prepare("SELECT is_disabled FROM users WHERE id=?");
        $chk->execute([$_SESSION['user_id']]);
        $row = $chk->fetch();
        $_SESSION['_disabled_checked'] = time();
        if ($row && $row['is_disabled']) {
            $_SESSION['user_disabled'] = true;
        } else {
            $_SESSION['user_disabled'] = false;
        }
    }

    // ── Step 4: Check for active warnings (cached 30s) ────────────────
    if (!isset($_SESSION['_warn_checked']) || $_SESSION['_warn_checked'] < time() - 30) {
        $_SESSION['_warn_checked'] = time();
        try {
            $wChk = $pdo->prepare(
                "SELECT id, message, expires_at FROM user_warnings
                 WHERE user_id = ? AND dismissed = 0 AND expires_at > NOW()
                 ORDER BY created_at DESC LIMIT 1"
            );
            $wChk->execute([$_SESSION['user_id']]);
            $wRow = $wChk->fetch();
            if ($wRow) {
                $_SESSION['user_warning']            = $wRow['message'];
                $_SESSION['user_warning_id']         = $wRow['id'];
                $_SESSION['user_warning_expires']    = $wRow['expires_at'];
            } else {
                $_SESSION['user_warning']            = null;
                $_SESSION['user_warning_id']         = null;
                $_SESSION['user_warning_expires']    = null;
            }
        } catch (Exception $e) {
            $_SESSION['user_warning'] = null;
        }
    }
}
function isAdminLoggedIn() {
    return isset($_SESSION['admin_id']) && !empty($_SESSION['admin_id']);
}

function requireAdmin() {
    global $pdo;
    if (!isAdminLoggedIn()) {
        header('Location: ' . SITE_URL . '/admin/login.php');
        exit;
    }

    // Ping DB every 60s — update is_online + last_active_at + current page
    $lastPing = $_SESSION['admin_last_ping'] ?? 0;
    if (time() - $lastPing >= 60) {
        try {
            $currentPage = basename($_SERVER['PHP_SELF'] ?? 'unknown');
            $pdo->prepare("
                UPDATE admins
                SET is_online      = 1,
                    last_active_at = NOW(),
                    current_page   = ?
                WHERE id = ?
            ")->execute([$currentPage, $_SESSION['admin_id']]);
        } catch (Exception $e) {}
        $_SESSION['admin_last_ping'] = time();
    }
}
function sanitize($v) { return htmlspecialchars(strip_tags(trim($v)), ENT_QUOTES, 'UTF-8'); }
function jsonResponse($data) { header('Content-Type: application/json'); echo json_encode($data); exit; }
// ── Review Popup Dismiss Handler ─────────────────────────────
// Handles AJAX dismiss so the popup won't re-show until admin re-triggers it
if (
    isset($_SERVER['HTTP_X_REQUESTED_WITH']) &&
    $_SERVER['REQUEST_METHOD'] === 'POST' &&
    ($_POST['action'] ?? '') === 'dismiss_review_popup' &&
    isset($_SESSION['user_id'])
) {
    $_SESSION['review_popup_dismissed'] = time();
    header('Content-Type: application/json');
    echo json_encode(['success' => true]);
    exit;
}