<script lang="ts" setup>
import { number, object, string, type InferType } from 'yup'
import type { FormSubmitEvent } from '#ui/types'
import dayjs from 'dayjs'

const toast = useToast()
const loginState = useLoginState()

const isCreateSlideOpen = ref(false)
const isCatSlideOpen = ref(false)

const { data: pptCategories, refresh: refreshPPTCategories } = useAsyncData(
  'pptCategories',
  () =>
    useFetchWrapped<
      PagedDataRequest & AuthedRequest,
      BaseResponse<PagedData<PPTCategory>>
    >('App.Digital_PowerPointCat.GetList', {
      token: loginState.token!,
      user_id: loginState.user.id,
      page: 1,
      perpage: 20,
    })
)

const selectedCat = ref<number>(0)
const pagination = reactive({
  page: 1,
  perpage: 18,
})

const { data: pptTemplates, refresh: refreshPptTemplates } = useAsyncData(
  'pptTemplates',
  () =>
    useFetchWrapped<
      PagedDataRequest & { type: string | number } & AuthedRequest,
      BaseResponse<PagedData<PPTTemplate>>
    >('App.Digital_PowerPoint.GetList', {
      token: loginState.token!,
      user_id: loginState.user.id,
      page: pagination.page,
      perpage: pagination.perpage,
      type: selectedCat.value === 0 ? '' : selectedCat.value,
    }),
  {
    watch: [selectedCat, pagination],
  }
)

const onDownloadClick = (ppt: PPTTemplate) => {
  const { download } = useDownload(ppt.file_url, `${ppt.title}.pptx`)
  download()
}

const pptCreateState = reactive({
  title: '',
  description: '',
  type: 0,
  preview_url: '',
  file_url: '',
})

const pptCreateSchema = object({
  title: string().required('模板标题不能为空'),
  description: string().required('模板描述不能为空'),
  type: number().notOneOf([0], '无效分类').required('请选择模板分类'),
  preview_url: string().required('请上传预览图'),
  file_url: string().required('请上传 PPT 文件'),
})

type PPTCreateSchema = InferType<typeof pptCreateSchema>

const selectMenuOptions = computed(() => {
  return pptCategories.value?.data.items.map((cat) => ({
    label: cat.type,
    value: cat.id,
  }))
})

const onCreateSubmit = (event: FormSubmitEvent<PPTCreateSchema>) => {
  useFetchWrapped<
    {
      title: string
      description: string
      type: number
      preview_url: string
      file_url: string
    } & AuthedRequest,
    BaseResponse<{ powerpoint_id: number }>
  >('App.Digital_PowerPoint.Create', {
    token: loginState.token!,
    user_id: loginState.user.id,
    title: event.data.title,
    description: event.data.description,
    type: event.data.type,
    preview_url: event.data.preview_url,
    file_url: event.data.file_url,
  })
    .then(async (res) => {
      if (res.data.powerpoint_id) {
        await refreshPPTCategories()
        toast.add({
          title: '创建成功',
          description: '已加入模板库',
          color: 'green',
          icon: 'i-tabler-check',
        })
        isCreateSlideOpen.value = false
        refreshPptTemplates()
        Object.assign(pptCreateState, {
          title: '',
          description: '',
          type: 0,
          preview_url: '',
          file_url: '',
        })
      }
    })
    .catch(() => {
      toast.add({
        title: '创建失败',
        description: '请检查输入是否正确',
        color: 'red',
        icon: 'i-tabler-alert-triangle',
      })
    })
}

const onFileSelect = async (files: FileList, type: 'preview' | 'ppt') => {
  const url = await useFileGo(files[0])
  if (type === 'preview') {
    pptCreateState.preview_url = url
  } else {
    pptCreateState.file_url = url
  }
  toast.add({
    title: '上传成功',
    description: `已上传 ${type === 'preview' ? '预览图' : 'PPT 文件'}`,
    color: 'green',
    icon: 'i-tabler-check',
  })
}

const onDeletePPT = (ppt: PPTTemplate) => {
  useFetchWrapped<
    { powerpoint_id: number } & AuthedRequest,
    BaseResponse<{ code: number }>
  >('App.Digital_PowerPoint.Delete', {
    token: loginState.token!,
    user_id: loginState.user.id,
    powerpoint_id: ppt.id,
  })
    .then(async (res) => {
      if (res.ret === 200 && res.data.code === 1) {
        await refreshPptTemplates()
        toast.add({
          title: '删除成功',
          description: '已删除模板',
          color: 'green',
          icon: 'i-tabler-check',
        })
      } else {
        toast.add({
          title: '删除失败',
          description: res.msg || '未知错误',
          color: 'red',
          icon: 'i-tabler-alert-triangle',
        })
      }
    })
    .catch(() => {
      toast.add({
        title: '删除失败',
        description: '未知错误',
        color: 'red',
        icon: 'i-tabler-alert-triangle',
      })
    })
}

const createCatInput = ref('')

const onCreateCat = () => {
  if (createCatInput.value) {
    useFetchWrapped<
      { type: string } & AuthedRequest,
      BaseResponse<{ ppt_cat_id: number }>
    >('App.Digital_PowerPointCat.Create', {
      token: loginState.token!,
      user_id: loginState.user.id,
      type: createCatInput.value,
    })
      .then(async (res) => {
        if (res.data.ppt_cat_id) {
          await refreshPPTCategories()
          toast.add({
            title: '创建成功',
            description: '已加入分类列表',
            color: 'green',
            icon: 'i-tabler-check',
          })
          createCatInput.value = ''
        }
      })
      .catch(() => {
        toast.add({
          title: '创建失败',
          description: '请检查输入是否正确',
          color: 'red',
          icon: 'i-tabler-alert-triangle',
        })
      })
  }
}

const onDeleteCat = (cat: PPTCategory) => {
  useFetchWrapped<
    { ppt_cat_id: number } & AuthedRequest,
    BaseResponse<{ code: number }>
  >('App.Digital_PowerPointCat.Delete', {
    token: loginState.token!,
    user_id: loginState.user.id,
    ppt_cat_id: cat.id,
  })
    .then(async (res) => {
      if (res.ret === 200 && res.data.code === 1) {
        await refreshPPTCategories()
        toast.add({
          title: '删除成功',
          description: '已删除分类',
          color: 'green',
          icon: 'i-tabler-check',
        })
      } else {
        toast.add({
          title: '删除失败',
          description: res.msg || '未知错误',
          color: 'red',
          icon: 'i-tabler-alert-triangle',
        })
      }
    })
    .catch(() => {
      toast.add({
        title: '删除失败',
        description: '请检查输入是否正确',
        color: 'red',
        icon: 'i-tabler-alert-triangle',
      })
    })
}
</script>

<template>
  <div>
    <div class="p-4 pb-0">
      <BubbleTitle
        title="PPT 模板库"
        subtitle="Slide Templates"
      >
        <template #action>
          <UButton
            v-if="loginState.user.auth_code === 2"
            label="分类管理"
            color="amber"
            variant="soft"
            icon="tabler:grid"
            @click="isCatSlideOpen = true"
          />
          <UButton
            v-if="loginState.user.auth_code === 2"
            label="创建模板"
            color="amber"
            variant="soft"
            icon="tabler:plus"
            @click="isCreateSlideOpen = true"
          />
        </template>
      </BubbleTitle>
      <GradientDivider />
    </div>
    <div class="p-4 pt-0">
      <!-- cat selector -->
      <div class="flex flex-wrap gap-2">
        <div
          v-for="cat in [
            { id: 0, type: '全部' },
            ...(pptCategories?.data.items || []),
          ]"
          @click="selectedCat = cat.id"
          :key="cat.id"
          :class="{
            'bg-primary text-white': selectedCat === cat.id,
            'bg-gray-100 text-gray-500': selectedCat !== cat.id,
          }"
          class="rounded-lg px-4 py-2 text-sm cursor-pointer"
        >
          {{ cat.type }}
        </div>
      </div>

      <div class="space-y-4">
        <div
          v-if="pptTemplates?.data.items.length === 0"
          class="w-full py-20 flex flex-col justify-center items-center gap-2"
        >
          <Icon
            class="text-7xl text-neutral-300 dark:text-neutral-700"
            name="i-tabler-photo-hexagon"
          />
          <p class="text-sm text-neutral-500 dark:text-neutral-400">
            暂时没有可用模板
          </p>
        </div>
        <div
          v-else
          class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 2xl:grid-cols-4 gap-4 mt-4"
        >
          <div
            v-for="ppt in pptTemplates?.data.items"
            :key="ppt.id"
            class="relative bg-white rounded-lg shadow-md overflow-hidden"
          >
            <NuxtImg
              :src="ppt.preview_url"
              :alt="ppt.title"
              class="w-full aspect-video object-cover"
            />
            <div
              class="absolute inset-x-0 bottom-0 p-3 pt-6 flex justify-between items-end bg-gradient-to-t from-black/50 to-transparent"
            >
              <div class="space-y-0.5">
                <h3 class="text-base font-bold text-white">{{ ppt.title }}</h3>
                <p class="text-xs font-medium text-neutral-200">
                  {{ ppt.description }}
                </p>
              </div>
              <div class="flex items-center gap-2">
                <!-- delete -->
                <UButton
                  v-if="loginState.user.auth_code === 2"
                  size="sm"
                  color="red"
                  icon="tabler:trash"
                  variant="soft"
                  @click="onDeletePPT(ppt)"
                />
                <UButton
                  label="下载"
                  size="sm"
                  color="primary"
                  icon="tabler:download"
                  @click="onDownloadClick(ppt)"
                />
              </div>
            </div>
          </div>
        </div>

        <div class="w-full flex justify-end">
          <UPagination
            v-if="pptTemplates?.data.total > pagination.perpage"
            :total="pptTemplates?.data.total"
            :page-count="pagination.perpage"
            :max="9"
            v-model="pagination.page"
          />
        </div>
      </div>
    </div>

    <USlideover v-model="isCreateSlideOpen">
      <UCard
        :ui="{
          body: { base: 'flex-1' },
          ring: '',
          divide: 'divide-y divide-gray-100 dark:divide-gray-800',
        }"
        class="flex flex-col flex-1"
      >
        <template #header>
          <UButton
            class="flex absolute end-5 top-5 z-10"
            color="gray"
            icon="tabler:x"
            padded
            size="sm"
            square
            variant="ghost"
            @click="isCreateSlideOpen = false"
          />
          创建 PPT 模板
        </template>

        <UForm
          class="space-y-4"
          :schema="pptCreateSchema"
          :state="pptCreateState"
          @submit="onCreateSubmit"
        >
          <UFormGroup
            label="模板标题"
            name="title"
          >
            <UInput v-model="pptCreateState.title" />
          </UFormGroup>
          <UFormGroup
            label="模板描述"
            name="description"
          >
            <UTextarea v-model="pptCreateState.description" />
          </UFormGroup>
          <UFormGroup
            label="模板分类"
            name="type"
          >
            <USelectMenu
              v-model="pptCreateState.type"
              value-attribute="value"
              option-attribute="label"
              searchable
              searchable-placeholder="搜索现有分类..."
              :options="selectMenuOptions"
            />
          </UFormGroup>
          <UFormGroup
            label="预览图"
            name="preview_url"
          >
            <UniFileDnD
              @change="onFileSelect($event, 'preview')"
              accept="image/png,image/jpeg"
            />
          </UFormGroup>
          <UFormGroup
            label="PPT 文件"
            name="file_url"
          >
            <UniFileDnD
              @change="onFileSelect($event, 'ppt')"
              accept="application/vnd.openxmlformats-officedocument.presentationml.presentation"
            />
          </UFormGroup>

          <div class="flex justify-end">
            <UButton
              label="创建"
              color="primary"
              type="submit"
            />
          </div>
        </UForm>
      </UCard>
    </USlideover>
    <USlideover v-model="isCatSlideOpen">
      <UCard
        :ui="{
          body: { base: 'flex-1' },
          ring: '',
          divide: 'divide-y divide-gray-100 dark:divide-gray-800',
        }"
        class="flex flex-col flex-1"
      >
        <template #header>
          <UButton
            class="flex absolute end-5 top-5 z-10"
            color="gray"
            icon="tabler:x"
            padded
            size="sm"
            square
            variant="ghost"
            @click="isCatSlideOpen = false"
          />
          PPT 模板分类管理
        </template>

        <div class="space-y-4">
          <UFormGroup label="创建分类">
            <UButtonGroup
              orientation="horizontal"
              class="w-full"
              size="lg"
            >
              <UInput
                class="flex-1"
                placeholder="分类名称"
                v-model="createCatInput"
              />
              <UButton
                icon="tabler:plus"
                color="gray"
                label="创建"
                :disabled="!createCatInput"
                @click="onCreateCat"
              />
            </UButtonGroup>
          </UFormGroup>
          <div class="border dark:border-neutral-700 rounded-md">
            <UTable
              :columns="[
                { key: 'id', label: 'ID' },
                { key: 'type', label: '分类' },
                { key: 'create_time', label: '创建时间' },
                { key: 'actions' },
              ]"
              :rows="pptCategories?.data.items"
            >
              <template #create_time-data="{ row }">
                {{
                  dayjs(row.create_time * 1000).format('YYYY-MM-DD HH:mm:ss')
                }}
              </template>
              <template #actions-data="{ row }">
                <UButton
                  color="red"
                  icon="tabler:trash"
                  size="xs"
                  variant="soft"
                  @click="onDeleteCat(row)"
                />
              </template>
            </UTable>
          </div>
        </div>
      </UCard>
    </USlideover>
  </div>
</template>

<style scoped></style>
