import { flashcardsService } from '@/lib/services/flashcards' import { ExtendedFlashcard } from '@/lib/types/review' import { TestItem } from '@/store/review/useTestQueueStore' import { isTestMode, getMockCompletedTests } from '@/lib/mock/reviewMockData' // 複習會話服務 export class ReviewService { // 數據轉換:將 Flashcard 轉換為 ExtendedFlashcard static transformToExtendedFlashcard(flashcard: any): ExtendedFlashcard { return { ...flashcard, // 確保必填欄位有預設值 nextReviewDate: flashcard.nextReviewDate || new Date().toISOString(), // 複習相關的額外欄位 currentInterval: flashcard.currentInterval || 0, isOverdue: false, overdueDays: 0, baseMasteryLevel: flashcard.masteryLevel || 0, lastReviewDate: flashcard.lastReviewDate || undefined, // 內容擴展 synonyms: flashcard.synonyms || [], exampleImage: flashcard.primaryImageUrl || undefined, // 複習統計 reviewCount: flashcard.timesReviewed || 0, successRate: 0 } } // 載入到期詞卡 static async loadDueCards(limit = 50): Promise { try { const result = await flashcardsService.getDueFlashcards(limit) if (result.success && result.data) { // 轉換為 ExtendedFlashcard return result.data.map(this.transformToExtendedFlashcard) } else { throw new Error(result.error || '載入詞卡失敗') } } catch (error) { console.error('載入到期詞卡失敗:', error) throw error } } // 載入已完成的測驗 static async loadCompletedTests(cardIds: string[]): Promise { try { // 🧪 測試模式:使用 Mock 數據 if (isTestMode()) { console.log('🧪 [測試模式] 使用 Mock 已完成測驗數據') const mockTests = getMockCompletedTests() // 模擬 API 延遲 await new Promise(resolve => setTimeout(resolve, 200)) console.log('✅ [測試模式] 載入Mock已完成測驗成功:', mockTests.length, '項測驗') return mockTests } // 🌐 正常模式:使用後端 API const result = await flashcardsService.getCompletedTests(cardIds) if (result.success && result.data) { return result.data } else { console.warn('載入已完成測驗失敗:', result.error) return [] } } catch (error) { console.error('載入已完成測驗異常:', error) return [] } } // 記錄測驗結果 static async recordTestResult(params: { flashcardId: string testType: string isCorrect: boolean userAnswer?: string confidenceLevel?: number responseTimeMs?: number }): Promise { try { const result = await flashcardsService.recordTestCompletion({ ...params, responseTimeMs: params.responseTimeMs || 2000 }) if (result.success) { return true } else { console.error('記錄測驗結果失敗:', result.error) return false } } catch (error) { console.error('記錄測驗結果異常:', error) return false } } // 生成測驗選項 static async generateTestOptions( cardId: string, testType: string, count = 4 ): Promise { try { // 這裡可以呼叫後端API生成選項 // 或者使用本地邏輯生成 // 暫時使用簡單的佔位符邏輯 return Array.from({ length: count }, (_, i) => `選項 ${i + 1}`) } catch (error) { console.error('生成測驗選項失敗:', error) return [] } } // 驗證學習會話完整性 static validateSession( cards: ExtendedFlashcard[], testItems: TestItem[] ): { isValid: boolean; errors: string[] } { const errors: string[] = [] // 檢查詞卡是否存在 if (!cards || cards.length === 0) { errors.push('沒有可用的詞卡') } // 檢查測驗項目 if (!testItems || testItems.length === 0) { errors.push('沒有可用的測驗項目') } // 檢查測驗項目和詞卡的一致性 if (cards && testItems) { const cardIds = new Set(cards.map(c => c.id)) const testCardIds = new Set(testItems.map(t => t.cardId)) for (const testCardId of testCardIds) { if (!cardIds.has(testCardId)) { errors.push(`測驗項目引用了不存在的詞卡: ${testCardId}`) } } } return { isValid: errors.length === 0, errors } } // 計算學習統計 static calculateStats(testItems: TestItem[], score: { correct: number; total: number }) { const completed = testItems.filter(item => item.isCompleted).length const total = testItems.length const progressPercentage = total > 0 ? (completed / total) * 100 : 0 const accuracyPercentage = score.total > 0 ? (score.correct / score.total) * 100 : 0 return { completed, total, remaining: total - completed, progressPercentage: Math.round(progressPercentage), accuracyPercentage: Math.round(accuracyPercentage), estimatedTimeRemaining: Math.max(0, (total - completed) * 30) // 假設每個測驗30秒 } } }