import { EnumQuestionType, EnumReviewMode } from "@/common/enum";
import { getPaper } from '@/api/modules/study';
import { Study } from "@/types";
import { Question } from "@/types/study";

/**
 * @description 兼容层：获取当前时间戳（毫秒）
 * 优先使用 performance.now()，不支持则降级到 Date.now()
 * 兼容微信小程序环境
 */
const getNow = (): number => {
  // #ifdef MP-WEIXIN
  return Date.now();
  // #endif

  // #ifndef MP-WEIXIN
  if (typeof performance !== 'undefined' && performance.now) {
    return performance.now();
  }
  return Date.now();
  // #endif
};

/**
 * @description 兼容层：请求动画帧
 * 微信小程序不支持 requestAnimationFrame，使用 setTimeout 模拟
 */
const requestAnimFrame = (() => {
  // #ifdef MP-WEIXIN
  return (callback: FrameRequestCallback): number => {
    return setTimeout(() => callback(Date.now()), 1000 / 60) as unknown as number;
  };
  // #endif

  // #ifndef MP-WEIXIN
  if (typeof requestAnimationFrame !== 'undefined') {
    return requestAnimationFrame;
  }
  return (callback: FrameRequestCallback): number => {
    return setTimeout(() => callback(Date.now()), 1000 / 60) as unknown as number;
  };
  // #endif
})();

/**
 * @description 兼容层：取消动画帧
 * 微信小程序不支持 cancelAnimationFrame，使用 clearTimeout 模拟
 */
const cancelAnimFrame = (() => {
  // #ifdef MP-WEIXIN
  return (id: number): void => {
    clearTimeout(id as unknown as NodeJS.Timeout);
  };
  // #endif

  // #ifndef MP-WEIXIN
  if (typeof cancelAnimationFrame !== 'undefined') {
    return cancelAnimationFrame;
  }
  return (id: number): void => {
    clearTimeout(id as unknown as NodeJS.Timeout);
  };
  // #endif
})();

/**
 * @description 解码 HTML 实体
 * 由于 uv-parse 的 decodeEntity 只支持有限的实体，需要手动解码音标等特殊实体
 * 使用手动映射表，兼容所有 uni-app 平台（包括小程序）
 */
export const decodeHtmlEntities = (str: string): string => {
  if (!str) return str;

  // 标准 HTML 实体映射表
  const entityMap: Record<string, string> = {
    // 音标相关 - 锐音符 (acute)
    'aacute': 'á',
    'eacute': 'é',
    'iacute': 'í',
    'oacute': 'ó',
    'uacute': 'ú',
    // 音标相关 - 重音符 (grave)
    'agrave': 'à',
    'egrave': 'è',
    'igrave': 'ì',
    'ograve': 'ò',
    'ugrave': 'ù',
    // 音标相关 - 扬抑符 (circumflex)
    'acirc': 'â',
    'ecirc': 'ê',
    'icirc': 'î',
    'ocirc': 'ô',
    'ucirc': 'û',
    // 音标相关 - 分音符 (umlaut/diaeresis)
    'auml': 'ä',
    'euml': 'ë',
    'iuml': 'ï',
    'ouml': 'ö',
    'uuml': 'ü',
    // 音标相关 - 波浪符 (tilde)
    'ntilde': 'ñ',
    'atilde': 'ã',
    'otilde': 'õ',
    'aelig': 'æ',
    'eth': 'ð',
    // 其他常用实体
    'quot': '"',
    'apos': "'",
    'nbsp': '\u00A0',
    'copy': '©',
    'reg': '®',
    'trade': '™',
    'mdash': '—',
    'ndash': '–',
    'hellip': '…',
    'darr': '↓',
    'uarr': '↑',
    'rarr': '→',
    'larr': '←',
    'harr': '↔',
    'crarr': '↵',
    'lArr': '⇐',
    'rArr': '⇒',
    'hArr': '⇔',
    'laquo': '«',
    'raquo': '»',
    'ldquo': '“',
    'rdquo': '”',
    'lsquo': '‘',
    'rsquo': '’',
    'lsaquo': '‹',
    'rsaquo': '›',
    // 数学符号
    'amp': '&',
    'minus': '−',
    'plus': '＋',
    'times': '×',
    'divide': '÷',
    'plusmn': '±',
    'deg': '°',
    'radic': '√',
    'isin': '∈',
    'infin': '∞',
    'there4': '∴',
    'because': '∵',
    'forall': '∀',
    'exists': '∃',
    'nexists': '∄',
    'notin': '∉',
    'ni': '∋',
    'empty': '∅',
    'prod': '∏',
    'sum': '∑',
    'prop': '∝',
    'sim': '∼',
    'simeq': '≃',
    'approx': '≈',
    'asymp': '≈',
    'neq': '≠',
    'equiv': '≡',
    'ne': '≠',
    'le': '≤',
    'ge': '≥',
    'll': '≪',
    'gg': '≫',
    'prec': '≺',
    'succ': '≻',
    'preceq': '≼',
    'succeq': '≽',
    'sub': '⊂',
    'sube': '⊆',
    'subset': '⊂',
    'subseteq': '⊆',
    'sup': '⊃',
    'supe': '⊇',
    'supset': '⊃',
    'supseteq': '⊇',
    'perp': '⊥',
    'parallel': '∥',
    'wedge': '∧',
    'vee': '∨',
    'cap': '∩',
    'cup': '∪',
    'int': '∫',
    'oint': '∮',
    'angle': '∠',
    'ang': '∠',
    'mid': '∣',
    'vdash': '⊢',
    'dashv': '⊣',
    'models': '⊨',
    'vDash': '⊩',
    'Vdash': '⊫',
    'VDash': '⊬',
    'Oslash': 'Ø',
    'ordm': 'º',
    'not': '¬',
    'prime': '′',
    // 排版符号
    'middot': '·',
    'bull': '•',
    'sect': '§',
    'para': '¶',
    'macr': '¯',
    'micro': 'µ',
    // 货币符号
    'yen': '¥',
    'euro': '€',
    'pound': '£',
    'cent': '¢',
    // 希腊字母
    'alpha': 'α',
    'beta': 'β',
    'gamma': 'γ',
    'delta': 'δ',
    'epsilon': 'ε',
    'zeta': 'ζ',
    'eta': 'η',
    'theta': 'θ',
    'iota': 'ι',
    'kappa': 'κ',
    'lambda': 'λ',
    'mu': 'μ',
    'nu': 'ν',
    'xi': 'ξ',
    'omicron': 'ο',
    'pi': 'π',
    'rho': 'ρ',
    'sigma': 'σ',
    'tau': 'τ',
    'upsilon': 'υ',
    'phi': 'φ',
    'chi': 'χ',
    'psi': 'ψ',
    'omega': 'ω',
    'Omega': 'Ω',
    'thetasym': 'ϑ',
    'upsih': 'ϒ',
    'piv': 'ϖ',
  };

  let result = str;

  // 清除所有的特殊空格实体
  result = result.replaceAll("&zwj;", "")
    .replaceAll("&nbsp;", "")
    .replaceAll("&zwnj;", "")
    .replaceAll("&thinsp;", "")
    .replaceAll("&emsp;", "")
    .replaceAll("&ensp;", "")
    .replaceAll("&shy;", "")
    .replaceAll("&#8203;", "");

  // 0. 保护真正的 HTML 标签，转义文本中的 < 和 >
  // 策略：< 后面如果不是字母或 /（标签开始），则转义为 &lt;
  // 这样可以处理 x<2、1<x<5 等数学表达式
  // result = result.replace(/<(?![a-zA-Z/])/g, '&lt;');  // < 后面不是字母或 / 的转义
  // result = result.replace(/(?<![a-zA-Z0-9])>/g, '&gt;'); // > 前面不是字母数字的转义（避免破坏标签）

  // 1. 处理非标准的上标实体：&sup数字; → <sup>数字</sup>
  // 例如：&sup2; → <sup>2</sup>, &sup123; → <sup>123</sup>
  result = result.replace(/&sup(\d+);/gi, (match, digits) => {
    return `<sup>${digits}</sup>`;
  });

  // 2. 处理非标准的下标实体：&sub数字; → <sub>数字</sub>
  // 例如：&sub2; → <sub>2</sub>, &sub123; → <sub>123</sub>
  result = result.replace(/&sub(\d+);/gi, (match, digits) => {
    return `<sub>${digits}</sub>`;
  });

  // 3. 处理标准命名实体（如 &iacute;、&there4;）
  // 注意：正则需要支持字母和数字的组合
  result = result.replace(/&([a-z0-9]+);/gi, (match, entity) => {
    const lowerEntity = entity.toLowerCase();
    if (entityMap[lowerEntity]) {
      return entityMap[lowerEntity];
    }
    return match;
  });

  // 4. 处理十进制数字实体（如 &#178; → ²）
  result = result.replace(/&#(\d+);/g, (match, num) => {
    const code = parseInt(num, 10);
    if (!isNaN(code)) {
      return String.fromCharCode(code);
    }
    return match;
  });

  // 5. 处理十六进制数字实体（如 &#xB2; → ²）
  result = result.replace(/&#x([0-9a-f]+);/gi, (match, hex) => {
    const code = parseInt(hex, 16);
    if (!isNaN(code)) {
      return String.fromCharCode(code);
    }
    return match;
  });

  return result;
}

export const useExam = () => {
  const questionTypeDesc: Record<EnumQuestionType, string> = {
    [EnumQuestionType.SINGLE_CHOICE]: '单选题',
    [EnumQuestionType.MULTIPLE_CHOICE]: '多选题',
    [EnumQuestionType.JUDGMENT]: '判断题',
    [EnumQuestionType.FILL_IN_THE_BLANK]: '填空题',
    [EnumQuestionType.SUBJECTIVE]: '主观题',
    [EnumQuestionType.SHORT_ANSWER]: '简答题',
    [EnumQuestionType.ESSAY]: '问答题',
    [EnumQuestionType.ANALYSIS]: '分析题',
    [EnumQuestionType.OTHER]: '阅读题'
  }
  // 题型顺序
  const questionTypeOrder = [
    EnumQuestionType.SINGLE_CHOICE,
    EnumQuestionType.MULTIPLE_CHOICE,
    EnumQuestionType.JUDGMENT,
    EnumQuestionType.FILL_IN_THE_BLANK,
    EnumQuestionType.SUBJECTIVE,
    EnumQuestionType.SHORT_ANSWER,
    EnumQuestionType.ESSAY,
    EnumQuestionType.ANALYSIS,
    EnumQuestionType.OTHER
  ];
  let interval: NodeJS.Timeout | null = null;
  let animationFrameId: number | null = null; // requestAnimationFrame 的 ID
  let countStart: number = 0;
  let countTime: number = 0;
  const countDownCallback = ref<() => void>(() => { });
  // 练习计时相关变量
  let practiceStartTime: number = 0; // 练习开始时间戳（毫秒）
  let practiceAccumulatedTime: number = 0; // 累计的练习时间（秒）
  // 练习时长
  const practiceDuration = ref<number>(0);
  const formatPracticeDuration = computed(() => {
    const hours = Math.floor(practiceDuration.value / 3600);
    const minutes = Math.floor((practiceDuration.value % 3600) / 60);
    const seconds = practiceDuration.value % 60;
    if (hours > 0) {
      return `${hours.toString().padStart(2, '0')}:${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}`;
    } else {
      return `${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}`;
    }
  });
  // 考试时长
  const examDuration = ref<number>(0);
  const formatExamDuration = computed(() => {
    const hours = Math.floor(examDuration.value / 3600);
    const minutes = Math.floor((examDuration.value % 3600) / 60);
    const seconds = examDuration.value % 60;
    return `${hours.toString().padStart(2, '0')}:${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}`;
  });
  const swiperDuration = ref<number>(300);
  const questionList = ref<Study.Question[]>([]);
  // 练习设置
  const practiceSettings = ref<Study.PracticeSettings>({
    reviewMode: EnumReviewMode.AFTER_SUBMIT,
    autoNext: false
  });
  // 收藏列表
  const favoriteList = ref<Study.Question[]>([]);
  // 不会列表
  const notKnowList = ref<Study.Question[]>([]);
  // 重点标记列表
  const markList = ref<Study.Question[]>([]);
  /// 虚拟题目索引，包含子题
  const virtualCurrentIndex = ref<number>(0);
  /// 虚拟总题量，包含子题
  const virtualTotalCount = computed(() => {
    return questionList.value.reduce((acc, item) => {
      if (item.subQuestions && item.subQuestions.length > 0) {
        return acc + item.subQuestions.length;
      }
      return acc + 1;
    }, 0);
  });
  // 包含状态的问题列表
  const stateQuestionList = computed(() => {
    const parseQuestion = (qs: Study.Question) => {
      if (qs.subQuestions && qs.subQuestions.length > 0) {
        qs.isLeaf = false;
        qs.subQuestions.forEach((subQs, index) => {
          subQs.isDone = isDone(subQs);
          subQs.isCorrect = isQuestionCorrect(subQs);
          subQs.isNotAnswer = isQuestionNotAnswer(subQs);
          subQs.isLeaf = true;
          subQs.options.forEach(option => {
            option.isCorrect = isOptionCorrect(subQs, option);
            option.isSelected = isOptionSelected(subQs, option);
            option.isMissed = !option.isSelected && option.isCorrect;
            option.isIncorrect = !option.isCorrect && option.isSelected;
          });
        });
      } else {
        qs.isSubQuestion = false;
        qs.isDone = isDone(qs);
        qs.isCorrect = isQuestionCorrect(qs);
        qs.isNotAnswer = isQuestionNotAnswer(qs);
        qs.isLeaf = true;
        qs.options.forEach(option => {
          option.isCorrect = isOptionCorrect(qs, option);
          option.isSelected = isOptionSelected(qs, option);
          option.isMissed = !option.isSelected && option.isCorrect;
          option.isIncorrect = !option.isCorrect && option.isSelected;
        });
      }
      return qs;
    }
    return questionList.value.map((item, index) => {
      return parseQuestion(item)
    });
  });
  /// 扁平化题目列表，用于答题卡
  const flatQuestionList = computed(() => {
    return stateQuestionList.value.flatMap(item => {
      if (item.subQuestions && item.subQuestions.length > 0) {
        return item.subQuestions.flat();
      }
      return item;
    });
  });
  /// 按照题型分组，用于答题卡
  const groupedQuestionList = computed(() => {
    const state = questionTypeOrder.map(type => {
      return {
        type,
        list: [] as {
          question: Study.Question;
          index: number
        }[]
      }
    });
    flatQuestionList.value.forEach((qs, index) => {
      let group;
      if (qs.isSubQuestion) {
        group = state.find(item => item.type === qs.parentTypeId);
      } else {
        group = state.find(item => item.type === qs.typeId);
      }
      if (group) {
        group.list.push({
          question: qs,
          index
        });
      } else {
        state.push({
          type: qs.typeId,
          list: [{
            question: qs,
            index
          }]
        });
      }
    });
    return state;
  });
  /// 是否全部做完
  const isAllDone = computed(() => {
    return doneCount.value === virtualTotalCount.value;
  });
  // 当前下标
  const currentIndex = ref<number>(0);
  // 子题下标
  const subQuestionIndex = ref<number>(0);
  // 当前题目
  const currentQuestion = computed(() => {
    return questionList.value[currentIndex.value];
  });
  // 当前子题
  const currentSubQuestion = computed(() => {
    if (currentQuestion.value.subQuestions.length === 0) {
      return null;
    }
    if (subQuestionIndex.value >= currentQuestion.value.subQuestions.length) {
      return null;
    }
    // return currentQuestion.value.subQuestions[subQuestionIndex.value];
    return currentQuestion.value.subQuestions[currentQuestion.value.activeSubIndex];
  });
  /// 总题量，不区分子题，等同于接口返回的题目列表
  const totalCount = computed(() => {
    return questionList.value.length;
  });
  /// 已做题的数量 --> stateQuestionList
  const doneCount = computed(() => {
    // 有答案的或者不会做的，都认为是做了
    let count = 0;
    for (let i = 0; i <= stateQuestionList.value.length - 1; i++) {
      const qs = stateQuestionList.value[i];
      if (qs.subQuestions && qs.subQuestions.length > 0) {
        qs.subQuestions.forEach(subQs => {
          if (subQs.isDone) {
            count++;
          }
        });
      } else {
        if (qs.isDone) {
          count++;
        }
      }
    }
    return count;
  });
  /// 未做题的数量
  const notDoneCount = computed(() => {
    return virtualTotalCount.value - doneCount.value;
  });
  watch(() => virtualCurrentIndex.value, (newVal, oldVal) => {
    updateQuestionDuration(oldVal);
  });
  // 更新单个题目做题时间
  const updateQuestionDuration = (index: number, continueCount = true) => {
    const question = flatQuestionList.value[index];
    const time = stopCount();
    question.duration += time;
    // 每次结算后都清空累计时长，避免多次提交或多次 stop 导致重复累加
    clearCount();
    if (continueCount) {
      startCount();
    }
  }
  /// 包含子题的题目计算整体做题进度
  const calcProgress = (qs: Study.Question): number => {
    if (qs.subQuestions && qs.subQuestions.length > 0) {
      return qs.subQuestions.reduce((acc, q) => acc + calcProgress(q), 0) / qs.subQuestions.length;
    }
    return qs.isDone ? 100 : 0;
  }
  /// 题目是否做完
  const isDone = (qs: Study.Question): boolean => {
    if (qs.subQuestions && qs.subQuestions.length > 0) {
      return qs.subQuestions.every(q => isDone(q));
    }
    return (qs.answers && qs.answers.filter(item => !!item).length > 0) || !!qs.isNotKnow;
  }
  /// 题目是否正确
  const isQuestionCorrect = (qs: Study.Question): boolean => {
    let { answers, answer1, answer2, typeId } = qs;
    answers = answers?.filter(item => !!item) || [];
    answer1 = answer1 || '';
    answer2 = answer2 || '';
    if ([EnumQuestionType.SINGLE_CHOICE, EnumQuestionType.JUDGMENT].includes(typeId)) {
      return answer1.trim() === answers[0];
    } else if ([EnumQuestionType.MULTIPLE_CHOICE].includes(typeId)) {
      return answers.length === answer1.length && answers.every(item => answer1.includes(item));
    } else {
      // 主观题 A 对 B 错
      return answers.includes('A') && !answers.includes('B');
    }
  };
  /// 题目是否未作答
  const isQuestionNotAnswer = (qs: Study.Question): boolean => {
    if (qs.subQuestions && qs.subQuestions.length > 0) {
      return qs.subQuestions.every(q => isQuestionNotAnswer(q));
    }
    return !qs.answers || qs.answers.filter(item => !!item).length === 0;
  }
  /// 选项是否正确
  const isOptionCorrect = (question: Study.Question, option: Study.QuestionOption) => {
    const { answers, answer1, typeId } = question;
    if ([EnumQuestionType.SINGLE_CHOICE, EnumQuestionType.JUDGMENT].includes(typeId)) {
      return answer1?.includes(option.no);
    } else if ([EnumQuestionType.MULTIPLE_CHOICE].includes(typeId)) {
      return answer1?.includes(option.no);
    } else {
      return answers?.includes(option.no) && option.no === 'A';
    }
  }
  /// 选项是否选中
  const isOptionSelected = (question: Study.Question, option: Study.QuestionOption) => {
    return question.answers.includes(option.no);
  }
  // 是否可以切换上一题
  const prevEnable = computed(() => {
    return currentIndex.value > 0 || currentQuestion.value.activeSubIndex > 0;
  });
  // 是否可以切换下一题
  const nextEnable = computed(() => {
    return currentIndex.value < questionList.value.length - 1 || currentQuestion.value.activeSubIndex < currentQuestion.value.subQuestions.length - 1;
  });
  // 下一题
  const nextQuestion = () => {
    if (!nextEnable.value) {
      return;
    }
    if (currentQuestion.value.activeSubIndex < currentQuestion.value.subQuestions.length - 1) {
      currentQuestion.value.activeSubIndex++;
    } else {
      const lastIndex = currentIndex.value + 1;
      questionList.value[lastIndex].activeSubIndex = 0;
      currentIndex.value = lastIndex;
    }
  }
  // 上一题
  const prevQuestion = () => {
    if (!prevEnable.value) {
      return;
    }
    if (currentQuestion.value.subQuestions && currentQuestion.value.subQuestions.length > 0) {
      if (currentQuestion.value.activeSubIndex > 0) {
        currentQuestion.value.activeSubIndex--;
      } else {
        const prevIndex = currentIndex.value - 1;
        questionList.value[prevIndex].activeSubIndex = questionList.value[prevIndex].subQuestions.length - 1;
        currentIndex.value = prevIndex;
      }
    } else {
      if (currentIndex.value > 0) {
        currentIndex.value--;
      }
    }
  }
  // 快速下一题
  const nextQuestionQuickly = () => {
    if (!nextEnable) {
      return;
    }
    swiperDuration.value = 0;
    setTimeout(() => {
      nextQuestion();
      setTimeout(() => {
        swiperDuration.value = 300;
      }, 0);
    }, 0);
  }
  // 快速上一题
  const prevQuestionQuickly = () => {
    if (!prevEnable.value) {
      return;
    }
    swiperDuration.value = 0;
    setTimeout(() => {
      prevQuestion();
      setTimeout(() => {
        swiperDuration.value = 300;
      }, 0);
    }, 0);
  }
  // 通过下标切换题目
  const changeIndex = (index: number, subIndex?: number) => {
    swiperDuration.value = 0;
    setTimeout(() => {
      currentIndex.value = index;
      if (!subIndex !== undefined) {
        if (subIndex !== undefined) {
          questionList.value[index].activeSubIndex = subIndex || 0;
        }
      }
      setTimeout(() => {
        swiperDuration.value = 300;
      }, 0);
    }, 0);
  }
  // 开始计时
  const startTiming = () => {
    startCount();

    // 记录开始时间戳（毫秒）
    if (practiceStartTime === 0) {
      practiceStartTime = getNow();
    }

    // 使用 requestAnimFrame 更新显示，更流畅且性能更好
    // 兼容微信小程序环境
    const updatePracticeDuration = () => {
      if (practiceStartTime > 0) {
        // 计算实际经过的时间（秒）
        const elapsed = (getNow() - practiceStartTime) / 1000;
        practiceDuration.value = Math.floor(practiceAccumulatedTime + elapsed);
        // 继续下一帧更新
        animationFrameId = requestAnimFrame(updatePracticeDuration);
      }
    };

    // 开始动画帧循环
    animationFrameId = requestAnimFrame(updatePracticeDuration);
  }
  // 停止计时
  const stopTiming = () => {
    stopCount();

    // 取消动画帧
    if (animationFrameId !== null) {
      cancelAnimFrame(animationFrameId);
      animationFrameId = null;
    }

    // 如果正在计时，累加经过的时间
    if (practiceStartTime > 0) {
      const elapsed = (getNow() - practiceStartTime) / 1000;
      practiceAccumulatedTime += elapsed;
      practiceDuration.value = Math.floor(practiceAccumulatedTime);
      practiceStartTime = 0;
    }
  }
  const startCount = () => {
    if (countStart === 0) {
      countStart = getNow();
    }
  }
  const stopCount = () => {
    // 如果当前没有在计时（countStart 为 0），说明已经 stop 过了，直接返回累计时长，避免重复累加
    if (countStart === 0) {
      return countTime;
    }
    countTime += (getNow() - countStart);
    countStart = 0;
    return countTime;
  }
  const clearCount = () => {
    countTime = 0;
  }
  // 开始倒计时
  const startCountdown = () => {
    interval = setInterval(() => {
      if (examDuration.value <= 0) {
        console.log('停止倒计时')
        stopExamDuration();
        return;
      }
      examDuration.value -= 1;
    }, 1000);
  }
  // 停止倒计时
  const stopExamDuration = () => {
    interval && clearInterval(interval);
    interval = null;
    countDownCallback.value && countDownCallback.value();
  }
  const setExamDuration = (duration: number) => {
    examDuration.value = duration;
  }
  const setPracticeDuration = (duration: number) => {
    practiceDuration.value = duration;
    practiceAccumulatedTime = duration;
    practiceStartTime = 0;
  }
  const setCountDownCallback = (callback: () => void) => {
    countDownCallback.value = callback;
  }
  const setDuration = (duration: number) => {
    examDuration.value = duration;
    practiceDuration.value = duration;
    practiceAccumulatedTime = duration;
    practiceStartTime = 0;
  }
  /// 整理题目结构
  const transerQuestions = (arr: Study.Question[]) => {
    let offset = 0;
    return arr.map((item: Study.Question, index: number) => {
      const result = {
        ...item,
        index: index
      };
      // 如果有子节点，处理子节点并计算subIndex
      if (item.subQuestions && Array.isArray(item.subQuestions) && item.subQuestions.length > 0) {
        // 为当前节点设置offset
        result.offset = offset;
        result.subQuestions = item.subQuestions.map((child, childIndex) => ({
          ...child,
          subIndex: childIndex,
          isSubQuestion: true,
          parentId: item.id,
          parentTypeId: item.typeId,
          parentIndex: index,
          index: index,
          virtualIndex: index + result.offset + childIndex
        }));
        // 更新offset，累加当前节点的子节点数量
        offset += (item.subQuestions.length - 1);
      } else {
        // 如果没有子节点，设置offset为当前累计值
        result.offset = offset;
        result.isSubQuestion = false;
        result.virtualIndex = result.index + offset;
      }
      return result;
    });
  }
  // 将ExamineeQuestion转为Question
  const setQuestionList = (list: Study.ExamineeQuestion[]) => {
    const orders = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'];
    // 数据预处理
    // 1、给每个项目补充额外字段
    const transerQuestion = (item: Study.ExamineeQuestion, index: number): Study.Question => {
      return {
        ...item,
        title: decodeHtmlEntities(item.title || ''),
        // 处理没有题型的大题，统一作为阅读题
        typeId: (item.typeId === null || item.typeId === undefined) ? EnumQuestionType.OTHER : item.typeId,
        answers: item.answers || [],
        subQuestions: item.subQuestions?.map(transerQuestion) || [],
        options: item.options?.map((option, index) => {
          // 移除选项编号（如 A.）并解码 HTML 实体（如 &iacute; → í）
          const cleanedOption = option.replace(/[A-Z]\./g, '').replace(/\s/g, ' ');
          return {
            name: decodeHtmlEntities(cleanedOption),
            no: orders[index],
            id: index,
            isAnswer: false,
            isCorrect: false,
            isSelected: false
          } as Study.QuestionOption
        }) || [],
        totalScore: item.totalScore || 0,
        offset: 0,
        index: index,
        virtualIndex: 0,
        duration: 0,
        activeSubIndex: 0,
        hasSubQuestions: item.subQuestions && item.subQuestions.length > 0,
        typeTitle: item.typeTitle
      } as Study.Question
    }
    questionList.value = transerQuestions(list.map((item, index) => transerQuestion(item, index)));
  }
  /// 重置题目状态
  const reset = () => {
    questionList.value = questionList.value.map(item => {
      return {
        ...item,
        answers: [],
        isMark: false,
        isNotKnow: false,
        hasParsed: false,
        showParse: false,
        subQuestions: item.subQuestions.map(subItem => {
          return {
            ...subItem,
            answers: [],
            isMark: false,
            isNotKnow: false,
            hasParsed: false,
            showParse: false,
            duration: 0, // 清空做题时长
          }
        }),
        options: item.options.map(option => {
          return {
            ...option,
            isAnswer: false,
            isCorrect: false,
            isSelected: false,
            isMissed: false,
            isIncorrect: false
          }
        }),
        duration: 0, // 清空做题时长
      }
    });
    changeIndex(0);
    practiceDuration.value = 0;
    practiceAccumulatedTime = 0;
    practiceStartTime = 0;
    examDuration.value = 0;
    interval && clearInterval(interval);
    interval = null;
    if (animationFrameId !== null) {
      cancelAnimFrame(animationFrameId);
      animationFrameId = null;
    }
  }
  /// 设置子题下标
  const setSubQuestionIndex = (index: number) => {
    currentQuestion.value.activeSubIndex = index;
  }
  // 切换阅卷模式
  const setPracticeSettings = (settings: Study.PracticeSettings) => {
    practiceSettings.value = settings;
  }
  const submit = () => {
    updateQuestionDuration(virtualCurrentIndex.value, false);
  }
  watch([() => currentIndex.value, () => currentQuestion.value?.activeSubIndex], (val) => {
    const qs = questionList.value[val[0]];
    virtualCurrentIndex.value = qs.index + qs.offset + val[1];
  }, {
    immediate: false
  });
  return {
    practiceSettings,
    questionList,
    groupedQuestionList,
    stateQuestionList,
    flatQuestionList,
    favoriteList,
    notKnowList,
    markList,
    currentIndex,
    isAllDone,
    totalCount,
    virtualCurrentIndex,
    virtualTotalCount,
    subQuestionIndex,
    setSubQuestionIndex,
    doneCount,
    notDoneCount,
    questionTypeDesc,
    currentSubQuestion,
    prevEnable,
    nextEnable,
    nextQuestion,
    prevQuestion,
    nextQuestionQuickly,
    prevQuestionQuickly,
    swiperDuration,
    practiceDuration,
    examDuration,
    formatExamDuration,
    formatPracticeDuration,
    startTiming,
    stopTiming,
    setDuration,
    startCountdown,
    stopExamDuration,
    setExamDuration,
    setPracticeDuration,
    setCountDownCallback,
    setQuestionList,
    changeIndex,
    reset,
    submit,
    isQuestionCorrect,
    isOptionCorrect,
    setPracticeSettings,
  }
}