import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
import { useEffect, useState, useRef, useCallback } from 'react';
import { useGameIframeSDK } from '../../useGameIframeSDK';
import { GameApiClient } from '../api';
import { createGamePayload, normalizeAnswerReport } from '../mappers';
// Session Error Codes (synced with backend)
export const SessionErrorCodes = {
    SESSION_NOT_STARTED: -60,
    SESSION_ENDED: -61,
    SESSION_COMPLETED: -62,
    SESSION_TIMEOUT: -63,
    SESSION_NOT_FOUND: -64,
    SESSION_ALREADY_ANSWERED: -65,
};
export const GamePlayer = ({ apiConfig, assignmentId, studentId, className, style, debug = false, onComplete, onError, onGameLoaded, extraGameData, onLog, onSessionStatus, renderLoading, renderError, loadingTimeout = 30000 }) => {
    const iframeRef = useRef(null);
    const [gameUrl, setGameUrl] = useState('');
    const [gameState, setGameState] = useState(null);
    const [loading, setLoading] = useState(true);
    const [error, setError] = useState(null);
    const [hasLoadedGame, setHasLoadedGame] = useState(false);
    const [apiClient] = useState(() => new GameApiClient(apiConfig));
    // Refs to prevent infinite loops
    const sendLeaderboardRef = useRef(null);
    const hasInitRef = useRef(false); // Track if init has been called
    const callbacksRef = useRef({ onGameLoaded, onLog, onSessionStatus, onError }); // Stable callback refs
    // Update callback refs on each render
    callbacksRef.current = { onGameLoaded, onLog, onSessionStatus, onError };
    // Helper: Create structured error
    const createError = useCallback((err) => {
        const errorMsg = err?.message || err?.error || String(err);
        const errorCode = err?.code; // Error code from API response
        // Check error code first (more reliable than message parsing)
        if (errorCode !== undefined) {
            // Session not started
            if (errorCode === SessionErrorCodes.SESSION_NOT_STARTED) {
                return {
                    type: 'not_started',
                    code: errorCode,
                    message: errorMsg || 'Bài tập chưa bắt đầu',
                    details: err,
                    canRetry: false
                };
            }
            // Session ended
            if (errorCode === SessionErrorCodes.SESSION_ENDED) {
                return {
                    type: 'session',
                    code: errorCode,
                    message: errorMsg || 'Bài tập đã kết thúc',
                    details: err,
                    canRetry: false
                };
            }
            // Session completed
            if (errorCode === SessionErrorCodes.SESSION_COMPLETED) {
                return {
                    type: 'session',
                    code: errorCode,
                    message: errorMsg || 'Bạn đã hoàn thành bài tập này rồi',
                    details: err,
                    canRetry: false
                };
            }
            // Session timeout
            if (errorCode === SessionErrorCodes.SESSION_TIMEOUT) {
                return {
                    type: 'timeout',
                    code: errorCode,
                    message: errorMsg || 'Đã hết thời gian làm bài',
                    details: err,
                    canRetry: false
                };
            }
        }
        // Fallback: Parse error message
        // API errors
        if (errorMsg.includes('API Error') || errorMsg.includes('Failed to fetch')) {
            // Check if it contains session-related message
            if (errorMsg.includes('chưa bắt đầu')) {
                return {
                    type: 'not_started',
                    message: 'Bài tập chưa bắt đầu',
                    details: err,
                    canRetry: false
                };
            }
            return {
                type: 'api',
                message: errorMsg,
                details: err,
                canRetry: true
            };
        }
        // Network errors
        if (errorMsg.includes('network') || errorMsg.includes('ECONNREFUSED')) {
            return {
                type: 'network',
                message: 'Lỗi kết nối mạng. Vui lòng kiểm tra internet.',
                details: err,
                canRetry: true
            };
        }
        // Session errors (message-based fallback)
        if (errorMsg.includes('chưa bắt đầu')) {
            return {
                type: 'not_started',
                message: errorMsg || 'Bài tập chưa bắt đầu',
                details: err,
                canRetry: false
            };
        }
        if (errorMsg.includes('hết thời gian') || errorMsg.includes('đã kết thúc') ||
            errorMsg.includes('đã hoàn thành') || errorMsg.includes('session')) {
            return {
                type: 'session',
                message: errorMsg,
                details: err,
                canRetry: false
            };
        }
        // Timeout errors
        if (errorMsg.includes('timeout') || errorMsg.includes('timed out')) {
            return {
                type: 'timeout',
                message: 'Kết nối quá lâu. Vui lòng thử lại.',
                details: err,
                canRetry: true
            };
        }
        return {
            type: 'unknown',
            message: errorMsg || 'Đã xảy ra lỗi không xác định',
            details: err,
            canRetry: true
        };
    }, []);
    // Helper: Handle error with callback
    const handleError = useCallback((err) => {
        const gameError = createError(err);
        setError(gameError);
        setLoading(false);
        if (onError) {
            onError(gameError);
        }
        if (onLog) {
            onLog(`[SDK ERR] ${gameError.type}: ${gameError.message}`, 'error');
        }
    }, [createError, onError, onLog]);
    // Retry function
    const retryInit = useCallback(() => {
        if (callbacksRef.current.onLog)
            callbacksRef.current.onLog('[SDK] Retrying initialization...', 'info');
        hasInitRef.current = false; // Allow re-init
        setError(null);
        setLoading(true);
        setGameUrl('');
        setGameState(null);
    }, []);
    // Define Handlers
    const handleAnswer = useCallback(async (data) => {
        try {
            if (onLog)
                onLog(`[SDK RECV] Answer Raw: ${JSON.stringify(data)}`, 'info');
            const report = normalizeAnswerReport(data);
            if (onLog)
                onLog(`[SDK] Processed Answer: ID ${report.question_id} | Choice: ${report.choice} | ${report.is_correct ? 'Correct' : 'Wrong'}`, 'info');
            if (onLog)
                onLog(`[API REQ] Submitting Answer ID ${report.question_id}...`, 'info');
            const res = await apiClient.submitAnswer(assignmentId, studentId, report.question_id, report.choice, report.time_spent, report.is_timeout);
            if (onLog)
                onLog(`[API RES] Submit Result: ${JSON.stringify(res)}`, 'success');
        }
        catch (err) {
            console.error('[GamePlayer] Submit error:', err);
            if (onLog)
                onLog(`[API ERR] Submit Failed: ${err.message}`, 'error');
        }
    }, [apiClient, assignmentId, studentId, onLog]);
    const handleFinalResult = useCallback(async (data) => {
        try {
            if (onLog)
                onLog(`[SDK RECV] Final Result Raw: ${JSON.stringify(data)}`, 'info');
            if (onLog)
                onLog('[SDK] Game Complete. Calling API...', 'info');
            const res = await apiClient.completeSession(assignmentId, studentId);
            if (onLog)
                onLog(`[API RES] Session Completed. Score: ${res.data?.finalScore}`, 'success');
            // Auto-refresh leaderboard after completion to ensure user rank is included
            if (onLog)
                onLog('[SDK] Auto-refreshing leaderboard after completion...', 'info');
            await new Promise(resolve => setTimeout(resolve, 500)); // Small delay for backend to process
            try {
                const lbRes = await apiClient.getLeaderboard(assignmentId, studentId);
                if (onLog)
                    onLog(`[API RES] Post-completion Leaderboard: ${JSON.stringify(lbRes)}`, 'success');
                if (lbRes.success && lbRes.data && sendLeaderboardRef.current) {
                    const leaderboardData = {
                        top_players: (lbRes.data.topPlayers || []).map((p) => ({
                            rank: p.rank,
                            name: p.name || p.studentName || p.userId,
                            score: p.score ?? p.finalScore ?? 0,
                            student_id: p.studentId || p.userId,
                            time_spent: p.timeSpent ?? p.time_spent ?? 0,
                            completed_at: p.completedAt
                        })),
                        user_rank: lbRes.data.userRank ? {
                            rank: lbRes.data.userRank.rank,
                            name: lbRes.data.userRank.name || lbRes.data.userRank.studentName,
                            score: lbRes.data.userRank.score ?? lbRes.data.userRank.finalScore ?? 0,
                            student_id: lbRes.data.userRank.studentId || lbRes.data.userRank.userId,
                            time_spent: lbRes.data.userRank.timeSpent ?? lbRes.data.userRank.time_spent ?? 0,
                            completed_at: lbRes.data.userRank.completedAt
                        } : null
                    };
                    if (onLog)
                        onLog(`[SDK SEND] Updated Leaderboard: ${JSON.stringify(leaderboardData)}`, 'info');
                    sendLeaderboardRef.current(leaderboardData);
                }
            }
            catch (lbErr) {
                if (onLog)
                    onLog(`[API ERR] Leaderboard refresh failed: ${lbErr.message}`, 'warning');
            }
            if (onComplete)
                onComplete(res);
        }
        catch (err) {
            console.error('[GamePlayer] Complete error:', err);
            if (onLog)
                onLog(`[API ERR] Complete Failed: ${err.message}`, 'error');
            if (onError)
                onError(err);
        }
    }, [apiClient, assignmentId, studentId, onComplete, onError, onLog]);
    // SDK Hook
    const { isReady, sendGameData, sendLeaderboard } = useGameIframeSDK({
        iframeRef,
        iframeOrigin: '*',
        debug,
        onGameReady: () => {
            if (onLog)
                onLog('[SDK RECV] Iframe Ready', 'success');
        },
        onAnswerReport: handleAnswer,
        onFinalResult: handleFinalResult,
        onLeaderboardRequest: async (top) => {
            try {
                if (onLog)
                    onLog(`[SDK RECV] Leaderboard Request Raw: top=${top}`, 'info');
                if (onLog)
                    onLog(`[API REQ] Fetching Leaderboard (top ${top})...`, 'info');
                const res = await apiClient.getLeaderboard(assignmentId, studentId);
                if (onLog)
                    onLog(`[API RES] Leaderboard Raw: ${JSON.stringify(res)}`, 'success');
                if (res.success && res.data) {
                    const leaderboardData = {
                        top_players: (res.data.topPlayers || []).map((p) => ({
                            rank: p.rank,
                            name: p.name || p.studentName || p.userId,
                            score: p.score ?? p.finalScore ?? 0,
                            student_id: p.studentId || p.userId,
                            time_spent: p.timeSpent ?? p.time_spent ?? 0,
                            completed_at: p.completedAt
                        })),
                        user_rank: res.data.userRank ? {
                            rank: res.data.userRank.rank,
                            name: res.data.userRank.name || res.data.userRank.studentName,
                            score: res.data.userRank.score ?? res.data.userRank.finalScore ?? 0,
                            student_id: res.data.userRank.studentId || res.data.userRank.userId,
                            time_spent: res.data.userRank.timeSpent ?? res.data.userRank.time_spent ?? 0,
                            completed_at: res.data.userRank.completedAt
                        } : null
                    };
                    if (onLog)
                        onLog(`[SDK SEND] Leaderboard Payload: ${JSON.stringify(leaderboardData)}`, 'info');
                    const sent = sendLeaderboard(leaderboardData);
                    if (onLog)
                        onLog(sent ? '[SDK] Leaderboard sent successfully' : '[SDK ERR] Failed to send leaderboard', sent ? 'success' : 'error');
                }
            }
            catch (err) {
                console.error('[GamePlayer] Leaderboard error:', err);
                if (onLog)
                    onLog(`[API ERR] Leaderboard Failed: ${err.message}`, 'error');
            }
        }
    });
    // Update ref after hook
    sendLeaderboardRef.current = sendLeaderboard;
    // 1. Fetch Game Data & Start Session
    useEffect(() => {
        let mounted = true;
        let loadingTimeoutId;
        const initGame = async () => {
            try {
                setLoading(true);
                setError(null);
                if (onLog)
                    onLog('[SDK] Initializing Game...', 'info');
                // Set loading timeout
                loadingTimeoutId = setTimeout(() => {
                    if (mounted && loading) {
                        if (onLog)
                            onLog('[SDK WARN] Loading taking longer than expected...', 'warning');
                    }
                }, loadingTimeout);
                // getGameWithProgress đã tự động tạo/restore session trong backend
                // thông qua getOrCreateSubmissionCache - không cần gọi startLiveSession riêng
                const res = await apiClient.getGameWithProgress(assignmentId, studentId);
                if (!res.success || !res.data) {
                    throw new Error(res.message || 'Failed to load game');
                }
                if (mounted) {
                    // Check session status TRƯỚC để quyết định có load game hay không
                    const session = res.data.session;
                    const progress = res.data.progress;
                    // Case 1: Already completed
                    if (res.data.isFinished || session?.completed) {
                        // CHỈ set error nếu CHƯA load game (lần đầu vào)
                        if (!hasLoadedGame) {
                            const errorObj = {
                                type: 'session',
                                message: 'Bạn đã hoàn thành bài tập này rồi',
                                details: { score: progress?.score, answered: progress?.answered, total: progress?.total },
                                canRetry: false
                            };
                            setError(errorObj);
                            setLoading(false);
                            clearTimeout(loadingTimeoutId);
                            if (onError)
                                onError(errorObj);
                            if (onLog)
                                onLog(`[SDK] ${errorObj.message}`, 'warning');
                        }
                        // Luôn gọi callback (cho cả 2 trường hợp)
                        if (onSessionStatus) {
                            onSessionStatus({
                                type: 'completed',
                                message: 'Bạn đã hoàn thành bài tập này',
                                data: {
                                    answered: progress?.answered || 0,
                                    total: progress?.total || 0,
                                    score: progress?.score || 0
                                }
                            });
                        }
                        // Nếu CHƯA load game → STOP
                        // Nếu ĐÃ load game → tiếp tục (cho game hiển thị leaderboard)
                        if (!hasLoadedGame) {
                            return; // ❌ STOP - không load game
                        }
                    }
                    // Case 2: Session timeout
                    if (session && session.remainingTime !== null && session.remainingTime <= 0) {
                        // CHỈ set error nếu CHƯA load game
                        if (!hasLoadedGame) {
                            const errorObj = {
                                type: 'timeout',
                                message: 'Thời gian làm bài đã hết',
                                details: { answered: progress?.answered, total: progress?.total },
                                canRetry: false
                            };
                            setError(errorObj);
                            setLoading(false);
                            clearTimeout(loadingTimeoutId);
                            if (onError)
                                onError(errorObj);
                            if (onLog)
                                onLog(`[SDK] ${errorObj.message}`, 'warning');
                        }
                        // Luôn gọi callback
                        if (onSessionStatus) {
                            onSessionStatus({
                                type: 'timeout',
                                message: 'Thời gian làm bài đã hết',
                                data: {
                                    answered: progress?.answered || 0,
                                    total: progress?.total || 0,
                                    score: progress?.score || 0,
                                    remainingTime: 0
                                }
                            });
                        }
                        // Nếu CHƯA load game → STOP
                        if (!hasLoadedGame) {
                            return; // ❌ STOP - không load game
                        }
                    }
                    // Case 3: Valid session - LOAD game
                    setGameState(res.data);
                    setGameUrl(res.data.gameUrl);
                    setLoading(false);
                    setHasLoadedGame(true); // ✅ Đánh dấu đã load game
                    clearTimeout(loadingTimeoutId);
                    if (onGameLoaded)
                        onGameLoaded(res.data);
                    if (onLog)
                        onLog(`[API RES] Game Loaded: ${res.data.title || res.data.gameType || assignmentId}`, 'success');
                    // Notify session status for valid sessions
                    if (session && onSessionStatus) {
                        // Resumed session (có câu đã trả lời)
                        if (progress && progress.answered > 0) {
                            onSessionStatus({
                                type: 'resumed',
                                message: `Tiếp tục làm bài (Đã làm ${progress.answered}/${progress.total} câu)`,
                                data: {
                                    answered: progress.answered,
                                    total: progress.total,
                                    score: progress.score,
                                    remainingTime: session.remainingTime,
                                    startedAt: session.startedAt
                                }
                            });
                        }
                        // New session
                        else {
                            onSessionStatus({
                                type: 'new',
                                message: 'Bắt đầu làm bài mới',
                                data: {
                                    answered: 0,
                                    total: progress?.total || 0,
                                    score: 0,
                                    remainingTime: session.remainingTime,
                                    startedAt: session.startedAt
                                }
                            });
                        }
                    }
                    // Log session info
                    if (session && onLog) {
                        const sessionInfo = `Session started at ${session.startedAt}, remaining: ${session.remainingTime}s`;
                        onLog(`[SDK] ${sessionInfo}`, 'info');
                    }
                }
            }
            catch (err) {
                console.error('[GamePlayer] Init error:', err);
                if (mounted) {
                    handleError(err);
                }
            }
        };
        if (assignmentId && studentId && !hasInitRef.current) {
            hasInitRef.current = true; // Prevent re-init
            initGame();
        }
        return () => {
            mounted = false;
            hasInitRef.current = false; // ✅ Reset for StrictMode remount
            if (loadingTimeoutId)
                clearTimeout(loadingTimeoutId);
        };
        // eslint-disable-next-line react-hooks/exhaustive-deps
    }, [assignmentId, studentId]); // ✅ Chỉ re-init khi assignmentId hoặc studentId thay đổi
    // 2. Auto Send Data when Ready
    useEffect(() => {
        if (isReady && gameState) {
            // Get expiresAt from session (absolute timestamp for accurate sync)
            const getEndTimeIso = () => {
                const session = gameState.session;
                if (!session)
                    return undefined;
                // Ưu tiên dùng expiresAt
                if (session.expiresAt) {
                    return session.expiresAt;
                }
                // Fallback: tính từ startedAt + duration
                if (session.startedAt && session.duration) {
                    const startTimeMs = new Date(session.startedAt).getTime();
                    const expiresAtMs = startTimeMs + (session.duration * 1000);
                    return new Date(expiresAtMs).toISOString();
                }
                return undefined;
            };
            const payload = createGamePayload({
                gameId: gameState.id,
                userId: studentId,
                gameData: gameState.jsonData,
                answeredQuestions: gameState.completed_question_ids,
                extraData: extraGameData,
                endTimeIso: getEndTimeIso() // ✅ Absolute timestamp
            });
            if (onLog)
                onLog(`[SDK SEND] Game Payload: ${JSON.stringify(payload)}`, 'info');
            sendGameData(payload);
        }
    }, [isReady, gameState, studentId, sendGameData, extraGameData, onLog]);
    // ===== RENDER =====
    // 1. Error State
    if (error) {
        if (renderError) {
            return _jsx(_Fragment, { children: renderError(error, retryInit) });
        }
        // Default error UI
        return (_jsxs("div", { className: "game-player-error", style: {
                display: 'flex',
                flexDirection: 'column',
                alignItems: 'center',
                justifyContent: 'center',
                height: '100%',
                padding: '2rem',
                textAlign: 'center',
                backgroundColor: '#f8f9fa',
                ...style
            }, children: [_jsx("div", { style: {
                        fontSize: '3rem',
                        marginBottom: '1rem'
                    }, children: error.type === 'network' ? '🌐' :
                        error.type === 'timeout' ? '⏱️' :
                            error.type === 'session' ? '🔒' :
                                error.type === 'not_started' ? '📅' : '⚠️' }), _jsx("h2", { style: {
                        fontSize: '1.5rem',
                        fontWeight: 'bold',
                        marginBottom: '0.5rem',
                        color: error.type === 'not_started' ? '#fd7e14' : '#dc3545'
                    }, children: error.type === 'network' ? 'Lỗi Kết Nối' :
                        error.type === 'timeout' ? 'Hết Giờ Làm Bài' :
                            error.type === 'session' ? 'Phiên Làm Bài Đã Kết Thúc' :
                                error.type === 'not_started' ? 'Bài Tập Chưa Bắt Đầu' :
                                    'Đã Xảy Ra Lỗi' }), _jsx("p", { style: {
                        fontSize: '1rem',
                        color: '#6c757d',
                        marginBottom: '1.5rem',
                        maxWidth: '500px'
                    }, children: error.message }), error.canRetry && (_jsx("button", { onClick: retryInit, style: {
                        padding: '0.75rem 2rem',
                        fontSize: '1rem',
                        fontWeight: 'bold',
                        color: '#fff',
                        backgroundColor: '#007bff',
                        border: 'none',
                        borderRadius: '0.5rem',
                        cursor: 'pointer',
                        transition: 'background-color 0.2s'
                    }, onMouseEnter: (e) => e.currentTarget.style.backgroundColor = '#0056b3', onMouseLeave: (e) => e.currentTarget.style.backgroundColor = '#007bff', children: "\uD83D\uDD04 Th\u1EED L\u1EA1i" })), !error.canRetry && (_jsx("p", { style: {
                        fontSize: '0.875rem',
                        color: '#6c757d',
                        marginTop: '1rem'
                    }, children: "Vui l\u00F2ng li\u00EAn h\u1EC7 gi\u00E1o vi\u00EAn ho\u1EB7c quay l\u1EA1i trang ch\u1EE7" }))] }));
    }
    // 2. Loading State
    if (loading || !gameUrl) {
        if (renderLoading) {
            return _jsx(_Fragment, { children: renderLoading() });
        }
        // Default loading UI
        return (_jsxs("div", { className: "game-player-loading", style: {
                display: 'flex',
                flexDirection: 'column',
                alignItems: 'center',
                justifyContent: 'center',
                height: '100%',
                backgroundColor: '#f8f9fa',
                ...style
            }, children: [_jsx("div", { style: {
                        width: '50px',
                        height: '50px',
                        border: '5px solid #e9ecef',
                        borderTop: '5px solid #007bff',
                        borderRadius: '50%',
                        animation: 'spin 1s linear infinite',
                        marginBottom: '1rem'
                    } }), _jsx("p", { style: {
                        fontSize: '1.125rem',
                        color: '#6c757d',
                        fontWeight: '500'
                    }, children: "\u0110ang t\u1EA3i tr\u00F2 ch\u01A1i..." }), _jsx("style", { children: `
                    @keyframes spin {
                        0% { transform: rotate(0deg); }
                        100% { transform: rotate(360deg); }
                    }
                ` })] }));
    }
    // 3. Game Iframe
    return (_jsx("iframe", { ref: iframeRef, src: gameUrl, className: className, style: { width: '100%', height: '100%', border: 'none', ...style }, allowFullScreen: true }));
};
//# sourceMappingURL=GamePlayer.js.map