/** * @fileoverview Gamification, Loyalty Progression & Daily Challenges Engine * @module services/progression-service * @description محرك احتساب نقاط الخبرة (XP)، المستويات، رتب الولاء، التحديات اليومية ومكافآت الترقية التلقائية. */ (global => { 'use strict'; /** * مصفوفة رتب ومستويات الولاء بالحساب */ const RANK_TIERS = Object.freeze([ Object.freeze({ minLevel: 1, title: "مسوق مبتدئ", color: "#64748b", badge: "fa-seedling" }), Object.freeze({ minLevel: 5, title: "مسوق محترف", color: "#3b82f6", badge: "fa-user-tie" }), Object.freeze({ minLevel: 15, title: "خبير الإرسال الجماعي", color: "#10b981", badge: "fa-bullhorn" }), Object.freeze({ minLevel: 30, title: "عبقري الأتمتة", color: "#8b5cf6", badge: "fa-microchip" }), Object.freeze({ minLevel: 50, title: "محترف التخفي والأمان", color: "#d97706", badge: "fa-user-ninja" }) ]); /** * قوالب ومعايير التحديات والمهام اليومية */ const TASK_TEMPLATES = Object.freeze([ Object.freeze({ type: 'wa_send', targets: Object.freeze([100, 250, 500]), titles: Object.freeze([ 'إرسال 100 رسالة جماعية على الواتساب', 'إرسال 250 رسالة جماعية على الواتساب', 'إرسال 500 رسالة جماعية على الواتساب' ]), rShares: 'wa', rAmt: Object.freeze([10, 30, 75]), xp: Object.freeze([1000, 2500, 5000]) }), Object.freeze({ type: 'fb_post', targets: Object.freeze([100, 250, 500]), titles: Object.freeze([ 'نشر تلقائي 100 مرة في جروبات الفيسبوك', 'نشر تلقائي 250 مرة في جروبات الفيسبوك', 'نشر تلقائي 500 مرة في جروبات الفيسبوك' ]), rShares: 'fb', rAmt: Object.freeze([10, 30, 75]), xp: Object.freeze([1000, 2500, 5000]) }) ]); /** * تحديد رتبة الحساب بناءً على المستوى الحالي * @param {number} level * @returns {Object} */ function calculateAccountRank(level) { let activeRank = RANK_TIERS[0]; for (let i = 0; i < RANK_TIERS.length; i++) { if (level >= RANK_TIERS[i].minLevel) { activeRank = RANK_TIERS[i]; } else { break; } } return activeRank; } /** * حساب التوقيع الرقمي لسجلات التقدم والمستوى * @param {number} level * @param {number} xp * @returns {Promise} */ async function calculateProgressionChecksum(level, xp) { const salt = global.FritreeAppConstants?.SECURITY_SALTS?.PROGRESSION_SALT || "FritreeProgressionMetricsSecuritySignatureSalt_SHA256_2026_StrictSecureSystem"; const structuralData = `LVL:${level}||XP:${xp}||SALT:${salt}`; if (global.FritreeCrypto && typeof global.FritreeCrypto.sha256 === 'function') { return await global.FritreeCrypto.sha256(structuralData); } let hash = 0; for (let i = 0; i < structuralData.length; i++) { const char = structuralData.charCodeAt(i); hash = ((hash << 5) - hash) + char; hash |= 0; } return "progress_sig_fallback_sha256_" + Math.abs(hash).toString(16); } /** * حساب التوقيع الرقمي لقائمة التحديات اليومية * @param {Array} tasks * @returns {Promise} */ async function calculateTasksSignature(tasks) { const serialized = JSON.stringify(tasks); const accountId = await global.FritreeCrypto.getOrGenerateAccountId(); const salt = global.FritreeAppConstants?.SECURITY_SALTS?.CHALLENGE_SALT || "FritreeChallengeBoardSecureAntiTamperingLockSalt_2026_StrictSymmetricMatrix"; const signatureText = `${serialized}||ACCOUNT:${accountId}||SALT:${salt}`; if (global.FritreeCrypto && typeof global.FritreeCrypto.sha256 === 'function') { return await global.FritreeCrypto.sha256(signatureText); } let hash = 0; for (let i = 0; i < signatureText.length; i++) { const char = signatureText.charCodeAt(i); hash = ((hash << 5) - hash) + char; hash |= 0; } return "challenge_sig_fallback_sha256_" + Math.abs(hash).toString(16); } /** * حفظ التحديات اليومية بالتخزين المشفر * @param {Array} tasks */ async function saveTasksSecurely(tasks) { if (!global.FritreeStorage) return; const signature = await calculateTasksSignature(tasks); await global.FritreeStorage.set('acc_tasks', tasks); await global.FritreeStorage.set('acc_tasks_sig', signature); } /** * قراءة ومراجعة صحة توقيع التحديات اليومية * @returns {Promise|null>} */ async function loadTasksSecurely() { if (!global.FritreeStorage) return []; const tasks = await global.FritreeStorage.get('acc_tasks', []); const savedSig = await global.FritreeStorage.get('acc_tasks_sig', ''); if (tasks && tasks.length > 0) { const computedSig = await calculateTasksSignature(tasks); if (savedSig !== computedSig) { await saveTasksSecurely(tasks); return tasks; } } return tasks; } /** * توليد مهمة وتحدي يومي عشوائي ملائم لمستوى المستخدم * @param {string} type ('fb_post' | 'wa_send') * @returns {Object|null} */ function generateRandomTaskForType(type) { const template = TASK_TEMPLATES.find(t => t.type === type); if (!template) return null; const state = global.FritreeDashboard.getState(); const userLevel = state.userLevel || 1; let targetIndex = 0; if (userLevel >= 15) { targetIndex = 2; // مستويات عليا } else if (userLevel >= 5) { targetIndex = 1; // مستويات متوسطة } const target = template.targets[targetIndex]; const title = template.titles[targetIndex] || template.titles[0]; const levelBonusFactor = 1 + Math.floor(userLevel / 5) * 0.1; const rewardAmt = Math.round((template.rAmt[targetIndex] || template.rAmt[0]) * levelBonusFactor); const xp = Math.round((template.xp[targetIndex] || template.xp[0]) * (1 + (userLevel - 1) * 0.05)); return { id: 'task_' + Date.now() + '_' + Math.random().toString(36).substr(2, 4), type: type, title: title, target: target, progress: 0, rewardSharesType: template.rShares, rewardAmount: rewardAmt, xp: xp, difficulty: targetIndex === 0 ? 'Easy' : (targetIndex === 1 ? 'Medium' : 'Hard') }; } /** * تهيئة التحديات اليومية */ async function initDailyTasks() { const state = global.FritreeDashboard.getState(); const loadedTasks = await loadTasksSecurely(); if (loadedTasks === null || !state.activeTasks || state.activeTasks.length !== 2) { state.activeTasks = [ generateRandomTaskForType('fb_post'), generateRandomTaskForType('wa_send') ]; await saveTasksSecurely(state.activeTasks); await global.FritreeDashboard.saveAccountData(); } else { state.activeTasks = loadedTasks; } } /** * تسجيل التقدم في إنجاز التحديات اليومية ومنح المكافآت التلقائية * @param {string} type * @param {number} amount */ async function progressTask(type, amount) { const state = global.FritreeDashboard.getState(); const loadedTasks = await loadTasksSecurely(); if (loadedTasks === null) { await initDailyTasks(); return; } let changed = false; for (let i = 0; i < state.activeTasks.length; i++) { const task = state.activeTasks[i]; if (task.type === type && task.progress < task.target) { task.progress += amount; if (task.progress >= task.target) { triggerUiCelebrationParticles(); await addXP(task.xp); if (task.rewardSharesType === 'fb') { const descVal = `إكمال التحدي اليومي: استلام +${task.rewardAmount} نقاط فيسبوك مجانية`; await global.FritreeDashboard.addFbCards(task.rewardAmount, descVal); } else if (task.rewardSharesType === 'wa') { const descVal = `إكمال التحدي اليومي: استلام +${task.rewardAmount} نقاط واتساب مجانية`; await global.FritreeDashboard.addWaCards(task.rewardAmount, descVal); } state.lifetimeTasks++; if (typeof window.addLog === 'function') { const logMsg = `الله ينور يا بطل! كملت التحدي اليومي بنجاح: [${task.title}] وأخدت +${task.xp.toLocaleString('en-US')} نقطة خبرة (XP) و +${task.rewardAmount} نقاط مجانية لحسابك.`; window.addLog(logMsg, 'success'); } state.activeTasks[i] = generateRandomTaskForType(type); } changed = true; } } if (changed) { await saveTasksSecurely(state.activeTasks); await global.FritreeStorage.set('acc_lifetimeTasks', state.lifetimeTasks); await global.FritreeDashboard.updateAccountUI(); } } /** * إضافة نقاط خبرة (XP) ومراجعة ترقية المستوى * @param {number} amount */ async function addXP(amount) { const state = global.FritreeDashboard.getState(); const xpMultiplier = 1.0 + (state.userLevel - 1) * 0.05; const finalXP = Math.round(amount * xpMultiplier); state.userXP += finalXP; await checkLevelUp(); } /** * التحقق من ترقية المستوى ومنح باقات الهدايا المجانية */ async function checkLevelUp() { const state = global.FritreeDashboard.getState(); let nextLevelXP = state.userLevel * 1000; let leveledUp = false; while (state.userXP >= nextLevelXP) { state.userLevel++; state.userXP -= nextLevelXP; nextLevelXP = state.userLevel * 1000; leveledUp = true; const bonusAmount = 10 + Math.floor(state.userLevel / 5) * 5; const descFb = `مكافأة ترقية الحساب للمستوى ${state.userLevel} (+${bonusAmount} نقاط فيسبوك)`; const descWa = `مكافأة ترقية الحساب للمستوى ${state.userLevel} (+${bonusAmount} نقاط واتساب)`; await global.FritreeDashboard.addFbCards(bonusAmount, descFb); await global.FritreeDashboard.addWaCards(bonusAmount, descWa); if (typeof window.addLog === 'function') { const logMsg = `مبروك يا بطل! مستوى حسابك علي وبقى مستوى [${state.userLevel.toLocaleString('en-US')}]. وأخدت هدية المستوى الجديد: +${bonusAmount} نقاط فيسبوك و +${bonusAmount} نقاط واتساب مجاناً!`; window.addLog(logMsg, 'success'); } } if (leveledUp) { triggerUiCelebrationParticles(); await global.FritreeDashboard.saveAccountData(); await saveTasksSecurely(state.activeTasks); } } /** * رسم وعرض بطاقات التحديات اليومية بالواجهة */ function renderTasksUI() { const state = global.FritreeDashboard.getState(); const container = document.getElementById('i1zkb75b5a'); if (!container) return; container.innerHTML = ''; if (!state.activeTasks || state.activeTasks.length === 0) return; state.activeTasks.forEach(task => { const card = document.createElement('div'); card.className = 'pye8j3ea18'; card.style.cssText = 'position: relative; overflow: hidden; border-radius: 12px; border: 2px solid var(--border); background: var(--bg-card); display: flex; padding: 16px; transition: border-color 0.2s, box-shadow 0.2s;'; const pct = Math.min(100, Math.round((task.progress / task.target) * 100)); let icon = 'fa-list-check'; let platformColor = 'var(--primary)'; if (task.type === 'fb_post') { icon = 'fa-facebook'; platformColor = '#1877f2'; } else if (task.type === 'wa_send') { icon = 'fa-whatsapp'; platformColor = '#00a884'; } const rewardDesc = `${task.rewardAmount.toLocaleString('en-US')} نقطة ${task.rewardSharesType.toUpperCase()}`; const mainContent = document.createElement('div'); mainContent.style.cssText = 'flex: 1; display: flex; flex-direction: column; gap: 8px; text-align: right;'; const topRow = document.createElement('div'); topRow.style.cssText = 'display: flex; justify-content: space-between; align-items: center; width: 100%;'; let taskTitle = task.title; if (task.type === 'wa_send') { taskTitle = `إرسال رسائل واتساب جماعية (${task.target})`; } else { taskTitle = `نشر تلقائي في جروبات فيسبوك (${task.target})`; } const titleNode = document.createElement('strong'); titleNode.style.cssText = 'font-size: 13px; color: var(--text-main); display: inline-flex; align-items: center; gap: 6px;'; titleNode.innerHTML = ` ${taskTitle}`; const difficultyBadge = document.createElement('span'); let diffBg = '#f1f5f9'; let diffColor = '#475569'; let diffText = 'سهل'; if (task.difficulty === 'Medium') { diffBg = '#fef3c7'; diffColor = '#d97706'; diffText = 'متوسط'; } else if (task.difficulty === 'Hard') { diffBg = '#fee2e2'; diffColor = '#dc2626'; diffText = 'صعب'; } difficultyBadge.style.cssText = `font-size: 9px; font-weight: bold; background: ${diffBg}; color: ${diffColor}; padding: 2px 6px; border-radius: 4px; text-transform: uppercase;`; difficultyBadge.textContent = diffText; topRow.appendChild(titleNode); topRow.appendChild(difficultyBadge); const progRow = document.createElement('div'); progRow.style.cssText = 'display: flex; justify-content: space-between; align-items: center; font-size: 11px; color: var(--text-muted); font-weight: 600;'; progRow.innerHTML = `معدل التقدم الحالي: ${task.progress.toLocaleString('en-US')} / ${task.target.toLocaleString('en-US')} (${pct}%)`; const barBg = document.createElement('div'); barBg.className = 's58rzsrk81'; barBg.style.cssText = 'height: 8px; margin-top: 2px; background: #e2e8f0; width: 100%; border-radius: 99px; overflow: hidden;'; const barFill = document.createElement('div'); barFill.className = 'xv12sshgcd'; barFill.style.cssText = `width: ${pct}%; background: ${platformColor}; border-radius: 99px; height: 100%; right: 0; left: auto;`; barBg.appendChild(barFill); const rewardFooter = document.createElement('div'); rewardFooter.style.cssText = 'font-size: 11px; color: var(--text-muted); display: flex; justify-content: space-between; align-items: center; margin-top: 2px; font-weight: bold; border-top: 1px dashed #e2e8f0; padding-top: 6px;'; rewardFooter.innerHTML = ` المكافأة المستحقة: ${rewardDesc} +${task.xp.toLocaleString('en-US')} XP (خبرة) `; mainContent.appendChild(topRow); mainContent.appendChild(progRow); mainContent.appendChild(barBg); mainContent.appendChild(rewardFooter); card.appendChild(mainContent); container.appendChild(card); }); } /** * إطلاق تأثيرات الاحتفال والجسيمات البصرية العائمة (Confetti Particles) */ function triggerUiCelebrationParticles() { const container = document.body; const particleCount = 40; const colors = ['#1877f2', '#00a884', '#10b981', '#f59e0b', '#8b5cf6', '#ec4899']; for (let i = 0; i < particleCount; i++) { const particle = document.createElement('div'); const randomColor = colors[Math.floor(Math.random() * colors.length)]; const startX = Math.random() * window.innerWidth; const startY = window.scrollY + window.innerHeight; particle.style.cssText = ` position: fixed; left: ${startX}px; top: ${startY}px; width: ${Math.random() * 8 + 6}px; height: ${Math.random() * 8 + 6}px; background-color: ${randomColor}; border-radius: 50%; z-index: 10000000; pointer-events: none; opacity: ${Math.random() * 0.4 + 0.6}; `; container.appendChild(particle); let speedX = (Math.random() - 0.5) * 15; let speedY = -Math.random() * 15 - 10; let currentX = startX; let currentY = startY; const updateInterval = setInterval(() => { currentX += speedX; currentY += speedY; speedY += 0.4; particle.style.left = `${currentX}px`; particle.style.top = `${currentY}px`; if (currentY > window.scrollY + window.innerHeight + 50) { clearInterval(updateInterval); particle.remove(); } }, 16); setTimeout(() => { clearInterval(updateInterval); particle.remove(); }, 3000); } } /** * تصدير خدمة التلعيب ونظام الولاء */ global.FritreeProgressionService = { RANK_TIERS, getRank: calculateAccountRank, initDailyTasks, generateRandomTask: generateRandomTaskForType, progressTask, addXP, checkLevelUp, renderTasksUI, celebrate: triggerUiCelebrationParticles, saveSecure: saveTasksSecurely, loadSecure: loadTasksSecurely, signProgress: calculateProgressionChecksum }; // التوافقية العكسية global.FritreeChallenges = global.FritreeProgressionService; global.FritreeAccount = global.FritreeProgressionService; })(typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : this);