/**
 * GameClientSDK - SDK dành cho Game Iframe
 *
 * Sử dụng trong game để:
 * - Tự động xác định mode (preview/live) từ URL
 * - Nhận data từ parent (preview) hoặc fetch API (live)
 * - Verify answers locally
 * - Report results về parent
 */
import { checkAnswer, sanitizeForClient, GAME_CODES } from '../kit/GameDataHandler';
import { getMockData } from './MockData';
import { validateGameData } from './DataValidator';
class SimpleEventEmitter {
    constructor() {
        this.handlers = new Map();
    }
    on(event, handler) {
        if (!this.handlers.has(event)) {
            this.handlers.set(event, new Set());
        }
        this.handlers.get(event).add(handler);
        return () => this.off(event, handler);
    }
    off(event, handler) {
        this.handlers.get(event)?.delete(handler);
    }
    emit(event, data) {
        this.handlers.get(event)?.forEach(handler => {
            try {
                handler(data);
            }
            catch (err) {
                console.error(`[GameClientSDK] Error in ${String(event)} handler:`, err);
            }
        });
    }
}
// =============================================================================
// GAME CLIENT SDK
// =============================================================================
export class GameClientSDK extends SimpleEventEmitter {
    constructor(config = {}) {
        super();
        // Data storage
        this.originalItems = new Map(); // Có đáp án
        this.sanitizedItems = []; // Không có đáp án
        this.userAnswers = new Map();
        this.isInitialized = false;
        this.startTime = 0;
        this.config = {
            debug: config.debug ?? false,
            apiBaseUrl: config.apiBaseUrl ?? '',
            getAuthHeaders: config.getAuthHeaders ?? (() => ({})),
        };
        // Parse URL params
        this.params = this.parseURLParams();
        this.mode = this.params.mode;
        this.log('info', 'SDK created', { mode: this.mode, params: this.params });
        // Emit mode detected
        this.emit('modeDetected', { mode: this.mode, params: this.params });
        // Setup message listener
        this.setupMessageListener();
        // Auto-initialize based on mode
        this.initialize();
    }
    // ==========================================================================
    // PUBLIC API
    // ==========================================================================
    /**
     * Get current mode
     */
    getMode() {
        return this.mode;
    }
    /**
     * Get URL params
     */
    getParams() {
        return { ...this.params };
    }
    /**
     * Get game code
     */
    getGameCode() {
        return this.params.gameCode;
    }
    /**
     * Get sanitized items (safe for rendering)
     */
    getItems() {
        return this.sanitizedItems;
    }
    /**
     * Submit an answer and get verification result
     */
    submitAnswer(questionId, choice) {
        const originalItem = this.originalItems.get(questionId);
        if (!originalItem) {
            this.log('warn', `Item not found: ${questionId}`);
            return { isCorrect: false, score: 0, feedback: 'Question not found' };
        }
        // Verify using GameDataHandler
        const result = checkAnswer(this.params.gameCode, originalItem, choice);
        // Store user answer
        const timeSpent = Date.now() - (this.userAnswers.size === 0 ? this.startTime : Date.now());
        this.userAnswers.set(questionId, {
            choice,
            result: result.isCorrect ? 1 : 0,
            time: timeSpent,
        });
        // Report to parent
        this.sendAnswerReport(questionId, choice, result.isCorrect ? 1 : 0, timeSpent);
        this.log('info', `Answer submitted: ${questionId}`, { choice, result });
        return result;
    }
    /**
     * Get final result
     */
    getFinalResult() {
        const details = Array.from(this.userAnswers.entries()).map(([id, data]) => ({
            question_id: id,
            choice: data.choice,
            result: data.result,
            time_spent: data.time,
        }));
        const correct = details.filter(d => d.result === 1).length;
        const total = this.originalItems.size;
        return {
            score: total > 0 ? Math.round((correct / total) * 100) : 0,
            total,
            correct,
            wrong: total - correct,
            details,
        };
    }
    /**
     * Report final result to parent
     */
    reportFinalResult(result) {
        const finalResult = result ?? this.getFinalResult();
        window.parent.postMessage({
            type: 'FINAL_RESULT',
            data: finalResult,
        }, '*');
        this.log('info', 'Final result reported', finalResult);
    }
    /**
     * Request leaderboard from parent
     */
    requestLeaderboard(top = 10) {
        window.parent.postMessage({
            type: 'GET_LEADERBOARD',
            data: { top },
        }, '*');
    }
    /**
     * Cleanup
     */
    destroy() {
        window.removeEventListener('message', this.handleMessage);
        this.originalItems.clear();
        this.sanitizedItems = [];
        this.userAnswers.clear();
        this.log('info', 'SDK destroyed');
    }
    // ==========================================================================
    // PRIVATE METHODS
    // ==========================================================================
    parseURLParams() {
        const searchParams = new URLSearchParams(window.location.search);
        const mode = (searchParams.get('mode') || 'preview');
        const gameCode = (searchParams.get('game_code') || 'G001');
        const gameId = searchParams.get('game_id') || undefined;
        const lid = searchParams.get('lid') || undefined;
        const studentId = searchParams.get('student_id') || undefined;
        // Validate mode
        if (mode !== 'preview' && mode !== 'live' && mode !== 'dev') {
            this.log('warn', `Invalid mode: ${mode}, defaulting to preview`);
        }
        // Validate game code
        if (!GAME_CODES[gameCode]) {
            this.log('warn', `Unknown game code: ${gameCode}`);
        }
        return { mode, gameCode, gameId, lid, studentId };
    }
    setupMessageListener() {
        this.handleMessage = this.handleMessage.bind(this);
        window.addEventListener('message', this.handleMessage);
    }
    handleMessage(event) {
        const { type, jsonData, leaderboardData } = event.data || {};
        this.log('debug', 'Message received', { type, hasData: !!jsonData });
        switch (type) {
            case 'SERVER_PUSH_DATA':
                if (jsonData) {
                    this.handleDataReceived(jsonData);
                }
                break;
            case 'SERVER_PUSH_LEADERBOARD':
                if (leaderboardData) {
                    this.log('info', 'Leaderboard received', leaderboardData);
                    // Could emit event here
                }
                break;
        }
    }
    async initialize() {
        // Send GAME_READY immediately
        this.sendGameReady();
        if (this.mode === 'dev') {
            // Dev mode: load mock data immediately
            this.log('info', 'DEV MODE: Loading mock data...');
            this.loadMockData();
        }
        else if (this.mode === 'live') {
            // Live mode: fetch data from API
            await this.fetchLiveData();
        }
        else {
            // Preview mode: wait for postMessage
            this.log('info', 'Preview mode: waiting for SERVER_PUSH_DATA...');
        }
    }
    /**
     * Load mock data for dev mode
     */
    loadMockData() {
        const mockData = getMockData(this.params.gameCode);
        if (!mockData) {
            this.emit('error', {
                message: `No mock data available for game code: ${this.params.gameCode}`
            });
            return;
        }
        this.log('info', `Loaded mock data for ${this.params.gameCode}`);
        this.handleDataReceived(mockData);
    }
    sendGameReady() {
        window.parent.postMessage({ type: 'GAME_READY' }, '*');
        this.emit('ready', undefined);
        this.log('info', 'GAME_READY sent');
    }
    async fetchLiveData() {
        const { gameId, lid } = this.params;
        if (!gameId || !lid) {
            this.emit('error', { message: 'Live mode requires game_id and lid' });
            return;
        }
        if (!this.config.apiBaseUrl) {
            this.emit('error', { message: 'Live mode requires apiBaseUrl' });
            return;
        }
        try {
            const url = `${this.config.apiBaseUrl}/games/${gameId}?lid=${lid}`;
            const headers = {
                'Content-Type': 'application/json',
                ...this.config.getAuthHeaders(),
            };
            this.log('info', `Fetching live data: ${url}`);
            const response = await fetch(url, { headers });
            if (!response.ok) {
                throw new Error(`API Error: ${response.status}`);
            }
            const data = await response.json();
            this.handleDataReceived(data);
        }
        catch (error) {
            this.log('error', 'Failed to fetch live data', error);
            this.emit('error', { message: 'Failed to fetch game data', error });
        }
    }
    handleDataReceived(payload) {
        this.startTime = Date.now();
        // Update game code if provided
        if (payload.game_code && GAME_CODES[payload.game_code]) {
            this.params.gameCode = payload.game_code;
        }
        // Validate data structure
        const validation = validateGameData(this.params.gameCode, payload);
        if (!validation.valid) {
            this.log('error', 'Data validation failed', validation.errors);
            this.emit('validationError', { validation });
            // Continue anyway to allow partial rendering
        }
        if (validation.warnings.length > 0) {
            this.log('warn', 'Data validation warnings', validation.warnings);
        }
        // Extract items from various payload formats
        const items = payload.data || payload.items || payload.questions || [];
        const resumeData = payload.completed_question_ids || [];
        // Store original items (with answers)
        this.originalItems.clear();
        items.forEach((item) => {
            if (item.id) {
                this.originalItems.set(item.id, item);
            }
        });
        // Sanitize for client (remove answers)
        this.sanitizedItems = sanitizeForClient(this.params.gameCode, items);
        this.isInitialized = true;
        this.log('info', `Data received: ${items.length} items, ${resumeData.length} completed`);
        // Emit event with validation result
        this.emit('dataReceived', {
            items: this.sanitizedItems,
            resumeData,
            validation,
        });
    }
    sendAnswerReport(questionId, choice, result, timeSpent) {
        window.parent.postMessage({
            type: 'ANSWER_REPORT',
            data: {
                question_id: questionId,
                question_index: Array.from(this.originalItems.keys()).indexOf(questionId),
                choice,
                result,
                time_spent: timeSpent,
            },
        }, '*');
    }
    log(level, message, data) {
        if (!this.config.debug && level === 'debug')
            return;
        const prefix = `[GameClientSDK:${this.mode}]`;
        switch (level) {
            case 'debug':
            case 'info':
                console.log(prefix, message, data ?? '');
                break;
            case 'warn':
                console.warn(prefix, message, data ?? '');
                break;
            case 'error':
                console.error(prefix, message, data ?? '');
                break;
        }
    }
}
// =============================================================================
// FACTORY
// =============================================================================
let clientInstance = null;
/**
 * Get or create GameClientSDK instance
 */
export function getGameClientSDK(config) {
    if (!clientInstance) {
        clientInstance = new GameClientSDK(config);
    }
    return clientInstance;
}
/**
 * Destroy client instance
 */
export function destroyGameClientSDK() {
    clientInstance?.destroy();
    clientInstance = null;
}
//# sourceMappingURL=GameClientSDK.js.map