<script setup lang="ts">
const props = withDefaults(
  defineProps<{
    stem: string
    answer?: string | null
    submitAnswer?: string
    reportFlag: number
    isDeadline?: boolean
  }>(),
  {
    submitAnswer: '',
    isDeadline: true,
  },
)

const emit = defineEmits(['submit'])

defineOptions({ inheritAttrs: false })

interface ParsedOption {
  label: string
  html: string
}

interface ParsedQuestion {
  index: number
  stemHtml: string
  options: ParsedOption[]
}

const parsedQuestions = computed<ParsedQuestion[]>(() => {
  if (!props.stem) return []
  try {
    const parser = new DOMParser()
    const doc = parser.parseFromString(props.stem, 'text/html')
    const sqEls = doc.querySelectorAll('.qml-sq')

    return Array.from(sqEls).map((sq, idx) => {
      const stemEl = sq.querySelector('.qml-stem')
      let stemHtml = ''
      if (stemEl) {
        const cloned = stemEl.cloneNode(true) as HTMLElement
        cloned.querySelectorAll('.qml-og').forEach(el => el.remove())
        const quesNo = cloned.querySelector('.ques-no')
        if (quesNo) quesNo.remove()
        stemHtml = cloned.innerHTML.trim()
      }

      const options: ParsedOption[] = []

      // table 格式: .qml-og td
      sq.querySelectorAll('.qml-og td').forEach(td => {
        const opSpan = td.querySelector('.qml-op')
        const text = td.textContent?.trim() || ''
        const match = text.match(/^([A-Z])\./)
        if (match) {
          options.push({
            label: match[1],
            html: opSpan?.innerHTML || '',
          })
        }
      })

      // inline 格式: .qml-og 内直接放 .qml-op（无 table）
      if (options.length === 0) {
        const ogEl = sq.querySelector('.qml-og')
        if (ogEl) {
          ogEl.querySelectorAll('.qml-op').forEach((opSpan, oIdx) => {
            options.push({
              label: String.fromCharCode(65 + oIdx),
              html: opSpan.innerHTML || '',
            })
          })
        }
      }

      return { index: idx, stemHtml, options }
    })
  } catch {
    return []
  }
})

const answerArray = computed(
  () =>
    props.answer
      ?.split(',')
      .map(s => s.trim())
      .filter(Boolean) || [],
)

const selectedAnswers = ref<string[]>([])

watch(
  [() => props.submitAnswer, () => parsedQuestions.value.length],
  ([val, total]) => {
    const arr = val ? val.split(',').map(s => s.trim()) : []
    while (arr.length < total) arr.push('')
    selectedAnswers.value = arr
  },
  { immediate: true },
)

function handleSelect(qIdx: number, label: string) {
  if (props.reportFlag) return
  const total = parsedQuestions.value.length
  const arr = [...selectedAnswers.value]
  while (arr.length < total) arr.push('')
  arr[qIdx] = label
  selectedAnswers.value = arr
  emit('submit', { submitAnswer: arr.join(',') })
}
</script>

<template>
  <div class="composite-stem">
    <div v-for="q in parsedQuestions" :key="q.index" class="composite-q">
      <div class="composite-q-header">
        <span class="composite-q-no">{{ q.index + 1 }}.</span>
        <div class="composite-q-text" v-html="q.stemHtml"></div>
      </div>
      <div class="composite-q-options">
        <div
          v-for="opt in q.options"
          :key="opt.label"
          :class="{
            'composite-q-option': true,
            pointer: !reportFlag,
            active: !reportFlag && selectedAnswers[q.index] === opt.label,
            success: isDeadline && !!reportFlag && answerArray[q.index] === opt.label,
            fail:
              isDeadline &&
              !!reportFlag &&
              selectedAnswers[q.index] === opt.label &&
              answerArray[q.index] !== opt.label,
          }"
          @click="handleSelect(q.index, opt.label)"
        >
          <div class="option-label">{{ opt.label }}</div>
          <div class="option-content" v-html="opt.html"></div>
        </div>
      </div>
    </div>
    <slot name="markAnswer"></slot>
  </div>
</template>

<style scoped lang="scss">
.composite-stem {
  overflow-y: auto;
}

.composite-q {
  margin-bottom: 3vh;

  &:last-child {
    margin-bottom: 0;
  }

  &-header {
    display: flex;
    align-items: flex-start;
    margin-bottom: 1.5vh;
  }

  &-no {
    font-family: $font-special;
    font-size: 2.67vh;
    font-weight: 700;
    color: #4f8ef7;
    margin-right: 6px;
    flex-shrink: 0;
    line-height: 1.6;
  }

  &-text {
    flex: 1;
    font-size: 2.67vh;
    color: $font-color;
    line-height: 1.6;

    :deep(img) {
      max-width: 100%;
      height: auto;
    }
  }

  &-options {
    padding-left: 2.5vh;
  }

  &-option {
    min-height: 6vh;
    border-radius: 1.2vh;
    border: 0.33vh solid #bed5fe;
    background: #f7faf9;
    display: flex;
    margin-bottom: 1.2vh;
    overflow: hidden;
    transition: all 0.2s;

    &:last-child {
      margin-bottom: 0;
    }

    .option-label {
      width: 60px;
      display: flex;
      align-items: center;
      justify-content: center;
      flex-shrink: 0;
      background-color: #f1f6fe;
      border-right: 0.33vh solid #bed5fe;
      color: #669cfe;
      font-family: Arial;
      font-size: 2.67vh;
      font-weight: 400;
    }

    .option-content {
      flex: 1;
      color: $font-color;
      font-family: Arial;
      font-size: 2.67vh;
      line-height: 1.6;
      padding: 1vh 16px;
      display: flex;
      align-items: center;
      flex-wrap: wrap;

      :deep(img) {
        max-width: 100%;
        height: auto;
      }
    }

    &.pointer {
      cursor: pointer;
    }

    &.active {
      border-color: #669cfe;

      .option-label {
        color: #fff;
        background-color: #a5c5fe;
        border-color: #669cfe;
      }
    }

    &.fail {
      border-color: #f00a0a;

      .option-label {
        color: #f00a0a;
        background-color: #febebf;
        border-color: #f00a0a;
      }
    }

    &.success {
      border-color: #8fcc00;

      .option-label {
        color: #8fcc00;
        background-color: #ddff8c;
        border-color: #8fcc00;
      }
    }
  }
}
</style>
