/**
 * 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)
  };

  // Multi-question support (from postMessage)
  this.list = [];
  this.currentQuestion = null;
  this.level = 0;
  this.totalQuestions = 0;
  this.userResults = [];
  this.gameID = null;
  this.userId = null;
  this.postMessageDataLoaded = false;
  this.isMatchingGame = false; // true nếu là game matching (G3xxx)

  // PostMessage listener tracking
  this._postMessageListenerRegistered = false;
  this._waitingForPostMessage = false;
  this._postMessageTimeout = null;
  this._loadCallback = null;

  // Game interaction tracking - để biết có thể reload data không
  this._gameStartedByUser = false; // true khi user đã tương tác (click, drag, etc.)
  this._dataLoadedFromServer = false; // true nếu data từ server (không phải postMessage)

  // ========== MODE SUPPORT ==========
  // 'live'    - Chờ vô hạn cho postMessage từ server (production)
  // 'preview' - Timeout 5s rồi fallback sample (testing với data thật)
  // 'dev'     - Load sample ngay lập tức (development)
  this.mode = "preview"; // Default mode
}

/**
 * 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]];
  }
};

/**
 * Load data từ postMessage (SERVER_PUSH_DATA)
 * Game type được xác định từ gameCode:
 * - G1xxx = Quiz (trắc nghiệm)
 * - G2xxx = Sort (sắp xếp)
 * - G3xxx = Match (nối cặp) -> forward to tdv_sdk
 * - G4xxx = Fill (điền từ)
 * - G5xxx = Custom
 *
 * Data format:
 * {
 *   gameCode: "G1400S1T30",  // Bắt buộc - xác định loại game
 *   data: { request, question, options: [] },
 *   answer: "..."
 * }
 */
SenaSDK.prototype.loadFromPostMessage = function (inputJson, callback) {
  let self = this;

  if (!inputJson) {
    console.error("🎮 Sena SDK: No data in postMessage");
    if (callback) callback(false);
    return false;
  }

  console.log("📦 Sena SDK: Loading from PostMessage:", inputJson);

  // ========== DETECT GAME TYPE TỪ GAMECODE ==========
  let gameCode = inputJson.gameCode || self.gameCode;
  let gameCategory = gameCode.charAt(1); // G[category]xxx - 1=Quiz, 2=Sort, 3=Match, 4=Fill, 5=Custom

  console.log("🎮 Sena SDK: GameCode:", gameCode, "| Category:", gameCategory);

  // ========== MATCHING GAME (G3xxx) ==========
  // Chuyển tiếp cho tdv_sdk xử lý
  if (gameCategory === "3") {
    console.log(
      "🎯 Sena SDK: Detected MATCHING GAME (G3xxx), forwarding to tdv_sdk...",
    );

    // Lưu thông tin cơ bản
    self.gameCode = gameCode;
    self.gameID = gameCode;
    self.postMessageDataLoaded = true;
    self.isMatchingGame = true;
    self._dataLoadedFromServer = false; // Data từ postMessage, không phải server

    // Forward data cho tdv_sdk nếu có
    if (window.tdv_sdk) {
      window.tdv_sdk.loadFromPostMessage(inputJson, callback);
      console.log("✅ Sena SDK: Forwarded to tdv_sdk");
    } else {
      console.warn("⚠️ Sena SDK: tdv_sdk not found, storing data locally");
      self.data = inputJson.data;
      self.correctAnswer = inputJson.answer;
      if (callback) callback(true);
    }
    return true;
  }

  // ========== QUIZ / SORT / FILL / CUSTOM (G1, G2, G4, G5) ==========
  // Single question format: có gameCode và data (không phải array)
  let isSingleQuestion =
    inputJson.gameCode && inputJson.data && !Array.isArray(inputJson.data);

  if (isSingleQuestion) {
    // ========== SINGLE QUESTION (SenaSDK format) ==========
    console.log("🎯 Sena SDK: Detected SINGLE QUESTION format");

    self.gameCode = inputJson.gameCode || self.gameCode;
    self.gameID = inputJson.gameCode;

    // Parse game code để lấy settings
    self._parseGameCode();

    // Set data trực tiếp
    self.data = {
      question: inputJson.data.question || "",
      request: inputJson.data.request || "",
      options: inputJson.data.options || [],
      image: inputJson.data.image || "",
      audio: inputJson.data.audio || "",
      hint: inputJson.data.hint || null,
    };

    // --- [UPDATE G5] Khởi tạo Master List cho G5 ---
    if (self.gameType === 5 && self.data && self.data.options) {
      // Lưu trữ danh sách gốc
      self.masterList = [...self.data.options];
      // Tính tổng số level
      self.totalLevels = Math.ceil(self.masterList.length / self.itemCount);
      self.currentLevel = 0;

      // Load Level 1 ngay lập tức để self.data.options chỉ chứa 6 card đầu
      self.loadLevelG5(1);
    }

    self.correctAnswer = inputJson.answer;

    // Cũng set vào list để hỗ trợ multi-question API
    self.list = [
      {
        id: "Q1",
        question: inputJson.data.question,
        request: inputJson.data.request,
        options: inputJson.data.options,
        answer: inputJson.answer,
        image: inputJson.data.image,
        audio: inputJson.data.audio,
      },
    ];
    self.totalQuestions = 1;
    self.level = 0;
    self.currentQuestion = self.list[0];
    self.userResults = [];

    // [UPDATE G4] Process G4 Data
    if (self.gameType === 4) self._processG4Data();

    console.log(
      "✅ Sena SDK: Single question loaded -",
      inputJson.description || inputJson.data.question,
    );
  } else {
    // ========== MULTI-QUESTION (Exam mode) ==========
    console.log("📋 Sena SDK: Detected MULTI-QUESTION format");

    // Lưu thông tin game
    self.gameID = inputJson.game_id || "quiz_game";
    self.userId = inputJson.user_id || "guest";

    // Lưu danh sách câu hỏi
    self.list = inputJson.data || inputJson.questions || [];
    self.totalQuestions = self.list.length;

    // Xử lý thời gian
    if (inputJson.total_time) {
      self.timeLimit = parseInt(inputJson.total_time, 10);
    }

    if (inputJson.end_time_iso) {
      let endTimeDate = new Date(inputJson.end_time_iso);
      let now = new Date();
      self.timeLimit = Math.max(0, Math.floor((endTimeDate - now) / 1000));
    }

    // Xử lý resume (câu hỏi đã hoàn thành)
    let completedData = inputJson.completed_question_ids || [];
    self.userResults = [];
    let resumeLevel = 0;

    for (let i = 0; i < self.list.length; i++) {
      let done = completedData.find(
        (item) => (item.id || item) === self.list[i].id,
      );
      if (done) {
        self.userResults.push({
          id: self.list[i].id,
          result: done.result !== undefined ? done.result : 0,
        });
        resumeLevel = i + 1;
      } else {
        resumeLevel = i;
        break;
      }
    }

    self.level = Math.min(resumeLevel, self.totalQuestions - 1);

    // Load câu hỏi đầu tiên và convert sang định dạng SenaSDK
    self._loadCurrentQuestionToData();

    console.log("✅ Sena SDK: Loaded", self.totalQuestions, "questions");
  }

  self.postMessageDataLoaded = true;

  if (callback) callback(true);
  return true;
};

/**
 * [UPDATED] Parse game code để lấy settings
 * Cho phép G1-G9 (thay vì G1-G5)
 */
SenaSDK.prototype._parseGameCode = function () {
  let self = this;
  const gameCode = self.gameCode || "G4410S1T30"; // G4 mẫu

  // Regex hỗ trợ G1-G9
  const regex = /^G([1-9])(\d{1,2})([0-2])([0-2])(?:S([0-1]))?(?:T(\d+))?$/;
  let match = gameCode.match(regex);

  if (match) {
    self.gameType = parseInt(match[1], 10);
    self.itemCount = parseInt(match[2], 10);
    self.questionType = parseInt(match[3], 10);
    self.optionType = parseInt(match[4], 10);
    const shuffleFlag = match[5] !== undefined ? match[5] : "1";
    const timeStr = match[6] !== undefined ? match[6] : "0";
    self.shuffle = shuffleFlag === "1";
    // --- [UPDATE G5] Logic Time Per Card ---
    if (self.gameType === 5) {
      self.timePerCard = parseInt(timeStr, 10); // T5 = 5s mỗi card
      self.timeLimit = 0; // G5 không giới hạn tổng thời gian
    } else {
      self.timeLimit = parseInt(timeStr, 10);
      self.timePerCard = 0;
    }
  }
};

/**
 * Load câu hỏi hiện tại vào this.data
 */
SenaSDK.prototype._loadCurrentQuestionToData = function () {
  let self = this;

  if (self.list.length > 0 && self.level < self.list.length) {
    self.currentQuestion = self.list[self.level];

    // Convert sang định dạng SenaSDK chuẩn
    self.data = {
      question: self.currentQuestion.question || "",
      request: self.currentQuestion.request || "",
      options: self.currentQuestion.options || [],
      image: self.currentQuestion.image || "",
      audio: self.currentQuestion.audio || "",
    };
    self.correctAnswer = self.currentQuestion.answer;
  }
};

/**
 * Chuyển sang câu hỏi tiếp theo (multi-question mode)
 */
SenaSDK.prototype.nextQuestion = function () {
  let self = this;

  if (self.level < self.totalQuestions - 1) {
    self.level++;
    self._loadCurrentQuestionToData();
    console.log(
      "🎮 Sena SDK: Next Question:",
      self.level + 1,
      "/",
      self.totalQuestions,
    );
    return true;
  }

  console.log("🎮 Sena SDK: No more questions");
  return false;
};

/**
 * Lấy số câu hỏi hiện tại (1-indexed)
 */
SenaSDK.prototype.getCurrentNumber = function () {
  return this.level + 1;
};

/**
 * Lấy tổng số câu hỏi
 */
SenaSDK.prototype.getTotalQuestions = function () {
  return this.totalQuestions || 1;
};

// Settings cho postMessage waiting
SenaSDK.prototype.POSTMESSAGE_TIMEOUT_MS = 1000; // 5 giây (chỉ dùng cho preview mode)

SenaSDK.prototype.load = function (callback, template = "G2510S1T30") {
  let self = this;

  // *** AUTO-REGISTER postMessage listener (chỉ 1 lần) ***
  if (!self._postMessageListenerRegistered) {
    self.registerPostMessageListener();
    self._postMessageListenerRegistered = true;
  }

  // Nếu đã có data từ postMessage, không cần load lại
  if (self.postMessageDataLoaded && self.list.length > 0) {
    console.log("🎮 Sena SDK: Data already loaded from postMessage");
    if (callback) callback(true);
    return;
  }

  // Nếu đã có data (từ bất kỳ nguồn nào), không cần load lại
  if (self.data && self.data.options) {
    console.log("🎮 Sena SDK: Data already available");
    if (callback) callback(true);
    return;
  }

  // ========== GET URL PARAMETERS ==========
  const urlParams = new URLSearchParams(window.location.search);

  // Get LID (game code) from URL
  const LID = urlParams.get("LID");
  if (LID) {
    self.gameCode = LID;
  }

  // Get MODE from URL: ?mode=live | ?mode=preview | ?mode=dev
  const urlMode = urlParams.get("mode");
  if (urlMode && ["live", "preview", "dev"].includes(urlMode.toLowerCase())) {
    self.mode = urlMode.toLowerCase();
  }

  console.log(
    "🎮 Sena SDK: Mode =",
    self.mode.toUpperCase(),
    "| GameCode =",
    self.gameCode,
  );

  // Lưu callback để gọi sau
  self._loadCallback = callback;

  // ========== MODE-BASED LOADING ==========
  switch (self.mode) {
    case "live":
      // LIVE MODE: Chờ vô hạn cho postMessage từ server
      self._waitingForPostMessage = true;
      console.log(
        "⏳ Sena SDK: [LIVE MODE] Waiting for server data via postMessage (no timeout)...",
      );
      // Không set timeout - chờ vô hạn
      // Gửi GAME_READY để server biết game sẵn sàng nhận data
      self._sendGameReady();
      break;

    case "dev":
      // DEV MODE: Load sample data ngay lập tức
      console.log("🔧 Sena SDK: [DEV MODE] Loading sample data immediately...");
      self._waitingForPostMessage = false;
      self._loadFromServer(callback, template);
      break;

    case "preview":
    default:
      // PREVIEW MODE: Timeout 5s rồi fallback sample
      self._waitingForPostMessage = true;
      console.log(
        "⏳ Sena SDK: [PREVIEW MODE] Waiting for postMessage (" +
          self.POSTMESSAGE_TIMEOUT_MS / 1000 +
          "s timeout)...",
      );

      // Set timeout để fallback load từ server
      self._postMessageTimeout = setTimeout(function () {
        if (self._waitingForPostMessage && !self.postMessageDataLoaded) {
          console.warn(
            "⚠️ Sena SDK: No postMessage received, fallback to sample data...",
          );
          self._loadFromServer(self._loadCallback, template);
        }
      }, self.POSTMESSAGE_TIMEOUT_MS);
      break;
  }
};

/**
 * Gửi GAME_READY message cho parent window
 * Để server biết game đã sẵn sàng nhận data
 */
SenaSDK.prototype._sendGameReady = function () {
  let self = this;
  window.parent.postMessage(
    {
      type: "GAME_READY",
      payload: {
        game_id: self.gameID || self.gameCode,
        game_code: self.gameCode,
        mode: self.mode,
      },
    },
    "*",
  );
  console.log("📤 Sena SDK: Sent GAME_READY to parent");
};

/**
 * Fallback: Load data từ server khi không có postMessage
 */
SenaSDK.prototype._loadFromServer = function (
  callback,
  template = "G2510S1T30",
) {
  let self = this;
  self._waitingForPostMessage = false;

  const validation = self.validateGameCode(self.gameCode);
  if (!validation.valid) {
    console.warn("🎮 Sena SDK: " + validation.error);
  }

  console.log("📡 Sena SDK: Fallback loading from server...");

  fetch(`https://senaai.tech/sample/${self.gameCode}.json`)
    .then((response) => response.json())
    .then((data) => {
      self.data = data.data;
      self.correctAnswer = data.answer || null;
      const gameCode = self.gameCode || template;

      // FIX: Regex chấp nhận 2 chữ số cho Count
      const strictRegex =
        /^G([1-9])(\d{1,2})([0-2])([0-2])(?:S([0-1]))?(?:T(\d+))?$/;
      let match = gameCode.match(strictRegex);

      if (match) {
        self.gameType = parseInt(match[1], 10);
        self.itemCount = parseInt(match[2], 10);
        self.questionType = parseInt(match[3], 10);
        self.optionType = parseInt(match[4], 10);
        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);

        console.log("🎮 Sena SDK: ✓ Valid game code parsed:", {
          type: self.gameType,
          count: self.itemCount,
          time: self.timeLimit,
        });
      } else {
        console.error(
          "🎮 Sena SDK: ✗ Cannot parse game code (Strict match failed):",
          gameCode,
        );
        // Fallback safe mode
        self.shuffle = true;
        // Nếu load được file json thì ta cứ tin tưởng lấy time trong đó nếu có, hoặc default 30s
        self.timeLimit = 30;
      }
      // Mục đích: Tráo vị trí data ngay lập tức sau khi load xong
      if (self.shuffle && self.data && self.data.options) {
        self.shuffleArray(self.data.options);
        console.log("🎮 Sena SDK: Data shuffled immediately on load");
      }

      // --- [UPDATE G5] Khởi tạo Master List cho G5 ---
      if (self.gameType === 5 && self.data && self.data.options) {
        // Lưu trữ danh sách gốc
        self.masterList = [...self.data.options];
        // Tính tổng số level
        self.totalLevels = Math.ceil(self.masterList.length / self.itemCount);
        self.currentLevel = 0;

        // Load Level 1 ngay lập tức để self.data.options chỉ chứa 6 card đầu
        self.loadLevelG5(1);
      }

      // [UPDATE G4] Process G4 Data
      if (self.gameType === 4) self._processG4Data();

      console.log("🎮 Sena SDK: Data loaded for", self.gameCode);
      self._dataLoadedFromServer = true;
      if (callback) callback(true);
    })
    .catch((error) => {
      console.error("🎮 Sena SDK: Error loading data:", error);
      if (callback) callback(false);
    });
};

/**
 * Validate game code format
 * @param {string} code - Game code to validate
 * @returns {Object} Validation result with valid flag and parsed values
 */
SenaSDK.prototype.validateGameCode = function (code) {
  code = code || this.gameCode;

  // Format: G[type][count][qType][oType]S[shuffle]T[time]
  // type: 1=Quiz, 2=Sort, 3=Match/Memory, 4=Fill, 5=Custom
  // count: 2-9
  // qType/oType: 0=Text, 1=Image, 2=Audio
  const regex = /^G([1-9])(\d{1,2})([0-2])([0-2])(?:S([0-1]))?(?:T(\d+))?$/;
  const match = code.match(regex);

  if (!match) {
    // Check what's wrong
    let error = "Invalid game code format";
    const looseMatch = code.match(/^G([0-9])(\d{1,2})([0-9])([0-9])/);

    if (looseMatch) {
      const issues = [];
      // QUAN TRỌNG: Sửa '5' thành '9' ở dòng dưới đây
      if (looseMatch[1] < "1" || looseMatch[1] > "9")
        issues.push("type must be 1-9");
      if (looseMatch[2] < "2" || looseMatch[2] > "9")
        issues.push("count must be 2-9");
      if (looseMatch[3] > "2")
        issues.push("qType must be 0-2 (0=Text, 1=Image, 2=Audio)");
      if (looseMatch[4] > "2")
        issues.push("oType must be 0-2 (0=Text, 1=Image, 2=Audio)");
      if (issues.length > 0) error = issues.join(", ");
    }

    return { valid: false, error: error, code: code };
  }

  return {
    valid: true,
    code: code,
    type: parseInt(match[1], 10),
    count: parseInt(match[2], 10),
    qType: parseInt(match[3], 10),
    oType: parseInt(match[4], 10),
    shuffle: match[5] !== "0",
    time: match[6] ? parseInt(match[6], 10) : 0,
    description: this.getGameCodeDescription(match),
  };
};

/**
 * Get human-readable description of game code
 */
SenaSDK.prototype.getGameCodeDescription = function (match) {
  if (!match) return "";

  const types = {
    1: "Quiz",
    2: "Sort/Sequence",
    3: "Match/Memory",
    4: "Fill",
    5: "Custom",
  };
  const contentTypes = ["Text", "Image", "Audio"];

  const gameType = types[match[1]] || "Unknown";
  const qType = contentTypes[parseInt(match[3])] || "Unknown";
  const oType = contentTypes[parseInt(match[4])] || "Unknown";

  return `${gameType}: ${match[2]} items, ${qType} → ${oType}`;
};
/**
 * 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-9])([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/url
 * @returns {string} Question, request text, or URL
 */
SenaSDK.prototype.getQuestionValue = function () {
  var q = String(this.data.question || "").trim();
  // Đã bỏ chặn URL để có thể lấy link ảnh/audio
  return q;
};
/**
 * 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-9])([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";
};

/**
 * [UPDATE] Get the question image URL
 * Dùng cho G4 khi cần hiển thị song song cả Text (getQuestionValue) và Image
 * @returns {string} Image URL
 */
SenaSDK.prototype.getQuestionImage = function () {
  if (this.data && this.data.image) {
    return String(this.data.image).trim();
  }
  return "";
};

/**
 * 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 () {
  if (this.data && this.data.options) {
    return this.data.options.length;
  }
  return 0;
};

/**
 * 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-9])([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;

  // Nếu là matching game, forward sang tdv_sdk.start()
  if (self.isMatchingGame) {
    console.log("🎮 Sena SDK: Matching game - forwarding start() to tdv_sdk");
    if (window.tdv_sdk && typeof window.tdv_sdk.start === "function") {
      window.tdv_sdk.start();
    }
    return;
  }

  // Quiz/Sort/Fill games
  self.curIndex = 0;
  if (self.shuffle && self.data && self.data.options) {
    self.shuffleArray(self.data.options);
  }
  self.startTime = Date.now();
  // Additional logic for tracking can be added here if needed
};

/**
 * Đánh dấu user đã tương tác với game
 * Gọi hàm này từ Construct khi user click/drag lần đầu
 * Sau khi gọi, postMessage muộn sẽ bị bỏ qua
 */
SenaSDK.prototype.markUserInteraction = function () {
  if (!this._gameStartedByUser) {
    this._gameStartedByUser = true;
    console.log(
      "🎮 Sena SDK: User interaction detected - late postMessage will be ignored",
    );

    // Cũng đánh dấu cho tdv_sdk nếu là matching game
    if (this.isMatchingGame && window.tdv_sdk) {
      window.tdv_sdk._gameStartedByUser = true;
    }
  }
};

/**
 * Kiểm tra xem có thể reload data không (user chưa tương tác)
 */
SenaSDK.prototype.canReloadData = function () {
  return !this._gameStartedByUser;
};

/**
 * End the game and check answer
 * [UPDATE] Support Unordered Answers & Auto-cleanup empty strings
 */
SenaSDK.prototype.end = function (answer, callback) {
  let self = this;

  // ========== MATCHING GAME: Forward to tdv_sdk ==========
  if (self.isMatchingGame && window.tdv_sdk) {
    console.log("🎮 Sena SDK: Matching game - forwarding end() to tdv_sdk");

    // Lấy kết quả từ tdv_sdk
    let isCorrect = window.tdv_sdk.isCorrect() === 1;
    let duration = window.tdv_sdk.getTimeSpent();
    let correctCount = window.tdv_sdk.getCorrectCount();
    let totalPairs = window.tdv_sdk.pairCount;

    console.log(`Time spent in game: ${duration} seconds`);
    console.log(
      `Result: ${correctCount}/${totalPairs} correct - ${isCorrect ? "CORRECT" : "INCORRECT"}`,
    );

    if (callback) callback(isCorrect);
    return {
      isCorrect: isCorrect,
      duration: duration,
      correctCount: correctCount,
      totalPairs: totalPairs,
    };
  }

  // ========== QUIZ/SORT/FILL GAMES ==========
  self.endTime = Date.now();
  const duration = (self.endTime - self.startTime) / 1000;

  // 1. CLEANUP INPUT: Tách chuỗi, Xóa khoảng trắng, Chuyển thường, LỌC BỎ RỖNG
  // .filter(a => a) sẽ loại bỏ ngay cái đuôi "" do dấu | thừa tạo ra
  const userAnswers = answer.includes("|")
    ? answer
        .split("|")
        .map((a) => a.trim().toLowerCase())
        .filter((a) => a)
    : [answer.trim().toLowerCase()].filter((a) => a);

  // 2. GET CORRECT ANSWERS
  let correctAnswers = [];
  if (self.correctAnswer) {
    if (Array.isArray(self.correctAnswer)) {
      correctAnswers = self.correctAnswer.map((a) =>
        (typeof a === "object" ? a.text || "" : String(a)).trim().toLowerCase(),
      );
    } else {
      let str =
        typeof self.correctAnswer === "object"
          ? self.correctAnswer.text
          : String(self.correctAnswer);
      correctAnswers = str.includes("|")
        ? str.split("|").map((a) => a.trim().toLowerCase())
        : [str.trim().toLowerCase()];
    }
  }

  // 3. COMPARE
  // Nếu là Game Type 2 (Sort) thì giữ nguyên thứ tự, nếu không thì sort (unordered)
  const isStrictOrder = self.gameType === 2;
  const finalUser = isStrictOrder ? [...userAnswers] : [...userAnswers].sort();
  const finalCorrect = isStrictOrder
    ? [...correctAnswers]
    : [...correctAnswers].sort();

  let isCorrect = false;

  // Helper check file name for URL matching
  const getFileName = (url) => {
    if (!url.startsWith("http")) return url;
    try {
      return url.split("/").pop().split("?")[0];
    } catch (e) {
      return url;
    }
  };

  if (finalUser.length === finalCorrect.length) {
    isCorrect = finalUser.every((uVal, index) => {
      let cVal = finalCorrect[index];
      if (uVal === cVal) return true;
      // Fuzzy match cho URL (so sánh tên file ảnh)
      if (uVal.startsWith("http") || cVal.startsWith("http")) {
        return getFileName(uVal) === getFileName(cVal);
      }
      return false;
    });
  }

  // -----------------------------------------------------------
  // [BƯỚC 1] Kiểm tra Time Limit TRƯỚC (Sửa biến isCorrect)
  // -----------------------------------------------------------
  if (self.timeLimit > 0 && duration > self.timeLimit) {
    isCorrect = false; // CHỈ sửa biến boolean, KHÔNG gọi result.isCorrect
    console.log("🎮 Sena SDK: Time Limit Exceeded -> Result set to False");
  }

  // -----------------------------------------------------------
  // [BƯỚC 2] Sau đó mới tạo biến result (Dùng isCorrect đã chốt)
  // -----------------------------------------------------------
  const result = {
    isCorrect: isCorrect, // Lúc này isCorrect đã được xử lý xong xuôi
    duration: duration,
    correctAnswer: correctAnswers.join(" | "),
    userAnswer: userAnswers.join(" | "),
  };

  // -----------------------------------------------------------
  // [BƯỚC 3] Log và Return
  // -----------------------------------------------------------
  console.log(`Time spent: ${duration}s`);
  console.log(
    `Result: ${isCorrect ? "CORRECT" : "INCORRECT"} (User: ${result.userAnswer} vs Correct: ${result.correctAnswer})`,
  );

  if (callback) callback(result.isCorrect);
  return result; // Return full object for debug
};

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];
};

/**
 * Đăng ký listener nhận data qua postMessage
 * Gọi hàm này sau khi tạo instance SenaSDK
 */
SenaSDK.prototype.registerPostMessageListener = function () {
  let self = this;

  window.addEventListener("message", function (event) {
    if (!event.data || !event.data.type) return;

    switch (event.data.type) {
      case "SERVER_PUSH_DATA":
        console.log(
          "📥 Sena SDK: Received SERVER_PUSH_DATA",
          event.data.jsonData,
        );

        // Hủy timeout fallback nếu đang chờ
        if (self._postMessageTimeout) {
          clearTimeout(self._postMessageTimeout);
          self._postMessageTimeout = null;
        }
        self._waitingForPostMessage = false;

        // ========== LATE ARRIVAL HANDLING ==========
        // Nếu đã load từ server NHƯNG user chưa tương tác → cho phép override
        if (self._dataLoadedFromServer && !self._gameStartedByUser) {
          console.log(
            "🔄 Sena SDK: PostMessage arrived late but user hasn't started - RELOADING DATA",
          );
          // Reset state trước khi load mới
          self.postMessageDataLoaded = false;
          self._dataLoadedFromServer = false;
        }

        // Nếu user đã tương tác → bỏ qua postMessage muộn
        if (self._gameStartedByUser) {
          console.log(
            "⚠️ Sena SDK: PostMessage arrived late but user already playing - IGNORED",
          );
          return;
        }

        // Load data từ postMessage
        self.loadFromPostMessage(event.data.jsonData);

        // Nếu là matching game, cũng forward cho tdv_sdk listener
        let gameCode = event.data.jsonData && event.data.jsonData.gameCode;
        if (gameCode && gameCode.charAt(1) === "3" && window.tdv_sdk) {
          // Hủy timeout của tdv_sdk nếu có
          if (window.tdv_sdk._postMessageTimeout) {
            clearTimeout(window.tdv_sdk._postMessageTimeout);
            window.tdv_sdk._postMessageTimeout = null;
          }
          window.tdv_sdk._waitingForPostMessage = false;

          // Gọi callback của tdv_sdk nếu có
          if (window.tdv_sdk._loadCallback) {
            window.tdv_sdk._loadCallback(true);
            window.tdv_sdk._loadCallback = null;
          }
        }

        // Gọi callback nếu có (từ hàm load())
        if (self._loadCallback) {
          self._loadCallback(true);
          self._loadCallback = null;
        }
        break;

      case "SYNC_TIME":
        if (event.data.end_time_iso) {
          let endTimeDate = new Date(event.data.end_time_iso);
          let now = new Date();
          self.timeLimit = Math.max(0, Math.floor((endTimeDate - now) / 1000));
          console.log(
            "🎮 Sena SDK: Time synced, remaining:",
            self.timeLimit,
            "s",
          );

          // Sync cho tdv_sdk nếu có
          if (window.tdv_sdk) {
            window.tdv_sdk.timeLimit = self.timeLimit;
            window.tdv_sdk.endTime = endTimeDate;
          }
        }
        break;

      // ========== NEW MESSAGE TYPES (theo README protocol) ==========

      case "SDK_DATA_READY":
        // Server gửi sanitized data cho game render (LIVE mode)
        console.log("📥 Sena SDK: Received SDK_DATA_READY", event.data.payload);
        self._handleSdkDataReady(event.data.payload);
        break;

      case "SDK_PUSH_DATA":
        // Preview mode: Game push data để SDK sanitize
        console.log("📥 Sena SDK: Received SDK_PUSH_DATA", event.data.payload);
        if (event.data.payload && event.data.payload.items) {
          // Convert items to our format và load
          self._handleSdkPushData(event.data.payload.items);
        }
        break;

      case "SDK_ANSWER_RESULT":
        // Server trả về kết quả verify answer
        console.log(
          "📥 Sena SDK: Received SDK_ANSWER_RESULT",
          event.data.payload,
        );
        self._lastAnswerResult = event.data.payload;
        // Trigger callback nếu có
        if (self._answerResultCallback) {
          self._answerResultCallback(event.data.payload);
          self._answerResultCallback = null;
        }
        break;

      case "SEQUENCE_SYNC":
        console.log("📥 Sena SDK: Received SEQUENCE_SYNC", event.data);
        if (event.data.uuid === self.uuid) {
          console.log("🔄 Sena SDK: Own message echoed back, processing...");
        }

        if (typeof self.onCustomMessage === "function") {
          self.onCustomMessage(event.data.data, event.data.uuid);
        }
        break;

      case "SDK_ERROR":
        // Server gửi error
        console.error("❌ Sena SDK: Received SDK_ERROR", event.data.payload);
        break;
    }
  });

  console.log("🎮 Sena SDK: PostMessage listener registered");
  console.log(
    "   Supported types: SERVER_PUSH_DATA, SDK_DATA_READY, SDK_PUSH_DATA, SYNC_TIME",
  );

  // Đăng ký tdv_sdk listener nếu có (không cần gọi registerPostMessageListener riêng)
  if (window.tdv_sdk && !window.tdv_sdk._postMessageListenerRegistered) {
    window.tdv_sdk._postMessageListenerRegistered = true;
    console.log("🎮 Sena SDK: tdv_sdk will receive forwarded data");
  }
};

/**
 * Handle SDK_DATA_READY message (LIVE mode - server gửi sanitized data)
 */
SenaSDK.prototype._handleSdkDataReady = function (payload) {
  let self = this;

  if (!payload || !payload.items) {
    console.error("🎮 Sena SDK: SDK_DATA_READY missing items");
    return;
  }

  // Hủy timeout nếu có
  if (self._postMessageTimeout) {
    clearTimeout(self._postMessageTimeout);
    self._postMessageTimeout = null;
  }
  self._waitingForPostMessage = false;

  // Convert SDK format to SenaSDK format
  let items = payload.items;

  if (items.length === 1) {
    // Single question
    let item = items[0];
    self.data = {
      question: item.question || "",
      request: item.question || "",
      options: item.options
        ? item.options.map((o) => o.text || o.audio || o)
        : [],
    };
    self.gameID = item.id;
  } else {
    // Multi-question
    self.list = items.map((item, idx) => ({
      id: item.id || idx,
      question: item.question || "",
      request: item.question || "",
      options: item.options
        ? item.options.map((o) => o.text || o.audio || o)
        : [],
      answer: null, // Server keeps answer
    }));
    self.totalQuestions = items.length;
    self.level = payload.completed_count || 0;
    self._loadCurrentQuestionToData();
  }

  self.postMessageDataLoaded = true;
  console.log("✅ Sena SDK: SDK_DATA_READY processed -", items.length, "items");

  // Gọi callback
  if (self._loadCallback) {
    self._loadCallback(true);
    self._loadCallback = null;
  }
};

/**
 * Handle SDK_PUSH_DATA message (PREVIEW mode - game push data với answer)
 */
SenaSDK.prototype._handleSdkPushData = function (items) {
  let self = this;

  if (!items || items.length === 0) {
    console.error("🎮 Sena SDK: SDK_PUSH_DATA missing items");
    return;
  }

  // Hủy timeout nếu có
  if (self._postMessageTimeout) {
    clearTimeout(self._postMessageTimeout);
    self._postMessageTimeout = null;
  }
  self._waitingForPostMessage = false;

  if (items.length === 1) {
    // Single question
    let item = items[0];
    self.data = {
      question: item.question || "",
      request: item.question || "",
      options: item.options
        ? item.options.map((o) => o.text || o.audio || o)
        : [],
    };
    self.correctAnswer = item.answer;
    self.gameID = item.id;
  } else {
    // Multi-question với answer
    self.list = items.map((item, idx) => ({
      id: item.id || idx,
      question: item.question || "",
      request: item.question || "",
      options: item.options
        ? item.options.map((o) => o.text || o.audio || o)
        : [],
      answer: item.answer,
    }));
    self.totalQuestions = items.length;
    self.level = 0;
    self._loadCurrentQuestionToData();
  }

  self.postMessageDataLoaded = true;
  console.log("✅ Sena SDK: SDK_PUSH_DATA processed -", items.length, "items");

  // Gọi callback
  if (self._loadCallback) {
    self._loadCallback(true);
    self._loadCallback = null;
  }
};

/**
 * Gửi SDK_CHECK_ANSWER cho server verify (LIVE mode)
 */
SenaSDK.prototype.checkAnswerViaServer = function (
  questionId,
  choice,
  callback,
) {
  let self = this;

  self._answerResultCallback = callback;

  window.parent.postMessage(
    {
      type: "SDK_CHECK_ANSWER",
      payload: {
        question_id: questionId,
        choice: choice,
        time_spent: self.getTimeSpent ? self.getTimeSpent() * 1000 : 0,
      },
    },
    "*",
  );

  console.log("📤 Sena SDK: Sent SDK_CHECK_ANSWER for", questionId);
};

/**
 * Get time spent in seconds
 */
SenaSDK.prototype.getTimeSpent = function () {
  if (!this.startTime) return 0;
  return Math.floor((Date.now() - this.startTime) / 1000);
};

/**
 * Submit đáp án cho multi-question mode
 * @param {string} selectedText - Đáp án người dùng chọn
 * @param {boolean} isTimeout - True nếu hết giờ
 * @returns {Object} Result object {isCorrect, result}
 */
SenaSDK.prototype.play = function (selectedText, isTimeout) {
  let self = this;

  // Nếu không có list (single question mode), dùng end()
  if (!self.currentQuestion && self.data) {
    let result = { isCorrect: false, result: 0 };
    self.end(selectedText, function (isCorrect) {
      result.isCorrect = isCorrect;
      result.result = isCorrect ? 1 : 0;
    });
    return result.result;
  }

  if (!self.currentQuestion) return 0;

  let isActuallyTimeout = isTimeout === true || String(isTimeout) === "true";

  // Kiểm tra đã trả lời câu này chưa
  let alreadyAnswered = self.userResults.find(
    (r) => r.id === self.currentQuestion.id,
  );
  if (alreadyAnswered) {
    return alreadyAnswered.result;
  }

  let isCorrect = false;
  let userChoice = null;

  if (isActuallyTimeout) {
    isCorrect = false;
    userChoice = null;
  } else {
    userChoice = String(selectedText).trim();
    let correctAnswer = String(self.currentQuestion.answer).trim();
    isCorrect = userChoice.toLowerCase() === correctAnswer.toLowerCase();
  }

  let resultValue = isCorrect ? 1 : 0;

  let report = {
    question_id: self.currentQuestion.id,
    result: resultValue,
    choice: userChoice,
    is_timeout: isActuallyTimeout,
  };

  self.userResults.push({ id: report.question_id, result: report.result });

  console.log("🎮 Sena SDK: Answer Report:", report);

  // Gửi kết quả cho parent window
  window.parent.postMessage({ type: "ANSWER_REPORT", data: report }, "*");

  return resultValue;
};

/**
 * Kết thúc bài thi và gửi kết quả (multi-question mode)
 */
SenaSDK.prototype.submitResults = function () {
  let self = this;

  // Loại bỏ duplicate results
  let uniqueResults = [];
  let seenIds = {};
  for (let i = self.userResults.length - 1; i >= 0; i--) {
    if (!seenIds[self.userResults[i].id]) {
      uniqueResults.unshift(self.userResults[i]);
      seenIds[self.userResults[i].id] = true;
    }
  }

  let correctCount = uniqueResults.filter((r) => r.result === 1).length;
  let totalScore =
    self.totalQuestions > 0
      ? Math.round((correctCount / self.totalQuestions) * 100) / 10
      : 0;
  let timeSpent = Math.floor((Date.now() - self.startTime) / 1000);

  let finalData = {
    game_id: self.gameID,
    user_id: self.userId,
    score: totalScore,
    time_spent: timeSpent,
    correct_count: correctCount,
    total_questions: self.totalQuestions,
    details: uniqueResults,
  };

  console.log(
    "🎮 Sena SDK: Final Result - Score:",
    totalScore,
    "Time Spent:",
    timeSpent,
    "s",
  );

  // Gửi kết quả cho parent window
  window.parent.postMessage({ type: "FINAL_RESULT", data: finalData }, "*");

  return finalData;
};

// 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;
}
/**
 * [NEW] Get Target Name for G9 (Memory Shuffle)
 * Lấy tên đáp án đúng (Ví dụ: "cat")
 */
SenaSDK.prototype.getTargetName = function () {
  // Với G9, correctAnswer sẽ lưu target name
  if (this.correctAnswer) {
    // Nếu correctAnswer là object (trường hợp hiếm), lấy text
    if (typeof this.correctAnswer === "object" && this.correctAnswer.text) {
      return this.correctAnswer.text;
    }
    return String(this.correctAnswer);
  }
  return "";
};
/**
 * [NEW] Helpers for Card Object (G9)
 */
SenaSDK.prototype.getCardName = function (index) {
  if (this.data && this.data.options && this.data.options[index]) {
    let opt = this.data.options[index];
    return opt.name || opt.text || "";
  }
  return "";
};
SenaSDK.prototype.getCardImage = function (index) {
  if (this.data && this.data.options && this.data.options[index]) {
    let opt = this.data.options[index];
    return opt.image || "";
  }
  return "";
};
SenaSDK.prototype.getCardAudio = function (index) {
  if (this.data && this.data.options && this.data.options[index]) {
    let opt = this.data.options[index];
    return opt.audio || "";
  }
  return "";
};

/**
 * [UPDATE G5] Load data cho level cụ thể (Phân trang tự nhiên)
 * Logic mới: Lấy vừa đủ số lượng còn lại, không lặp lại (wrap-around) data cũ.
 */
SenaSDK.prototype.loadLevelG5 = function (levelIndex) {
  let self = this;
  if (self.gameType !== 5 || !self.masterList) return false;

  self.currentLevel = levelIndex;
  let count = self.itemCount; // Số card tối đa mỗi trang (VD: 6)

  window.Sena_TotalLevels = Math.ceil(self.masterList.length / count);

  let startIndex = (levelIndex - 1) * count;

  // --- LOGIC MỚI: CẮT DATA (SLICING) ---
  // Tính điểm kết thúc: Nếu vượt quá độ dài list thì lấy độ dài list (không wrap)
  let endIndex = Math.min(startIndex + count, self.masterList.length);

  // Cắt danh sách card cho level hiện tại
  let levelOptions = self.masterList.slice(startIndex, endIndex);

  // Gán vào data.options để C2 render
  self.data.options = levelOptions;

  console.log(
    `🎮 Sena SDK: Loaded Level ${levelIndex} (G5) with ${levelOptions.length} cards`,
  );
  return true;
};

/**
 * [NEW G5] Lấy thông tin Level
 */
SenaSDK.prototype.getTotalLevels = function () {
  return this.totalLevels || 1;
};

SenaSDK.prototype.getTimePerCard = function () {
  if (this.timePerCard === undefined) {
    this._parseGameCode();
  }

  if (this.timePerCard && this.timePerCard > 0) {
    return this.timePerCard;
  }

  return 5;
};

SenaSDK.prototype.getCardType = function (index) {
  // Ưu tiên 1: Lấy từ data.options (G4, G1, G2 đang chạy trên grid hiện tại)
  if (this.data && this.data.options && this.data.options[index]) {
    return this.data.options[index].type || "text";
  }

  // Ưu tiên 2: Fallback cho G5 (Master List)
  if (this.masterList && this.masterList[index]) {
    return this.masterList[index].type || "text";
  }

  // Mặc định
  return "text";
};

// [UPDATE G4] Xử lý data đặc thù cho Memory Card: Fill blank và Xử lý thẻ lẻ (Orphan)
SenaSDK.prototype._processG4Data = function () {
  let self = this;
  if (!self.data.options) self.data.options = [];

  // BƯỚC 1: Xử lý thẻ lẻ (Sanitize Data) ngay tại nguồn
  // Đếm số lượng xuất hiện của từng cặp tên
  let counts = {};
  self.data.options.forEach((item) => {
    if (item.type !== "blank" && item.name) {
      counts[item.name] = (counts[item.name] || 0) + 1;
    }
  });

  // Duyệt lại và biến những thẻ có số lượng < 2 thành blank
  self.data.options.forEach((item) => {
    if (item.type !== "blank" && item.name) {
      if (counts[item.name] < 2) {
        console.log("🎮 Sena SDK: Orphan card detected & removed:", item.name);
        item.type = "blank";
        item.name = "blank"; // Xóa tên để tránh logic game bắt nhầm
        item.image = ""; // Xóa ảnh
        item.id = "blank_sanitized";
      }
    }
  });

  // BƯỚC 2: Fill thêm thẻ blank cho đủ 9 ô (Logic cũ)
  while (self.data.options.length < 9) {
    self.data.options.push({
      id: "blank_" + self.data.options.length,
      type: "blank",
      name: "blank",
      value: -1,
      image: "",
    });
  }

  // BƯỚC 3: Shuffle (Trộn bài)
  if (self.shuffle) {
    self.shuffleArray(self.data.options);
  }
};

// [UPDATE G4] Hàm lấy ID
SenaSDK.prototype.getCardID = function (index) {
  if (this.data && this.data.options && this.data.options[index]) {
    return this.data.options[index].id || "";
  }
  return "";
};

// [UPDATE G4] Hàm Check Pair (Logic tạm thời ở Client cho Mock)
SenaSDK.prototype.checkPair = function (idx1, idx2, callback) {
  let self = this;

  // Validate index
  let card1 = self.data.options[idx1];
  let card2 = self.data.options[idx2];

  if (!card1 || !card2) {
    if (callback) callback(false);
    return;
  }

  // Logic so sánh: Name giống nhau VÀ ID khác nhau (tránh click 2 lần 1 thẻ) VÀ không phải blank
  let isMatch = false;

  if (card1.type !== "blank" && card2.type !== "blank") {
    if (card1.id !== card2.id) {
      // Check ko phải chính nó
      // So sánh name (ví dụ: "dog" == "dog")
      if (
        card1.name &&
        card2.name &&
        card1.name.toLowerCase() === card2.name.toLowerCase()
      ) {
        isMatch = true;
      }
    }
  }

  console.log(
    `🎮 Sena SDK: Check Pair [${idx1}] vs [${idx2}] -> ${isMatch ? "MATCH" : "WRONG"}`,
  );

  // [TODO] Sau này sẽ thay đoạn này bằng postMessage lên Server verify
  if (callback) callback(isMatch);
};

/**
 * [NEW v2.2] Gửi Custom Data lên Parent Window
 * @param {Object} data - Object chứa 5 trường data1 -> data5
 */
SenaSDK.prototype.sendMessageToParent = function (data) {
  let self = this;

  // Tự động tạo UUID cho session nếu chưa có
  if (!self.uuid) {
    self.uuid =
      "session-" + Date.now() + "-" + Math.floor(Math.random() * 10000);
  }

  // Đóng gói payload đúng chuẩn tài liệu v2.2
  let payload = {
    type: "SEQUENCE_SYNC",
    uuid: self.uuid,
    data: data,
    timestamp: Date.now(),
  };

  console.log("📤 Sena SDK: Sending SEQUENCE_SYNC to parent:", payload);

  // Gửi lên Parent Window (Backend/Iframe parent)
  window.parent.postMessage(payload, "*");
};

if (typeof module !== "undefined" && module.exports) {
  module.exports = SenaSDK;
} else if (typeof define === "function" && define.amd) {
  define([], function () {
    return SenaSDK;
  });
} else {
  window.SenaSDK = SenaSDK;
}
