<template>
  <div class="flex gap-2 items-center flex-wrap">
    <NUpload :custom-request="upload" :show-file-list="false" multiple>
      <NButton size="small"> 添加附件 </NButton>
    </NUpload>
    <div
      v-for="a in attachments"
      :key="a.id"
      class="text-xs px-2 py-1 bg-neutral-100 rounded flex items-center gap-1"
    >
      <span>{{ a.filename }} ({{ Math.round(a.size_bytes / 1024) }} KB)</span>
      <NButton text size="tiny" @click="remove(a.id)"> × </NButton>
    </div>
  </div>
</template>

<script setup lang="ts">
import { ref, watch } from 'vue'
import { NUpload, NButton, useMessage } from 'naive-ui'
import type { UploadCustomRequestOptions } from 'naive-ui'

import { chatApi, type Attachment } from '@/api/chat'

const props = defineProps<{
  modelCapabilities?: { image: boolean; pdf: boolean; audio?: boolean }
}>()
const emit = defineEmits<{ change: [ids: string[]] }>()

const attachments = ref<Attachment[]>([])
const msg = useMessage()

const MAX_ATTACHMENT_SIZE_MB = 20
const MAX_ATTACHMENT_SIZE_BYTES = MAX_ATTACHMENT_SIZE_MB * 1024 * 1024

async function upload(opts: UploadCustomRequestOptions) {
  const f = opts.file.file
  if (!f) {
    opts.onError()
    return
  }
  if (f.type.startsWith('image/') && !props.modelCapabilities?.image) {
    msg.error('当前模型不支持图片')
    opts.onError()
    return
  }
  if (f.type === 'application/pdf' && !props.modelCapabilities?.pdf) {
    msg.error('当前模型不支持 PDF')
    opts.onError()
    return
  }
  if (f.type.startsWith('audio/') && !props.modelCapabilities?.audio) {
    msg.error('当前模型不支持音频')
    opts.onError()
    return
  }
  if (f.size > MAX_ATTACHMENT_SIZE_BYTES) {
    msg.error(`单文件不能超过 ${MAX_ATTACHMENT_SIZE_MB} MB`)
    opts.onError()
    return
  }
  try {
    const a = await chatApi.uploadAttachment(f)
    attachments.value.push(a)
    opts.onFinish()
  } catch (e) {
    msg.error(e instanceof Error ? e.message : String(e))
    opts.onError()
  }
}

function remove(id: string) {
  attachments.value = attachments.value.filter((a) => a.id !== id)
}

watch(
  () => attachments.value.map((a) => a.id),
  () =>
    emit(
      'change',
      attachments.value.map((a) => a.id),
    ),
)

defineExpose({
  clear: () => {
    attachments.value = []
  },
})
</script>
