<script setup lang="ts">
definePageMeta({ title: '媒体库' })

type MediaAssetRow = {
  id: number
  storageKey: string
  publicPath: string
  mime: string
  sizeBytes: number
  createdAt: string
  refCount: number
}

const toast = useToast()
const { fetchData, getApiErrorMessage } = useClientApi()

const page = ref(1)
const pageSize = ref(20)
const items = ref<MediaAssetRow[]>([])
const total = ref(0)
const loading = ref(true)
const uploading = ref(false)
const fileInput = ref<HTMLInputElement | null>(null)

const pageSizeItems = [
  { label: '每页 10', value: 10 },
  { label: '每页 20', value: 20 },
  { label: '每页 50', value: 50 },
]

function formatBytes(n: number): string {
  if (n < 1024) {
    return `${n} B`
  }
  if (n < 1024 * 1024) {
    return `${(n / 1024).toFixed(1)} KB`
  }
  return `${(n / (1024 * 1024)).toFixed(1)} MB`
}

function formatDt(iso: string | null): string {
  if (!iso) {
    return '—'
  }
  const d = new Date(iso)
  return Number.isNaN(d.getTime()) ? iso : d.toLocaleString('zh-CN')
}

async function load() {
  loading.value = true
  try {
    const q = new URLSearchParams({
      page: String(page.value),
      pageSize: String(pageSize.value),
    })
    const body = await fetchData<{ items: MediaAssetRow[]; total: number }>(
      `/api/me/media/assets?${q.toString()}`,
      { notify: false },
    )
    items.value = body.items
    total.value = body.total
  } catch (e: unknown) {
    toast.add({ title: getApiErrorMessage(e), color: 'error' })
  } finally {
    loading.value = false
  }
}

watch(pageSize, () => {
  page.value = 1
})

watch(
  [page, pageSize],
  () => {
    void load()
  },
  { immediate: true },
)

function openFilePicker() {
  fileInput.value?.click()
}

async function onFileChange(ev: Event) {
  const input = ev.target as HTMLInputElement
  const files = input.files ? Array.from(input.files) : []
  input.value = ''
  if (!files.length) {
    return
  }

  uploading.value = true
  try {
    const form = new FormData()
    for (const f of files) {
      form.append('file', f)
    }
    await fetchData<{ files: { url: string }[] }>('/api/file/upload', {
      method: 'POST',
      body: form,
      notify: false,
    })
    toast.add({
      title: files.length === 1 ? '上传成功' : `已上传 ${files.length} 个文件`,
      color: 'success',
    })
    await load()
  } catch (e: unknown) {
    toast.add({ title: getApiErrorMessage(e), color: 'error' })
  } finally {
    uploading.value = false
  }
}

async function copyUrl(item: MediaAssetRow) {
  if (!import.meta.client) {
    return
  }
  const absoluteUrl = `${window.location.origin}${item.publicPath}`
  try {
    await navigator.clipboard.writeText(absoluteUrl)
    toast.add({ title: '已复制 URL', color: 'success' })
  } catch (e: unknown) {
    toast.add({ title: getApiErrorMessage(e), color: 'error' })
  }
}

async function copyMarkdown(item: MediaAssetRow) {
  if (!import.meta.client) {
    return
  }
  const absoluteUrl = `${window.location.origin}${item.publicPath}`
  const md = `![](${absoluteUrl})`
  try {
    await navigator.clipboard.writeText(md)
    toast.add({ title: '已复制 Markdown', color: 'success' })
  } catch (e: unknown) {
    toast.add({ title: getApiErrorMessage(e), color: 'error' })
  }
}
</script>

<template>
  <div class="space-y-6 w-full max-w-[min(100%,88rem)] px-0 sm:px-0">
    <div>
      <h2 class="text-lg font-medium">
        资源库
      </h2>
      <p class="text-sm text-muted mt-1">
        浏览已上传图片、复制外链或 Markdown，用于文章与资料。
      </p>
    </div>

    <div class="flex flex-wrap items-end gap-x-5 gap-y-3">
      <input
        ref="fileInput"
        type="file"
        class="sr-only"
        accept="image/png,image/jpeg,image/jpg,image/webp"
        multiple
        @change="onFileChange"
      >
      <UButton
        color="primary"
        :loading="uploading"
        :disabled="uploading"
        @click="openFilePicker"
      >
        选择图片上传
      </UButton>
      <UFormField label="每页" class="w-40 shrink-0">
        <USelect v-model="pageSize" :items="pageSizeItems" value-key="value" class="w-full" />
      </UFormField>
    </div>

    <div v-if="loading" class="text-muted">
      加载中…
    </div>
    <UEmpty
      v-else-if="!items.length"
      title="暂无图片"
      description="上传 PNG / JPEG / WebP 后，将在此列出并可直接复制链接。"
    />
    <div v-else class="grid gap-4 sm:grid-cols-2 lg:grid-cols-3">
      <UCard v-for="item in items" :key="item.id">
        <div class="space-y-3">
          <img
            :src="item.publicPath"
            :alt="item.storageKey"
            class="w-full aspect-video object-cover rounded-md border border-default"
            loading="lazy"
          >
          <div
            class="truncate font-mono text-xs text-default"
            :title="item.storageKey"
          >
            {{ item.storageKey }}
          </div>
          <div class="flex flex-wrap gap-x-3 gap-y-1 text-xs text-muted tabular-nums">
            <span>{{ formatBytes(item.sizeBytes) }}</span>
            <span>{{ formatDt(item.createdAt) }}</span>
          </div>
          <p class="text-xs text-default">
            引用数: {{ item.refCount }}
          </p>
          <div class="flex flex-wrap gap-2">
            <UButton size="xs" variant="soft" @click="copyUrl(item)">
              复制 URL
            </UButton>
            <UButton size="xs" variant="soft" @click="copyMarkdown(item)">
              复制 Markdown
            </UButton>
          </div>
        </div>
      </UCard>
    </div>

    <div v-if="!loading && total > pageSize" class="flex justify-end">
      <UPagination v-model:page="page" :total="total" :items-per-page="pageSize" size="sm" />
    </div>
  </div>
</template>
