<?php
// ============================================================
// FONCTIONS GLOBALES — JeTeGageQue
// ============================================================

// --- VÉRIFICATIONS DE NIVEAU ---
function isPremium($user) {
    return isset($user['tier']) && in_array($user['tier'], ['premium', 'premium_plus', 'admin']);
}
function isPremiumPlus($user) {
    return isset($user['tier']) && in_array($user['tier'], ['premium_plus', 'admin']);
}
function isAdmin($user) {
    return (isset($user['admin']) && (int)$user['admin'] === 1)
        || (isset($user['tier']) && strtolower($user['tier']) === 'admin');
}
function isOracle($user, $circleId, $pdo) {
    $stmt = $pdo->prepare("SELECT oracle_id FROM circles WHERE id = ?");
    $stmt->execute([$circleId]);
    $circle = $stmt->fetch();
    return $circle && (int)$circle['oracle_id'] === (int)$user['id'];
}

// --- REDIRECTION SÉCURISÉE ---
function requireLogin() {
    if (!isset($_SESSION['user_id'])) {
        header("Location: index.php");
        exit;
    }
}
function requireAdmin($user) {
    if (!isAdmin($user)) {
        header("Location: index.php");
        exit;
    }
}

// --- CHARGER L'UTILISATEUR CONNECTÉ ---
function getConnectedUser($pdo) {
    if (!isset($_SESSION['user_id'])) return null;
    $stmt = $pdo->prepare("SELECT * FROM users WHERE id = ?");
    $stmt->execute([$_SESSION['user_id']]);
    $user = $stmt->fetch();
    if ($user) {
        // Mettre à jour last_activity
        $pdo->prepare("UPDATE users SET last_activity = NOW() WHERE id = ?")->execute([$user['id']]);
    }
    return $user ?: null;
}

// --- NOTIFICATIONS ---
function addWalletPoints($pdo, $userId, $amount, $type, $desc = '', $refId = null) {
    try {
        $pdo->prepare("UPDATE users SET wallet_points=wallet_points+? WHERE id=?")->execute([$amount, $userId]);
        $pdo->prepare("INSERT INTO wallet_transactions (user_id,amount,type,description,ref_id) VALUES (?,?,?,?,?)")
            ->execute([$userId, $amount, $type, $desc, $refId]);
        return true;
    } catch (Exception $e) { return false; }
}

function getWalletConfig($pdo, $key, $default = 0) {
    try {
        $s = $pdo->prepare("SELECT config_value FROM admin_config WHERE config_key=?");
        $s->execute([$key]);
        $v = $s->fetchColumn();
        return $v !== false ? $v : $default;
    } catch (Exception $e) { return $default; }
}

function addNotification($pdo, $userId, $message, $link = null) {
    $stmt = $pdo->prepare("INSERT INTO notifications (user_id, message, link) VALUES (?, ?, ?)");
    $stmt->execute([$userId, $message, $link]);
}

// --- COURRIEL ---
function notifyUser($to, $subject, $body) {
    $headers  = "From: JeTeGageQue <noreply@jetegageque.com>\r\n";
    $headers .= "Content-Type: text/html; charset=UTF-8\r\n";
    $headers .= "MIME-Version: 1.0\r\n";
    return mail($to, $subject, $body, $headers);
}

// --- BADGE DE STATUT ---
function getBetStatusBadge($status) {
    $status = strtolower($status);
    if ($status === 'won')     return '<span class="badge bg-success" style="font-size:0.55rem;">GAGNÉ</span>';
    if ($status === 'lost')    return '<span class="badge bg-danger"  style="font-size:0.55rem;">PERDU</span>';
    return '<span class="badge bg-warning text-dark" style="font-size:0.55rem;">EN COURS</span>';
}

// --- POINTS D'INTERACTION ---
function addInteractionPoints($pdo, $userId, $action) {
    // Valeurs configurables dans admin_config
    $defaults = [
        'chat'      => 1,
        'message'   => 10,
        'vote'      => 5,
        'login'     => 2,
        'bet_view'  => 1,
        'profile'   => 1,
    ];
    $stmt = $pdo->prepare("SELECT config_value FROM admin_config WHERE config_key = ?");
    $stmt->execute(['pts_' . $action]);
    $row = $stmt->fetch();
    $pts = $row ? (int)$row['config_value'] : ($defaults[$action] ?? 0);

    if ($pts > 0) {
        $pdo->prepare("UPDATE users SET interaction_points = interaction_points + ? WHERE id = ?")
            ->execute([$pts, $userId]);
    }
}

// --- ORACLE AI : phrase aléatoire ---
function getOraclePhrase($type = 'trash') {
    $phrases = [
        'win'  => [
            "L'Oracle a parlé : T'es une machine ! Les points sont à toi.",
            "Facile de même ? L'Oracle est impressionné.",
            "Victoire confirmée. Ton cercle devrait commencer à avoir peur.",
        ],
        'loss' => [
            "L'Oracle a tranché : C'est un échec monumental.",
            "Ayoye... l'Oracle a mal pour toi. Pari perdu.",
            "Triste verdict. On se relève et on recommence ?",
        ],
        'trash' => [
            "L'Oracle surveille le chat... Ça parle beaucoup, mais ça gage pas fort.",
            "Petit rappel : L'Oracle voit tout, même tes paris douteux.",
            "Hey ! L'Oracle trouve que ce cercle manque de piquant aujourd'hui.",
        ],
    ];
    $list = $phrases[$type] ?? $phrases['trash'];
    return $list[array_rand($list)];
}

// --- GÉNÉRER CODE UNIQUE GAGE (ex: 4T6G71) ---
function generateBetCode() {
    $chars = 'ABCDEFGHJKLMNPQRSTUVWXYZ23456789';
    $code = '';
    for ($i = 0; $i < 6; $i++) $code .= $chars[random_int(0, strlen($chars) - 1)];
    return $code;
}

// Charger la terminologie configurable
if (file_exists(__DIR__ . '/lang.php')) require_once __DIR__ . '/lang.php';

// ── Protection CSRF ───────────────────────────────────────────────
function csrf_token() {
    if (empty($_SESSION['csrf_token'])) {
        $_SESSION['csrf_token'] = bin2hex(random_bytes(32));
    }
    return $_SESSION['csrf_token'];
}

function csrf_field() {
    return '<input type="hidden" name="csrf_token" value="' . csrf_token() . '">';
}

function csrf_verify() {
    $token = $_POST['csrf_token'] ?? $_SERVER['HTTP_X_CSRF_TOKEN'] ?? '';
    if (!hash_equals($_SESSION['csrf_token'] ?? '', $token)) {
        http_response_code(403);
        die(json_encode(['error' => 'Token CSRF invalide. Rechargez la page.']));
    }
    return true;
}

// ── Protection brute force connexion ────────────────────────────
function getClientIp() {
    $ip = $_SERVER['REMOTE_ADDR'] ?? '0.0.0.0';
    if (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
        $ips = explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']);
        $ip = trim($ips[0]);
    }
    return filter_var($ip, FILTER_VALIDATE_IP) ? $ip : '0.0.0.0';
}

function checkLoginAttempts($pdo, $ip) {
    try {
        $pdo->exec("CREATE TABLE IF NOT EXISTS login_attempts (
            id INT AUTO_INCREMENT PRIMARY KEY,
            ip VARCHAR(45) NOT NULL,
            attempts INT DEFAULT 1,
            last_attempt TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
            locked_until DATETIME DEFAULT NULL,
            KEY idx_ip (ip)
        )");
        $stmt = $pdo->prepare("SELECT * FROM login_attempts WHERE ip=? LIMIT 1");
        $stmt->execute([$ip]);
        $row = $stmt->fetch();
        if ($row && $row['locked_until'] && strtotime($row['locked_until']) > time()) {
            $mins = ceil((strtotime($row['locked_until']) - time()) / 60);
            return "Trop de tentatives. Réessayez dans {$mins} minute(s).";
        }
    } catch (Exception $e) {}
    return null;
}

function recordFailedLogin($pdo, $ip) {
    try {
        $max = 5; $lockMins = 15;
        $stmt = $pdo->prepare("SELECT * FROM login_attempts WHERE ip=? LIMIT 1");
        $stmt->execute([$ip]);
        $row = $stmt->fetch();
        if ($row) {
            $attempts = $row['attempts'] + 1;
            $locked = $attempts >= $max ? date('Y-m-d H:i:s', strtotime("+{$lockMins} minutes")) : null;
            $pdo->prepare("UPDATE login_attempts SET attempts=?, locked_until=? WHERE ip=?")->execute([$attempts, $locked, $ip]);
        } else {
            $pdo->prepare("INSERT INTO login_attempts (ip, attempts) VALUES (?,1)")->execute([$ip]);
        }
    } catch (Exception $e) {}
}

function clearLoginAttempts($pdo, $ip) {
    try { $pdo->prepare("DELETE FROM login_attempts WHERE ip=?")->execute([$ip]); } catch(Exception $e){}
}

// ── Vérification et attribution des trophées ─────────────────────
function checkAndAwardTrophies($pdo, $userId) {
    try {
        $trophies = $pdo->query("SELECT * FROM trophy_levels")->fetchAll();
        $stats = $pdo->prepare("SELECT * FROM user_stats WHERE user_id=?");
        $stats->execute([$userId]); $st = $stats->fetch() ?: [];
        $user = $pdo->prepare("SELECT * FROM users WHERE id=?");
        $user->execute([$userId]); $u = $user->fetch() ?: [];

        foreach ($trophies as $tr) {
            // Déjà eu ?
            $chk = $pdo->prepare("SELECT id FROM user_trophies WHERE user_id=? AND trophy_id=?");
            $chk->execute([$userId, $tr['id']]);
            if ($chk->fetch()) continue;

            $give = false;
            switch ($tr['requirement_type']) {
                case 'win_count':
                    if (($st['won_bets'] ?? 0) >= $tr['requirement_value']) $give = true;
                    break;
                case 'win_percent':
                    $total = ($st['total_bets'] ?? 0);
                    if ($total > 0 && (($st['won_bets'] ?? 0) / $total * 100) >= $tr['requirement_value']) $give = true;
                    break;
                case 'interaction':
                    if (($u['interaction_points'] ?? 0) >= $tr['requirement_value']) $give = true;
                    break;
                case 'reliability':
                    $rs = $pdo->prepare("SELECT reliability_score FROM user_stats WHERE user_id=?");
                    $rs->execute([$userId]);
                    $score = (int)($rs->fetchColumn() ?? 100);
                    if ($score >= $tr['requirement_value']) $give = true;
                    break;
            }
            if ($give) {
                $pdo->prepare("INSERT IGNORE INTO user_trophies (user_id, trophy_id) VALUES (?,?)")->execute([$userId, $tr['id']]);
                addNotification($pdo, $userId, "🏆 Nouveau trophée débloqué : " . htmlspecialchars($tr['title']), "trophees.php");
            }
        }
    } catch (Exception $e) {}
}

// ── Vérification des droits par fonctionnalité ───────────────────
// Retourne true si le tier de l'user a accès à la fonctionnalité
// Les valeurs par défaut correspondent à la matrice dans admin_droits.php
function checkDroit($pdo, $tier, $featKey) {
    // Defaults par fonctionnalité et tier
    $defaults = [
        'dashboard'       => ['free'=>1,'premium'=>1,'premplus'=>1,'admin'=>1],
        'pastilles'       => ['free'=>0,'premium'=>1,'premplus'=>1,'admin'=>1],
        'create_bet'      => ['free'=>1,'premium'=>1,'premplus'=>1,'admin'=>1],
        'global_bet'      => ['free'=>1,'premium'=>1,'premplus'=>1,'admin'=>1],
        'wallet_bet'      => ['free'=>0,'premium'=>1,'premplus'=>1,'admin'=>1],
        'vote_bet'        => ['free'=>1,'premium'=>1,'premplus'=>1,'admin'=>1],
        'chat_send'       => ['free'=>1,'premium'=>1,'premplus'=>1,'admin'=>1],
        'chat_icons_free' => ['free'=>1,'premium'=>1,'premplus'=>1,'admin'=>1],
        'chat_icons_prem' => ['free'=>0,'premium'=>1,'premplus'=>1,'admin'=>1],
        'chat_icons_pp'   => ['free'=>0,'premium'=>0,'premplus'=>1,'admin'=>1],
        'chat_color'      => ['free'=>0,'premium'=>0,'premplus'=>1,'admin'=>1],
        'chat_photo'      => ['free'=>0,'premium'=>0,'premplus'=>1,'admin'=>1],
        'upload_proof'    => ['free'=>1,'premium'=>1,'premplus'=>1,'admin'=>1],
        'gallery'         => ['free'=>1,'premium'=>1,'premplus'=>1,'admin'=>1],
        'profile_custom'  => ['free'=>1,'premium'=>1,'premplus'=>1,'admin'=>1],
        'custom_theme'    => ['free'=>0,'premium'=>0,'premplus'=>1,'admin'=>1],
        'private_msg'     => ['free'=>1,'premium'=>1,'premplus'=>1,'admin'=>1],
        'friends'         => ['free'=>1,'premium'=>1,'premplus'=>1,'admin'=>1],
        'rate_user'       => ['free'=>1,'premium'=>1,'premplus'=>1,'admin'=>1],
        'wallet_access'   => ['free'=>1,'premium'=>1,'premplus'=>1,'admin'=>1],
        'wallet_daily'    => ['free'=>1,'premium'=>1,'premplus'=>1,'admin'=>1],
        'wallet_roll'     => ['free'=>1,'premium'=>1,'premplus'=>1,'admin'=>1],
        'wallet_shop'     => ['free'=>1,'premium'=>1,'premplus'=>1,'admin'=>1],
        'join_circle'     => ['free'=>1,'premium'=>1,'premplus'=>1,'admin'=>1],
        'create_circle'   => ['free'=>1,'premium'=>1,'premplus'=>1,'admin'=>1],
        'manage_circle'   => ['free'=>1,'premium'=>1,'premplus'=>1,'admin'=>1],
        'oracle_vote'     => ['free'=>1,'premium'=>1,'premplus'=>1,'admin'=>1],
        'oracle_judge'    => ['free'=>0,'premium'=>0,'premplus'=>0,'admin'=>1],
        'oracle_mail'     => ['free'=>0,'premium'=>0,'premplus'=>0,'admin'=>1],
        'circle_wall'     => ['free'=>1,'premium'=>1,'premplus'=>1,'admin'=>1],
        'admin_panel'     => ['free'=>0,'premium'=>0,'premplus'=>0,'admin'=>1],
    ];

    // Normaliser le tier
    $tierKey = match($tier ?? 'free') {
        'premium_plus' => 'premplus',
        'premium'      => 'premium',
        'admin'        => 'admin',
        default        => 'free',
    };

    // Admin a toujours accès
    if ($tierKey === 'admin') return true;

    // Lire depuis admin_config (priorité sur les defaults)
    $cfgKey = 'droit_' . $featKey . '_' . $tierKey;
    try {
        $stmt = $pdo->prepare("SELECT config_value FROM admin_config WHERE config_key=?");
        $stmt->execute([$cfgKey]);
        $val = $stmt->fetchColumn();
        if ($val !== false) return (bool)$val;
    } catch (Exception $e) {}

    // Fallback sur les defaults
    return (bool)($defaults[$featKey][$tierKey] ?? true);
}


// ── Filtre de mots interdits ──────────────────────────────────────
function _loadBadWords($pdo) {
    static $words = null;
    if ($words !== null) return $words;
    try {
        $pdo->exec("CREATE TABLE IF NOT EXISTS bad_words (
            id INT AUTO_INCREMENT PRIMARY KEY,
            word VARCHAR(100) NOT NULL,
            replacement VARCHAR(20) DEFAULT '***',
            active TINYINT(1) DEFAULT 1,
            created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
            UNIQUE KEY uniq_word (word)
        )");
        $stmt = $pdo->query("SELECT word, replacement FROM bad_words WHERE active=1");
        $words = $stmt->fetchAll(PDO::FETCH_KEY_PAIR);
    } catch (Exception $e) {
        $words = [];
    }
    return $words;
}

/**
 * Filtre les mots interdits dans un texte.
 * Remplace par le symbole configuré (ex: *** ou 😶). Insensible à la casse.
 */
function filterBadWords($text, $pdo) {
    if (empty($text)) return $text;
    $words = _loadBadWords($pdo);
    if (empty($words)) return $text;
    foreach ($words as $word => $replacement) {
        if (empty(trim($word))) continue;
        $pattern = '/\b' . preg_quote(trim($word), '/') . '\b/iu';
        $text = preg_replace($pattern, $replacement ?: '***', $text);
    }
    return $text;
}

// ── Détection de mots-clés et classification des gages ───────────
function _loadKeywords($pdo) {
    static $keywords = null;
    if ($keywords !== null) return $keywords;
    try {
        $pdo->exec("CREATE TABLE IF NOT EXISTS bet_keywords (
            id INT AUTO_INCREMENT PRIMARY KEY,
            keyword VARCHAR(100) NOT NULL,
            category VARCHAR(50) NOT NULL,
            subcategory VARCHAR(50) NOT NULL,
            active TINYINT(1) DEFAULT 1,
            created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
            UNIQUE KEY uniq_kw (keyword)
        )");
        // Ajouter colonne classification dans bets si absente
        try { $pdo->exec("ALTER TABLE bets ADD COLUMN IF NOT EXISTS bet_category VARCHAR(50) DEFAULT NULL"); } catch(Exception $e){}
        try { $pdo->exec("ALTER TABLE bets ADD COLUMN IF NOT EXISTS bet_subcategory VARCHAR(50) DEFAULT NULL"); } catch(Exception $e){}

        $stmt = $pdo->query("SELECT keyword, category, subcategory FROM bet_keywords WHERE active=1 ORDER BY LENGTH(keyword) DESC");
        $keywords = $stmt->fetchAll();
    } catch (Exception $e) {
        $keywords = [];
    }
    return $keywords;
}

/**
 * Détecte la catégorie et sous-catégorie d'un gage selon les mots-clés configurés.
 * Retourne ['category' => '...', 'subcategory' => '...'] ou null si rien détecté.
 */
function detectBetCategory($text, $pdo) {
    if (empty($text)) return null;
    $keywords = _loadKeywords($pdo);
    if (empty($keywords)) return null;
    $textLower = mb_strtolower($text, 'UTF-8');
    foreach ($keywords as $kw) {
        $pattern = '/\b' . preg_quote(mb_strtolower(trim($kw['keyword']), 'UTF-8'), '/') . '\b/iu';
        if (preg_match($pattern, $textLower)) {
            return ['category' => $kw['category'], 'subcategory' => $kw['subcategory']];
        }
    }
    return null;
}

/**
 * Détecte et sauvegarde la classification d'un gage en BD.
 */
function classifyBet($betId, $description, $pdo) {
    $result = detectBetCategory($description, $pdo);
    if ($result) {
        try {
            $pdo->prepare("UPDATE bets SET bet_category=?, bet_subcategory=? WHERE id=?")
                ->execute([$result['category'], $result['subcategory'], $betId]);
        } catch (Exception $e) {}
    }
    return $result;
}

// ── v1.7 — Cercles privés (famille/école/entreprise) ─────────────

/**
 * Retourne les infos du cercle privé d'un user si applicable.
 * Ajoute les colonnes nécessaires à la volée.
 */
function getPrivateCircleInfo($pdo, $circleId) {
    if (!$circleId) return null;
    try {
        // Ajouter colonnes v1.7 si absentes
        try { $pdo->exec("ALTER TABLE circles ADD COLUMN IF NOT EXISTS group_type ENUM('famille','ecole','entreprise') DEFAULT NULL"); } catch(Exception $e){}
        try { $pdo->exec("ALTER TABLE circles ADD COLUMN IF NOT EXISTS is_isolated TINYINT(1) DEFAULT 0"); } catch(Exception $e){}
        try { $pdo->exec("ALTER TABLE bets ADD COLUMN IF NOT EXISTS reward_text VARCHAR(255) DEFAULT NULL"); } catch(Exception $e){}

        $stmt = $pdo->prepare("SELECT id, name, group_type, is_isolated, oracle_id, creator_id FROM circles WHERE id=?");
        $stmt->execute([$circleId]);
        return $stmt->fetch() ?: null;
    } catch (Exception $e) { return null; }
}

/**
 * Retourne true si le user est dans un cercle isolé (mode privé).
 */
function isIsolatedMember($pdo, $userId, $circleId) {
    $info = getPrivateCircleInfo($pdo, $circleId);
    return $info && !empty($info['is_isolated']) && !empty($info['group_type']);
}

/**
 * Retourne true si le user est l'organisateur (oracle/creator) du cercle privé.
 */
function isGroupOrganizer($pdo, $userId, $circleId) {
    $info = getPrivateCircleInfo($pdo, $circleId);
    if (!$info) return false;
    return (int)$info['oracle_id'] === (int)$userId || (int)$info['creator_id'] === (int)$userId;
}
