// 评论框的组件 用于评论的输入 以及 表情 图片的输入 以及 发表按钮
<script setup lang="ts">
import RichTextarea from '../RichTextarea/index.vue'
import UploadImgIcon from '../UploadImgIcon/index.vue'
import UploadEmojiIcon from '../UploadEmojiIcon/index.vue'
import { useUploadImg } from '@/hooks'
import type { IEmoji } from '@/utils/emoji/type'
import { MENTION_USER_FN_KEY, IS_REAL_KEY_COMMENT } from '@/constants/symbolKey'

const isReal = inject(IS_REAL_KEY_COMMENT, 0)
function escapeHtml(str: string) {
  return str
    .replace(/&/g, '&amp;')
    .replace(/</g, '&lt;')
    .replace(/>/g, '&gt;')
    .replace(/"/g, '&quot;')
    .replace(/'/g, '&#39;')
}

/** 将纯文本中的 @昵称 转为带 data-id 的 span（仅对在 MentionBox 中选中的用户生效） */
function buildAnswerHtml(source: string, mentionUsers: Array<{ userId: string; name: string }>) {
  const mentions = mentionUsers
    .filter((u) => u?.name)
    .sort((a, b) => b.name.length - a.name.length)
    .map((u) => ({ token: `@${u.name}`, userId: String(u.userId) }))

  const isBoundary = (ch: string | undefined) => !ch || /\s/.test(ch)

  let html = ''
  let i = 0
  while (i < source.length) {
    const prev = i > 0 ? source[i - 1] : undefined
    const matched = mentions.find(({ token }) => {
      if (!source.startsWith(token, i)) return false
      const next = source[i + token.length]
      return isBoundary(prev) && isBoundary(next)
    })

    if (matched) {
      html += `<span contenteditable="false" data-id="${escapeHtml(matched.userId)}" data-isreal="${unref(isReal)}" style="color: #2563eb;cursor:pointer;">${escapeHtml(matched.token)}</span>&nbsp;`
      i += matched.token.length
      continue
    }

    html += escapeHtml(source.charAt(i))
    i++
  }
  return html
}

interface CommentBoxProps {
  textAreaHeight?: number
  placeholder?: string
  showMention?: boolean
}

const {
  textAreaHeight = 55,
  placeholder = '请输入内容',
  showMention = true,
} = defineProps<CommentBoxProps>()

const inputStr = defineModel<string>('inputText', { required: true })
const imgStrs = defineModel<string>('inputImg', { required: true })

const { uploadPercent, imgList, handleFileChange, handleDeleteImg } = useUploadImg(imgStrs)
const richTextareaRef = useTemplateRef<InstanceType<typeof RichTextarea>>('richTextareaRef')

const handleSelectEmoji = async (emoji: IEmoji) => {
  const textarea = richTextareaRef.value?.getTextarea()
  if (!textarea) return

  // 当选中一段文本时 这俩值是不一样
  const start = textarea.selectionStart
  const end = textarea.selectionEnd
  const value = inputStr.value

  // 插入内容（你可以是 [微笑]，也可以是 😀）
  inputStr.value = value.slice(0, start) + emoji.name + value.slice(end)

  // 插入后把光标放到表情后面
  await nextTick()
  textarea.focus()
  textarea.selectionStart = textarea.selectionEnd = start + emoji.name.length
}

const mentionFnObj: {
  getMentionUserIds?: () => string[]
  getMentionUsers?: () => Array<{ userId: string; name: string }>
} = {}
provide(MENTION_USER_FN_KEY, mentionFnObj)

const getAnswerHtml = (): string =>
  buildAnswerHtml(inputStr.value ?? '', mentionFnObj.getMentionUsers?.() ?? [])

defineExpose({
  focus: async () => {
    await nextTick()
    richTextareaRef.value?.getTextarea()?.focus()
  },
  getMentionFns: () => {
    return mentionFnObj
  },
  getAnswerHtml,
})
</script>

<template>
  <div>
    <RichTextarea
      ref="richTextareaRef"
      v-model="inputStr"
      :imgList="imgList"
      :uploadPercent="uploadPercent"
      @deleteImg="handleDeleteImg"
      :height="textAreaHeight"
      :placeholder="placeholder"
      :showMention="showMention"
    />
    <div class="flex justify-between items-center mt-3">
      <div class="flex items-center gap-2">
        <UploadImgIcon @fileChange="handleFileChange" />
        <UploadEmojiIcon @selectEmoji="handleSelectEmoji" />
      </div>
      <div>
        <!-- 插槽 用于插入 发表按钮 -->
        <slot name="submit" />
      </div>
    </div>
  </div>
</template>

<style scoped></style>
