/**
 * Sena SDK Constructor
 * @param {Object} config - Configuration object for the SDK
 * @param {Object} config.data - Quiz data containing question, options, and answer
 */
function SenaSDK(gid = 'G2510S1T30') {
    // Initialize data
    this.data = null;
    this.correctAnswer = null;
    this.gameCode = gid;
    // Initialize properties
    this.timeLimit = 0;
    this.shuffle = true;
    // tracking time in game
    this.startTime = 0;
    this.endTime = 0;
    // Initialize Web Speech API
    this.speechSynthesis = window.speechSynthesis;
    this.currentUtterance = null;
    this.voiceSettings = {
        lang: 'en-US',
        rate: 1.0,      // Speed (0.1 to 10)
        pitch: 1.0,     // Pitch (0 to 2)
        volume: 1.0     // Volume (0 to 1)
    };
}

/**
 * Shuffle array using Fisher-Yates algorithm
 * @param {Array} array - Array to shuffle
 */
SenaSDK.prototype.shuffleArray = function(array) {
    for (let i = array.length - 1; i > 0; i--) {
        const j = Math.floor(Math.random() * (i + 1));
        [array[i], array[j]] = [array[j], array[i]];
    }
};
SenaSDK.prototype.load = function(callback,template = 'G2510S1T30') {
    let self = this;
    // get parameter LID from URL
    const urlParams = new URLSearchParams(window.location.search);
    const LID = urlParams.get('LID');
    if (LID) {
        self.gameCode = LID;
    };
    fetch(`https://senaai.tech/sample/${self.gameCode}.json`)
    .then(response => response.json())
    .then(data => {
        self.data = data.data;
        self.correctAnswer = data.answer || null;
        // based on game code, set timeLimit and shuffle
        const gameCode = self.gameCode || template;
        const regex = /^G([1-5])([2-9])([0-2])([0-2])(?:S([0-1]))?(?:T(\d+))?$/;
        const match = gameCode.match(regex);
        if (match) {
            const shuffleFlag = match[5] !== undefined ? match[5] : '1';
            const timeStr = match[6] !== undefined ? match[6] : '0';
            self.shuffle = (shuffleFlag === '1');
            self.timeLimit = parseInt(timeStr, 10);
        }
        if (callback) callback(true);
    })
    .catch(error => {
        console.error('Error loading LID data:', error);
        if (callback) callback(false);
    });
};
/**
 * Generate comprehensive developer guide based on game code
 * @returns {string} Developer guide with implementation instructions
 */
SenaSDK.prototype.guide = function() {
    let self = this;
    const gameCode = self.gameCode || 'G2510S1T30';
    const data = self.data || {};

    /**
     * Regex giải thích:
     * ^G([1-5])([2-9])([0-2])([0-2]) : Bắt buộc (Loại, Số lượng, Q, O)
     * (?:S([0-1]))?                 : Không bắt buộc, mặc định S1
     * (?:T(\d+))?                   : Không bắt buộc, mặc định T0
     */
    const regex = /^G([1-5])([2-9])([0-2])([0-2])(?:S([0-1]))?(?:T(\d+))?$/;
    const match = gameCode.match(regex);

    if (!match) return "Mã game không hợp lệ! Định dạng chuẩn: Gxxxx hoặc GxxxxSxTxx";

    const category = match[1];
    const count = match[2];
    const qIdx = match[3];
    const oIdx = match[4];
    const shuffle = match[5] !== undefined ? match[5] : '1'; 
    const time = match[6] !== undefined ? match[6] : '0';    

    const types = { '0': 'Text', '1': 'Image', '2': 'Audio' };
    let guide = '';

    // Header
    guide += `╔════════════════════════════════════════════════════════════════════════════╗\n`;
    guide += `║              SENA SDK - DEVELOPER GUIDE: ${gameCode.padEnd(37)}║\n`;
    guide += `╚════════════════════════════════════════════════════════════════════════════╝\n\n`;

    // Game Analysis
    guide += `📊 GAME ANALYSIS\n`;
    guide += `━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n`;

    let gameName = '', instruction = '', displayMode = '';
    
    switch(category) {
        case '1':
            gameName = "Quiz (Trắc nghiệm)";
            instruction = `Người dùng chọn 1 đáp án đúng trong ${count} options`;
            displayMode = `Question: ${types[qIdx]} → Options: ${types[oIdx]}`;
            break;
        case '2':
            if (qIdx === '0' && oIdx === '0') {
                gameName = "Sort Word (Sắp xếp từ)";
                instruction = `Sắp xếp ${count} từ/ký tự thành chuỗi hoàn chỉnh`;
            } else {
                gameName = "Sequences (Sắp xếp chuỗi)";
                instruction = `Sắp xếp ${count} items theo đúng thứ tự`;
            }
            displayMode = `Hint: ${types[qIdx]} → Items: ${types[oIdx]}`;
            break;
        case '3':
            if (qIdx === oIdx) {
                gameName = "Memory Card (Trí nhớ)";
                instruction = `Lật và ghép ${count} cặp thẻ giống nhau`;
            } else {
                gameName = "Matching (Nối cặp)";
                instruction = `Nối ${count} items từ 2 nhóm với nhau`;
            }
            displayMode = `Group A: ${types[qIdx]} ↔ Group B: ${types[oIdx]}`;
            break;
    }

    guide += `Game Type    : ${gameName}\n`;
    guide += `Objective    : ${instruction}\n`;
    guide += `Display Mode : ${displayMode}\n`;
    guide += `Items Count  : ${count}\n`;
    guide += `Shuffle      : ${shuffle === '1' ? 'YES (call sdk.start() to shuffle)' : 'NO (S0)'}\n`;
    guide += `Time Limit   : ${time === '0' ? 'Unlimited' : time + ' seconds'}\n`;
    
    if (data.hint && data.hint.type) {
        guide += `Hint Type    : ${data.hint.type}\n`;
        guide += `Hint Count   : ${Array.isArray(data.hint.value) ? data.hint.value.length : '1'}\n`;
    }

    guide += `\n🔧 IMPLEMENTATION STEPS\n`;
    guide += `━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n\n`;

    // Step 1: Initialize
    guide += `1️⃣  INITIALIZE SDK\n`;
    guide += `   var sdk = new SenaSDK('${gameCode}');\n`;
    guide += `   sdk.load(function(success) {\n`;
    guide += `       if (success) sdk.start();\n`;
    guide += `   });\n\n`;

    // Step 2: Display based on game type
    guide += `2️⃣  DISPLAY UI\n`;
    
    if (category === '1') {
        // Quiz
        guide += `   // Display Question\n`;
        if (qIdx === '0') {
            guide += `   var questionText = sdk.getQuestionValue();\n`;
            guide += `   displayText(questionText); // Show text\n`;
        } else if (qIdx === '1') {
            guide += `   var questionImg = sdk.getQuestionValue();\n`;
            guide += `   displayImage(questionImg); // Show image URL\n`;
        } else if (qIdx === '2') {
            guide += `   sdk.playVoice('question'); // Auto play audio\n`;
        }
        
        guide += `\n   // Display Options\n`;
        guide += `   var optionsCount = sdk.getOptionsCount(); // ${count} items\n`;
        guide += `   for (var i = 0; i < optionsCount; i++) {\n`;
        if (oIdx === '0') {
            guide += `       var optionText = sdk.getOptionsValue(i).text;\n`;
            guide += `       createButton(optionText, i); // Show text button\n`;
        } else if (oIdx === '1') {
            guide += `       var optionImg = sdk.getOptionsValue(i).image;\n`;
            guide += `       createImageButton(optionImg, i); // Show image button\n`;
        } else if (oIdx === '2') {
            guide += `       createAudioButton(i); // Button to play audio\n`;
            guide += `       // onClick: sdk.playVoice('option' + (i+1));\n`;
        }
        guide += `   }\n`;
        
    } else if (category === '2') {
        // Sort/Sequences
        guide += `   // Display Hint (if exists)\n`;
        if (qIdx === '0') {
            guide += `   var hintText = sdk.getQuestionValue() || sdk.getRequestValue();\n`;
            guide += `   if (hintText) displayHint(hintText);\n`;
        } else if (qIdx === '1') {
            guide += `   var hintImg = sdk.getQuestionValue();\n`;
            guide += `   if (hintImg) displayHintImage(hintImg);\n`;
        }
        
        guide += `\n   // Display Draggable Items\n`;
        guide += `   var itemsCount = sdk.getOptionsCount();\n`;
        guide += `   for (var i = 0; i < itemsCount; i++) {\n`;
        if (oIdx === '0') {
            guide += `       var itemText = sdk.getOptionsValue(i).text;\n`;
            guide += `       createDraggableText(itemText, i);\n`;
        } else if (oIdx === '1') {
            guide += `       var itemImg = sdk.getOptionsValue(i).image;\n`;
            guide += `       createDraggableImage(itemImg, i);\n`;
        }
        guide += `   }\n`;
        guide += `   // User drags to reorder items\n`;
        
    } else if (category === '3') {
        // Memory/Matching
        guide += `   var itemsCount = sdk.getOptionsCount();\n`;
        if (qIdx === oIdx) {
            guide += `   // Memory Card - Create pairs\n`;
            guide += `   var allCards = []; // Duplicate items for pairs\n`;
            guide += `   for (var i = 0; i < itemsCount; i++) {\n`;
            guide += `       allCards.push(sdk.getOptionsValue(i));\n`;
            guide += `       allCards.push(sdk.getOptionsValue(i)); // Duplicate\n`;
            guide += `   }\n`;
            guide += `   shuffleArray(allCards);\n`;
            guide += `   // Create face-down cards, flip on click\n`;
        } else {
            guide += `   // Matching - Create two groups\n`;
            guide += `   for (var i = 0; i < itemsCount; i++) {\n`;
            if (qIdx === '0') {
                guide += `       var leftText = sdk.getOptionsValue(i).text;\n`;
                guide += `       createLeftItem(leftText, i);\n`;
            } else if (qIdx === '1') {
                guide += `       var leftImg = sdk.getOptionsValue(i).image;\n`;
                guide += `       createLeftItem(leftImg, i);\n`;
            }
            if (oIdx === '0') {
                guide += `       var rightText = sdk.getOptionsValue(i).text; // Matching pair\n`;
                guide += `       createRightItem(rightText, i);\n`;
            } else if (oIdx === '1') {
                guide += `       var rightImg = sdk.getOptionsValue(i).image;\n`;
                guide += `       createRightItem(rightImg, i);\n`;
            }
            guide += `   }\n`;
            guide += `   // User draws lines to match pairs\n`;
        }
    }

    // Step 3: Handle Hint
    if (data.hint && data.hint.type) {
        guide += `\n3️⃣  HANDLE HINT (Optional)\n`;
        guide += `   var hintType = sdk.getHintType(); // "${data.hint.type}"\n`;
        if (data.hint.type === 'display') {
            guide += `   var hintCount = sdk.getHintCount();\n`;
            guide += `   for (var i = 0; i < hintCount; i++) {\n`;
            guide += `       var hintItem = sdk.getHintValue(i);\n`;
            guide += `       displayHintItem(hintItem, i); // Show each hint\n`;
            guide += `   }\n`;
        } else if (data.hint.type === 'audio') {
            guide += `   var hintAudio = sdk.getHintValue();\n`;
            guide += `   createHintButton(hintAudio); // Play audio hint\n`;
        } else if (data.hint.type === 'text') {
            guide += `   var hintText = sdk.getHintValue();\n`;
            guide += `   displayHintText(hintText);\n`;
        }
    }

    // Step 4: Check Answer
    const stepNum = data.hint ? '4️⃣' : '3️⃣';
    guide += `\n${stepNum}  CHECK ANSWER\n`;
    
    if (category === '1') {
        guide += `   // User clicks an option\n`;
        guide += `   function onOptionClick(selectedIndex) {\n`;
        guide += `       var userAnswer = sdk.getOptionsValue(selectedIndex).text;\n`;
        guide += `       var result = sdk.end(userAnswer, function(isCorrect) {\n`;
        guide += `           if (isCorrect) showSuccess();\n`;
        guide += `           else showError();\n`;
        guide += `       });\n`;
        guide += `   }\n`;
    } else if (category === '2') {
        guide += `   // User finishes sorting\n`;
        guide += `   function onSubmitOrder(orderedArray) {\n`;
        guide += `       var answerStr = orderedArray.map(item => item.text).join('|');\n`;
        guide += `       sdk.end(answerStr, function(isCorrect) {\n`;
        guide += `           if (isCorrect) showSuccess();\n`;
        guide += `           else showCorrectOrder();\n`;
        guide += `       });\n`;
        guide += `   }\n`;
    } else if (category === '3') {
        guide += `   // User completes all matches/pairs\n`;
        guide += `   function onAllMatched(matchedPairs) {\n`;
        guide += `       var answerStr = matchedPairs.map(p => p.text).join('|');\n`;
        guide += `       sdk.end(answerStr, function(isCorrect) {\n`;
        guide += `           showResult(isCorrect);\n`;
        guide += `       });\n`;
        guide += `   }\n`;
    }

    // Step 5: Timer
    if (time !== '0') {
        const nextStep = data.hint ? '5️⃣' : '4️⃣';
        guide += `\n${nextStep}  TIMER COUNTDOWN\n`;
        guide += `   var timeLimit = sdk.timeLimit; // ${time} seconds\n`;
        guide += `   startCountdown(timeLimit);\n`;
        guide += `   // If time runs out before sdk.end(), user fails\n`;
    }

    // API Reference
    guide += `\n\n📚 KEY API METHODS\n`;
    guide += `━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n`;
    guide += `sdk.load(callback, template)     - Load data from server\n`;
    guide += `sdk.start()                       - Start game, shuffle if needed\n`;
    guide += `sdk.getQuestionValue()            - Get question text/image/audio\n`;
    guide += `sdk.getQuestionType()             - Get question type (text/image/audio)\n`;
    guide += `sdk.getOptionsCount()             - Get number of options\n`;
    guide += `sdk.getOptionsValue(index)        - Get option object at index\n`;
    guide += `sdk.getOptionsType()              - Get options type\n`;
    guide += `sdk.getHintType()                 - Get hint type\n`;
    guide += `sdk.getHintValue(index)           - Get hint value/array item\n`;
    guide += `sdk.getHintCount()                - Get hint items count\n`;
    guide += `sdk.playVoice(type)               - Play TTS (question/option1/hint)\n`;
    guide += `sdk.end(answer, callback)         - Check answer & return result\n`;
    guide += `sdk.timeLimit                     - Time limit in seconds\n`;
    guide += `sdk.shuffle                       - Whether to shuffle options\n`;

    guide += `\n\n💡 TIPS\n`;
    guide += `━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n`;
    if (shuffle === '1') {
        guide += `• Options are shuffled after sdk.start() - display in new order\n`;
    }
    if (time !== '0') {
        guide += `• Implement timer UI and auto-submit when time expires\n`;
    }
    guide += `• Use Web Speech API: sdk.playVoice() for TTS in English\n`;
    guide += `• Multiple answers format: "answer1|answer2|answer3"\n`;
    guide += `• sdk.end() returns: {isCorrect, duration, correctAnswer, userAnswer}\n`;
    
    guide += `\n${'═'.repeat(76)}\n`;

    return guide;
};
/**
 * Get the question text
 * @returns {string} Question or request text
 */
SenaSDK.prototype.getQuestionValue = function() {
    if (this.data.question && this.data.question !== "") {
        return this.data.question;
    } else {
        return "";
    }
};
/**
 * Get the question type
 * @returns {string} Question type (text, image, audio)
 */
SenaSDK.prototype.getQuestionType = function() {
    let self = this;
    // based on game code, determine question type
    const gameCode = self.gameCode || 'G2510S1T30';
    const regex = /^G([1-5])([2-9])([0-2])([0-2])(?:S([0-1]))?(?:T(\d+))?$/;
    const match = gameCode.match(regex);
    if (match) {
        const qIdx = match[3];
        const types = { '0': 'text', '1': 'image', '2': 'audio' };
        return types[qIdx] || 'text';
    }
    return 'text';
};

/**
 * Get the request value
 * @returns {string} Request text
 */
SenaSDK.prototype.getRequestValue = function() {
    if (this.data && this.data.request && this.data.request !== "") {
        return this.data.request;
    } else {
        return "";
    }
};

/**
 * Get the request type (same as question type)
 * @returns {string} Request type (text, image, audio)
 */
SenaSDK.prototype.getRequestType = function() {
    return this.getQuestionType();
};

/**
 * Get total number of options
 * @returns {number} Number of options
 */
SenaSDK.prototype.getOptionsCount = function() {
    return this.data.options.length;
};

/**
 * Get options type based on game code
 * @returns {string} Options type (text, image, audio)
 */
SenaSDK.prototype.getOptionsType = function() {
    let self = this;
    // based on game code, determine options type
    const gameCode = self.gameCode || 'G2510S1T30';
    const regex = /^G([1-5])([2-9])([0-2])([0-2])(?:S([0-1]))?(?:T(\d+))?$/;
    const match = gameCode.match(regex);
    if (match) {
        const oIdx = match[4];
        const types = { '0': 'text', '1': 'image', '2': 'audio' };
        return types[oIdx] || 'text';
    }
    return 'text';
};
/**
 * Get option value by index based on options type from game code
 * @param {number} index - Option index
 * @returns {string} Option value (text, image URL, or audio URL based on game code)
 */
SenaSDK.prototype.getOptionsValue = function(index) {
    return this.data.options[index];
};

/**
 * Get hint type
 * @returns {string} Hint type (e.g., 'display', 'audio', 'text', or empty string if no hint)
 */
SenaSDK.prototype.getHintType = function() {
    if (this.data && this.data.hint && this.data.hint.type) {
        return this.data.hint.type;
    }
    return "";
};

/**
 * Get hint count (number of elements if hint is an array, particularly for display type)
 * @returns {number} Number of elements in hint array, or 1 if not an array, or 0 if no hint
 */
SenaSDK.prototype.getHintCount = function() {
    const hintValue = this.getHintValue();
    if (hintValue === null) {
        return 0;
    }
    if (Array.isArray(hintValue)) {
        return hintValue.length;
    }
    return 1;
};

/**
 * Get hint value
 * @param {number} index - Optional index for array hints (display type)
 * @returns {*} Hint value (string, array element, or null if no hint)
 */
SenaSDK.prototype.getHintValue = function(index) {
    if (this.data && this.data.hint && this.data.hint.value !== undefined) {
        const hintValue = this.data.hint.value;
        const hintType = this.getHintType();
        
        // If hint type is display and value is array, return specific index
        if (hintType === 'display' && Array.isArray(hintValue)) {
            if (index !== undefined && index >= 0 && index < hintValue.length) {
                return hintValue[index];
            }
            // If no index provided or invalid, return the whole array
            return hintValue;
        }
        
        // For audio or text type, return the value directly
        return hintValue;
    }
    return null;
};

/**
 * Start the quiz - resets index and shuffles options
 */
SenaSDK.prototype.start = function() {
    let self = this;
    self.curIndex = 0;
    if (self.shuffle) {
        self.shuffleArray(self.data.options);
    }
    self.startTime = Date.now();
    // Additional logic for tracking can be added here if needed
};
/**
 * End the game and check answer
 * @param {string} answer - User's answer (single text or multiple answers separated by |)
 * @returns {Object} Result object with isCorrect, duration, correctAnswer, and userAnswer
 */
SenaSDK.prototype.end = function(answer , callback) {
    let self = this;
    self.endTime = Date.now();
    const duration = (self.endTime - self.startTime) / 1000;
    
    // Parse user answer - split by | for multiple answers
    const userAnswers = answer.includes('|') ? answer.split('|').map(a => a.trim().toLowerCase()) : [answer.trim().toLowerCase()];
    
    // Get correct answer(s) from data
    let correctAnswers = [];
    if (self.correctAnswer) {
        // Check if answer is an array (multiple answers) or single answer
        if (Array.isArray(self.correctAnswer)) {
            correctAnswers = self.correctAnswer.map(a => {
                if (typeof a === 'string') return a.toLowerCase();
                if (a.text) return a.text.toLowerCase();
                return '';
            });
        } else if (typeof self.correctAnswer === 'string') {
            correctAnswers = [self.correctAnswer.toLowerCase()];
        } else if (self.correctAnswer.text) {
            correctAnswers = [self.correctAnswer.text.toLowerCase()];
        }
    }
    
    // Check if answer is correct
    let isCorrect = false;
    if (userAnswers.length === correctAnswers.length) {
        // For ordered multiple answers
        isCorrect = userAnswers.every((ans, index) => ans === correctAnswers[index]);
    } else if (userAnswers.length === 1 && correctAnswers.length === 1) {
        // For single answer
        isCorrect = userAnswers[0] === correctAnswers[0];
    }
    
    const result = {
        isCorrect: isCorrect,
        duration: duration,
        correctAnswer: correctAnswers.join(' | '),
        userAnswer: userAnswers.join(' | ')
    };
    // if time spent more than time limit, mark as incorrect
    if (self.timeLimit > 0 && duration > self.timeLimit) {
        result.isCorrect = false;
    }
    console.log(`Time spent in game: ${duration} seconds`);
    console.log(`Result: ${isCorrect ? 'CORRECT' : 'INCORRECT'}`);
    if (callback) callback(result.isCorrect);
};

SenaSDK.prototype.playVoice = function(type) {
    let self = this;
    // type: 'question', 'optionA', 'optionB', ...
    // if type is options, get corresponding option text like option0 -> index 0
    let textToSpeak = '';
    if (type.startsWith('option')) {
        const optionIndex = parseInt(type.slice(6)) - 1;
        textToSpeak = self.getOptionsValue(optionIndex);
    } else if (type === 'question') {
        textToSpeak = self.getQuestionValue();
    } else if (type === 'request') {
        textToSpeak = self.getRequestValue();
    } else if (type === 'hint') {
        const hintValue = self.getHintValue();
        if (typeof hintValue === 'string') {
            textToSpeak = hintValue;
        }
    }
    if(textToSpeak == "") return;
    if (window['audioPlayer']) {
        window['audioPlayer'].pause();
        window['audioPlayer'].src = textToSpeak;
        window['audioPlayer'].play();
    } else {
        window['audioPlayer'] = new Audio(textToSpeak);
        window['audioPlayer'].play();
    }
};

SenaSDK.prototype.helper = {};

SenaSDK.prototype.helper.CalcObjectPositions = function(n, objectWidth, margin, maxWidth) {
    let self = this;
    self.positions = [];
    const totalWidth = n * objectWidth + (n - 1) * margin;
    const startX = (maxWidth - totalWidth) / 2;
    let positions = [];
    for (let i = 0; i < n; i++) {
        positions.push(startX + i * (objectWidth + margin));
    }
    positions.map(pos => pos + objectWidth / 2); // Adjusting to center the objects
    self.positions = positions;
};
SenaSDK.prototype.helper.getPosXbyIndex = function(index) {
    let self = this;
    if (index < 0 || index >= self.positions.length) {
        return null; // Return null if index is out of bounds
    }
    return self.positions[index];
};  
// Export for different module systems
if (typeof module !== 'undefined' && module.exports) {
    module.exports = SenaSDK;
} else if (typeof define === 'function' && define.amd) {
    define([], function() { return SenaSDK; });
} else {
    window.SenaSDK = SenaSDK;
}