<template>
  <div class="x-markdown-section-extractor">
    <!-- 左上角上传按钮 -->
    <div v-if="showUploadButton" class="extractor-header">
      <input
        ref="fileInput"
        type="file"
        accept=".md,.markdown,text/markdown"
        class="file-input"
        @change="handleFileUpload"
      >
    </div>

    <!-- 渲染 extractAs 返回的 sections -->
    <div v-if="renderedSections.length" class="rendered-sections">
      <div v-for="(sec, idx) in renderedSections" :key="idx" class="section-block">
        <div class="section-title">{{ sec.sectionTitle }}</div>
        <div v-for="(item, iIdx) in sec.items" :key="iIdx" class="item-block">
          <div class="item-title">{{ item.title }}</div>
          <div v-if="item.content.length" class="item-list">
            <div
              v-for="(c, cIdx) in item.content"
              :key="cIdx"
              class="list-item"
              :class="{ 'is-selected': isItemSelected(idx, iIdx, cIdx) }"
              @click="toggleItem(idx, iIdx, cIdx)"
            >
              <span class="radio-wrapper">
                <span class="radio-inner"></span>
              </span>
              <span class="item-number">{{ cIdx + 1 }}.</span>
              <span class="item-text">{{ c }}</span>
            </div>
          </div>
          <input
            type="text"
            class="custom-input"
            :class="{ 'has-content': isCustomActive(idx, iIdx) }"
            v-model="customInputs[`${idx}-${iIdx}`]"
            :placeholder="'其他（请输入）'"
            @focus="onCustomInputFocus(idx, iIdx)"
            @input="emitCustomInput(idx, iIdx)"
          >
        </div>
      </div>
    </div>

    <slot
      :sections="sections"
      :itemsArray="itemsArray"
      :itemsByKey="itemsByKey"
      :formattedData="computedFormattedData"
      :loading="loading"
      :error="error"
    />
  </div>
</template>

<script>
import { readMarkdownAsText } from '@vue2-client/base-client/components/common/XMarkdownViewer'
import {
  extractSectionsFromMarkdown,
  flattenSectionsToItemsArray,
  flattenSectionsToItemsByKey,
  convertToFormat,
  extractByKeywords
} from './markdownSectionExtractor'

export default {
  name: 'XMarkdownSectionExtractor',
  props: {
    source: {
      type: [String, Object],
      required: true
    },
    sectionsConfig: {
      type: Array,
      default: () => []
    },
    autoExtract: {
      type: Boolean,
      default: true
    },
    outputFormat: {
      type: String,
      default: 'default',
      validator: (value) => {
        return ['default', 'xlist-default', 'xlist-card', 'xlist-title-content'].includes(value)
      }
    },
    outputOptions: {
      type: Object,
      default: () => ({})
    },
    showUploadButton: {
      type: Boolean,
      default: true
    }
  },
  data () {
    return {
      loading: false,
      error: null,
      sections: [],
      itemsArray: [],
      itemsByKey: {},
      formattedData: null,
      currentSource: null,
      renderedSections: [],
      selectedItems: {},
      customInputs: {},
      // 追踪每个分组最后操作的是什么：'custom' | 'option' | null
      lastActiveInput: {}
    }
  },
  computed: {
    computedFormattedData () {
      if (!this.sections || this.sections.length === 0) {
        return this.outputFormat === 'default' ? [] : (this.outputFormat === 'xlist-card' ? [] : [])
      }
      return convertToFormat(this.sections, this.outputFormat, this.outputOptions)
    }
  },
  watch: {
    source: {
      handler (val) {
        this.currentSource = val
        if (this.autoExtract) {
          this.extract()
        }
      },
      immediate: true,
      deep: false
    },
    sectionsConfig: {
      handler () {
        if (this.autoExtract) {
          this.extract()
        }
      },
      deep: true
    },
    outputFormat: {
      handler () {
        this.$emit('update:formattedData', this.computedFormattedData)
        this.$emit('formatted-data', this.computedFormattedData)
      }
    },
    outputOptions: {
      handler () {
        this.$emit('update:formattedData', this.computedFormattedData)
        this.$emit('formatted-data', this.computedFormattedData)
      },
      deep: true
    }
  },
  methods: {
    handleFileUpload (event) {
      const file = event.target.files && event.target.files[0]
      if (!file) return

      if (!file.name.endsWith('.md') && !file.name.endsWith('.markdown') && file.type !== 'text/markdown') {
        this.$emit('error', new Error('请上传 .md 或 .markdown 文件'))
        return
      }

      this.$emit('upload', file)
      this.currentSource = file
      this.extract()

      event.target.value = ''
    },
    /**
     * 设置 markdown 内容（传入字符串）
     * @param {string} markdownText - markdown 格式的字符串
     */
    setSource (markdownText) {
      if (typeof markdownText !== 'string') {
        console.warn('[XMarkdownSectionExtractor] setSource requires a string')
        return
      }
      this.currentSource = markdownText
      this.$emit('source-changed', markdownText)
    },
    async extract () {
      if (!this.currentSource) {
        return
      }
      this.loading = true
      this.error = null
      try {
        const text = await readMarkdownAsText(this.currentSource)
        const sections = extractSectionsFromMarkdown(text, this.sectionsConfig || [])
        this.sections = sections
        const itemsArray = flattenSectionsToItemsArray(sections)
        this.itemsArray = itemsArray
        const itemsByKey = flattenSectionsToItemsByKey(sections)
        this.itemsByKey = itemsByKey
        const formattedData = convertToFormat(sections, this.outputFormat, this.outputOptions)
        this.formattedData = formattedData
        this.$emit('update:sections', sections)
        this.$emit('update:itemsArray', itemsArray)
        this.$emit('update:itemsByKey', itemsByKey)
        this.$emit('update:formattedData', formattedData)
        this.$emit('extracted', sections)
        this.$emit('extracted-items', itemsArray)
        this.$emit('extracted-items-by-key', itemsByKey)
        this.$emit('formatted-data', formattedData)
        return sections
      } catch (e) {
        console.error('[XMarkdownSectionExtractor] 抽取失败:', e)
        this.error = e
        this.sections = []
        this.itemsArray = []
        this.itemsByKey = {}
        this.formattedData = null
        this.$emit('error', e)
        return []
      } finally {
        this.loading = false
      }
    },
    async extractAs (keywords = [], parseType = 'title-content') {
      if (!Array.isArray(keywords) || keywords.length === 0) {
        return []
      }
      if (!this.currentSource) {
        console.warn('[XMarkdownSectionExtractor] currentSource is not set, call setSource() first')
        return []
      }
      const config = keywords.map((label, idx) => ({
        key: `section_${idx}`,
        label,
        headingLevel: 3
      }))
      try {
        // 读取 markdown 内容（支持字符串、文件、URL 等）
        const text = await readMarkdownAsText(this.currentSource)
        if (!text) {
          console.warn('[XMarkdownSectionExtractor] No text content from source')
          return []
        }
        const sections = extractSectionsFromMarkdown(text, config)
        console.log('[extractAs] sections:', JSON.stringify(sections, null, 2))
        if (parseType === 'flat') {
          return flattenSectionsToItemsArray(sections)
        }
        const result = sections.map(sec => ({
          sectionTitle: sec.label || '',
          items: Array.isArray(sec.hierarchicalItems)
            ? sec.hierarchicalItems.map(h => ({
              title: h.title || '',
              content: Array.isArray(h.items) ? h.items : []
            }))
            : []
        }))
        console.log('[extractAs] result:', JSON.stringify(result, null, 2))
        // 创建新数组引用以确保 Vue 响应式更新
        const newSections = [...this.renderedSections, ...result]
        this.renderedSections = newSections
        // 强制更新视图
        this.$forceUpdate()
        // 等待 DOM 更新后发送事件
        this.$nextTick(() => {
          this.$emit('sections-rendered', this.renderedSections)
        })
        return result
      } catch (e) {
        console.error('[XMarkdownSectionExtractor] extractAs error:', e)
        return []
      }
    },
    toggleItem (sectionIdx, itemIdx, contentIdx) {
      const groupKey = `${sectionIdx}-${itemIdx}`
      const key = `${groupKey}-${contentIdx}`

      if (this.selectedItems[groupKey] === key) {
        this.$delete(this.selectedItems, groupKey)
        // 如果取消选择，清除最后操作记录
        this.$delete(this.lastActiveInput, groupKey)
      } else {
        this.selectedItems = {
          ...this.selectedItems,
          [groupKey]: key
        }
        // 记录最后操作的是选项
        this.lastActiveInput = {
          ...this.lastActiveInput,
          [groupKey]: 'option'
        }
      }
      this.$emit('selection-change', this.getSelectedItems())
    },
    isItemSelected (sectionIdx, itemIdx, contentIdx) {
      const groupKey = `${sectionIdx}-${itemIdx}`
      const key = `${groupKey}-${contentIdx}`
      return this.selectedItems[groupKey] === key
    },
    getSelectedItems () {
      const result = []

      this.renderedSections.forEach((sec, secIdx) => {
        if (Array.isArray(sec.items)) {
          sec.items.forEach((item, itemIdx) => {
            const groupKey = `${secIdx}-${itemIdx}`
            const lastActive = this.lastActiveInput[groupKey]

            // 根据最后操作决定使用哪个值
            if (lastActive === 'custom' && this.customInputs[groupKey]) {
              // 最后操作的是自定义输入
              result.push({
                sectionTitle: sec.sectionTitle,
                sectionIndex: secIdx,
                itemTitle: item.title,
                itemIndex: itemIdx,
                contentIndex: -1,
                content: this.customInputs[groupKey],
                isCustom: true
              })
            } else if (lastActive === 'option' && this.selectedItems[groupKey]) {
              // 最后操作的是选项
              const keyParts = this.selectedItems[groupKey].split('-')
              const contentIdx = parseInt(keyParts[keyParts.length - 1])
              const content = item.content[contentIdx]
              result.push({
                sectionTitle: sec.sectionTitle,
                sectionIndex: secIdx,
                itemTitle: item.title,
                itemIndex: itemIdx,
                contentIndex: contentIdx,
                content: content,
                isCustom: false
              })
            } else if (!lastActive && this.customInputs[groupKey]) {
              // 没有任何操作记录，但有自定义输入（兼容旧逻辑）
              result.push({
                sectionTitle: sec.sectionTitle,
                sectionIndex: secIdx,
                itemTitle: item.title,
                itemIndex: itemIdx,
                contentIndex: -1,
                content: this.customInputs[groupKey],
                isCustom: true
              })
            } else if (!lastActive && this.selectedItems[groupKey]) {
              // 没有任何操作记录，但有选项选中（兼容旧逻辑）
              const keyParts = this.selectedItems[groupKey].split('-')
              const contentIdx = parseInt(keyParts[keyParts.length - 1])
              const content = item.content[contentIdx]
              result.push({
                sectionTitle: sec.sectionTitle,
                sectionIndex: secIdx,
                itemTitle: item.title,
                itemIndex: itemIdx,
                contentIndex: contentIdx,
                content: content,
                isCustom: false
              })
            }
          })
        }
      })

      return result
    },
    clearSelection () {
      this.selectedItems = {}
      this.customInputs = {}
      this.lastActiveInput = {}
      this.$emit('selection-change', [])
    },
    clearRenderedSections () {
      this.renderedSections = []
      this.selectedItems = {}
      this.customInputs = {}
      this.lastActiveInput = {}
      this.$emit('sections-cleared')
    },
    emitCustomInput (sectionIdx, itemIdx) {
      const groupKey = `${sectionIdx}-${itemIdx}`
      const value = this.customInputs[groupKey] || ''

      // 记录最后操作的是自定义输入
      this.lastActiveInput = {
        ...this.lastActiveInput,
        [groupKey]: 'custom'
      }

      this.$emit('custom-input', {
        sectionIdx,
        itemIdx,
        value
      })
      this.$emit('selection-change', this.getSelectedItems())
    },
    onCustomInputFocus (sectionIdx, itemIdx) {
      const groupKey = `${sectionIdx}-${itemIdx}`
      // 聚焦时标记为自定义激活，同时清除选项选择
      this.lastActiveInput = {
        ...this.lastActiveInput,
        [groupKey]: 'custom'
      }
      // 清除该分组的选项选中状态
      if (this.selectedItems[groupKey]) {
        this.$delete(this.selectedItems, groupKey)
        this.$emit('selection-change', this.getSelectedItems())
      }
    },
    isCustomActive (sectionIdx, itemIdx) {
      const groupKey = `${sectionIdx}-${itemIdx}`
      return this.lastActiveInput[groupKey] === 'custom'
    },
    /**
     * 重置内容区域，清除所有状态
     */
    resetContent () {
      this.loading = false
      this.error = null
      this.sections = []
      this.itemsArray = []
      this.itemsByKey = {}
      this.formattedData = null
      this.currentSource = null
      this.renderedSections = []
      this.selectedItems = []
      this.customInputs = {}
      this.lastActiveInput = {}
      this.$emit('content-reset')
    },
    forceRender () {
      this.$forceUpdate()
      this.$nextTick(() => {
        this.$emit('sections-rendered', this.renderedSections)
      })
    },
    /**
     * 根据关键字提取 markdown 中各区块的内容
     *
     * 用途：从一份 markdown 病历中按「主诉、现病史、既往史」等标题快速提取对应的区块内容。
     * 返回格式为数组，每个元素是一个以关键字为 key 的对象。
     *
     * 规则：
     * - 每个关键字会找到对应标题（默认 2 级标题即 ## 开头），提取从该标题到下一个同级或更高等级标题之前的内容
     * - 若文档中没有匹配的关键字，则内容为空字符串
     * - 只返回有匹配的关键字，未匹配的不返回
     *
     * @param {string} markdownText - markdown 格式的字符串
     * @param {string[]} keywords - 关键字数组，如 ['主诉', '现病史', '既往史']
     * @param {Object} [options] - 可选配置
     * @param {number} [options.headingLevel=2] - 标题级别，默认 2（对应 ##），可设为 3（对应 ###）等
     * @param {boolean} [options.trimContent=true] - 是否去除内容首尾空白，默认为是
     * @param {boolean} [options.stripMarkdown=true] - 是否去除 markdown 格式符号（如 **、-、引用等），默认为是
     * @returns {Array<Object>} - 数组，每个元素以关键字为 key，如 [{ "主诉": "反复左额部..." }, { "现病史": "患者女性..." }]
     *
     * @example
     * const result = this.extractByKeywords(markdownString, ['主诉', '现病史', '既往史'])
     * // result = [
     * //   { "主诉": "反复左额部搏动性疼痛2年余，加重伴呕吐1天。" },
     * //   { "现病史": "患者女性，2年前无明显诱因出现左侧额部头痛..." }
     * // ]
     */
    extractByKeywords (markdownText, keywords, options) {
      if (typeof markdownText !== 'string') {
        console.warn('[XMarkdownSectionExtractor] extractByKeywords requires a string as first argument')
        return []
      }
      return extractByKeywords(markdownText, keywords, options)
    }
  }
}
</script>

<style lang="less" scoped>
.x-markdown-section-extractor {
  display: block;
  width: 100%;
  max-height: 450px;
  overflow-y: auto;
  overflow-x: hidden;
}

.extractor-header {
  margin-bottom: 8px;
}

.file-input {
  display: none;
}

.rendered-sections {
  padding: 16px;
  background: #FFFFFF;
  box-sizing: border-box;
  border: 1px solid #E5E9F0;
  border-radius: 8px;
  margin: 5px;
}

.section-block {
  margin-bottom: 20px;
  padding-bottom: 16px;
  border-bottom: 1px dashed #e8e8e8;

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

.section-title {
  font-family: Source Han Sans, -apple-system, BlinkMacSystemFont, sans-serif;
  font-size: 16px;
  font-weight: bold;
  line-height: normal;
  text-align: justify;
  letter-spacing: 0em;
  font-feature-settings: "kern" on;
  color: #313131;
  margin-bottom: 12px;
}

.item-block {
  margin: 8px 0 8px 0;
  padding-left: 0;
}

.item-title {
  font-family: Source Han Sans, -apple-system, BlinkMacSystemFont, sans-serif;
  font-size: 16px;
  font-weight: bold;
  line-height: normal;
  text-align: justify;
  letter-spacing: 0em;
  font-feature-settings: "kern" on;
  color: #313131;
  margin-bottom: 6px;
}

.item-list {
  padding-left: 0;
}

.list-item {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 6px 8px;
  font-family: Source Han Sans, -apple-system, BlinkMacSystemFont, sans-serif;
  font-size: 16px;
  font-weight: normal;
  line-height: normal;
  text-align: justify;
  letter-spacing: 0em;
  font-variation-settings: "opsz" auto;
  font-feature-settings: "kern" on;
  color: #313131;
  border-radius: 4px;
  cursor: pointer;

  &.is-selected {
    .item-number,
    .item-text {
      color: #313131;
    }
  }
}

.item-number {
  font-family: Source Han Sans, -apple-system, BlinkMacSystemFont, sans-serif;
  font-size: 16px;
  font-weight: normal;
  color: #313131;
  margin-left: 0;
}

.item-text {
  font-family: Source Han Sans, -apple-system, BlinkMacSystemFont, sans-serif;
  font-size: 16px;
  font-weight: normal;
  line-height: normal;
  text-align: justify;
  letter-spacing: 0em;
  font-variation-settings: "opsz" auto;
  font-feature-settings: "kern" on;
  color: #313131;
}

/* 单选框样式 */
.radio-wrapper {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 16px;
  height: 16px;
  min-width: 16px;
  background: #FFFFFF;
  border: 1px solid #CDCFD4;
  border-radius: 50%;
  box-sizing: border-box;
  cursor: pointer;
  transition: all 0.2s ease;
}

.radio-inner {
  width: 10px;
  height: 10px;
  background: #0057FE;
  border-radius: 50%;
  opacity: 0;
  transform: scale(0);
  transition: all 0.2s ease;
}

.list-item.is-selected .radio-wrapper {
  border-color: #0057FE;
}

.list-item.is-selected .radio-inner {
  opacity: 1;
  transform: scale(1);
}

.custom-input {
  height: 32px;
  margin-top: 8px;
  padding: 0 12px;
  border-radius: 7px;
  opacity: 1;
  background: #FFFFFF;
  box-sizing: border-box;
  border: 1px solid #E5E9F0;
  font-family: Source Han Sans, -apple-system, BlinkMacSystemFont, sans-serif;
  font-size: 14px;
  color: #313131;
  outline: none;
  width: 100%;

  &::placeholder {
    color: #999;
  }

  &.has-content {
    border: 2px solid #0057FE;

    &:focus {
      box-shadow: 0 0 0 2px rgba(0, 87, 254, 0.1);
    }
  }

  &:focus {
    border-color: #0057FE;
    box-shadow: 0 0 0 2px rgba(0, 87, 254, 0.1);
  }
}
</style>
