<template>
  <div
    class="relative overflow-hidden bg-[radial-gradient(circle_at_12%_18%,rgba(135,196,235,0.05),transparent_24%),radial-gradient(circle_at_86%_12%,rgba(200,182,224,0.04),transparent_24%),radial-gradient(circle_at_50%_100%,rgba(249,199,216,0.03),transparent_28%),linear-gradient(180deg,#fcfaf6_0%,#fbf8f7_44%,#fefcfb_100%)]">
    <div
      class="pointer-events-none absolute left-[-5rem] top-6 h-80 w-80 rounded-full bg-[rgba(135,196,235,0.10)] opacity-48 blur-[88px]">
    </div>
    <div
      class="pointer-events-none absolute right-[-5rem] top-32 h-[22rem] w-[22rem] rounded-full bg-[rgba(249,199,216,0.08)] opacity-48 blur-[88px]">
    </div>
    <div
      class="pointer-events-none absolute inset-0 opacity-14 [background-image:linear-gradient(rgba(255,255,255,0.18)_1px,transparent_1px),linear-gradient(90deg,rgba(255,255,255,0.18)_1px,transparent_1px)] [background-size:36px_36px] [mask-image:linear-gradient(180deg,rgba(0,0,0,0.8),transparent_85%)]">
    </div>

    <n-scrollbar ref="virtualListInst" class="relative z-[1] py-6" :style="boxStyle" @scroll="handleScroll">
      <section
        class="relative mx-auto w-[82%] rounded-[28px] border border-white/62 bg-[linear-gradient(145deg,rgba(255,251,246,0.68),rgba(237,246,244,0.56))] p-6 shadow-[0_1px_3px_rgba(128,118,126,0.05),0_16px_38px_rgba(128,118,126,0.09),0_44px_84px_rgba(215,26,68,0.07),inset_0_1px_0_rgba(255,255,255,0.7)] backdrop-blur-[20px] after:pointer-events-none after:absolute after:inset-0 after:rounded-[inherit] after:bg-[linear-gradient(120deg,rgba(255,255,255,0.24),transparent_45%)] after:content-['']">
        <div class="max-w-[48rem]">
          <h1 class="m-0 text-[clamp(1.8rem,2.5vw,2.8rem)] leading-[1.2] text-[#2c3a4a]">
            把喜欢的画面收进一片更柔和的光里
          </h1>
          <p class="mt-[0.9rem] max-w-[42rem] leading-[1.75] text-[#66778b]">
            如果图片效果模糊的话，可以点击图片查看原图。
          </p>
        </div>

        <div
          class="mt-6 rounded-full border border-white bg-[linear-gradient(135deg,rgba(255,249,241,0.76),rgba(236,245,243,0.72)),radial-gradient(circle_at_top_right,rgba(255,255,255,0.28),transparent_34%)] shadow-[0_0_0_2px_rgba(255,255,255,0.75),inset_0_1px_0_rgba(255,255,255,0.55)] transition-[box-shadow,border-color] duration-300">
          <n-input class="gallery-search" round size="large" clearable v-model:value="kw" @keyup.enter="onSearch"
            placeholder="输入分享者 | 图片名，按回车开始搜索">
            <template #suffix>
              <n-icon class="cursor-pointer text-slate-500 transition-colors duration-200 hover:text-primary" size="large" @click="onSearch">
                <icon-search />
              </n-icon>
            </template>
          </n-input>
        </div>
      </section>

      <section
        class="mx-auto mt-6 w-[82%] min-h-[80vh] rounded-[30px] border border-white/62 bg-white/42 p-6 shadow-[0_1px_3px_rgba(128,118,126,0.05),0_14px_30px_rgba(128,118,126,0.09),0_36px_72px_rgba(215,26,68,0.07),inset_0_1px_0_rgba(255,255,255,0.7)] backdrop-blur-[18px]">
        <div class="mb-5 flex flex-col gap-4 md:flex-row md:items-start md:justify-between">
          <div>
            <div class="text-[1.6rem] font-semibold text-[#5c3d46]">图片列表</div>
            <div class="mt-1 flex items-center gap-2 text-[13px] text-slate-500">
              <span v-if="searchKeyword" class="inline-flex items-center rounded-full bg-[rgba(215,26,68,0.1)] px-2.5 py-0.5 font-semibold text-[rgb(215,26,68)]">
                关键词：{{ searchKeyword }}
              </span>
              <span>{{ galleryStats.status }}</span>
            </div>
          </div>
          <div class="inline-flex items-center gap-2 self-start rounded-full bg-white/68 px-5 py-2 text-[#72515a] shadow-[0_2px_8px_rgba(128,118,126,0.08),inset_0_1px_0_rgba(255,255,255,0.7)]">
            <span class="inline-block h-2 w-2 rounded-full" :class="loading ? 'animate-pulse bg-[#D71A44]' : 'bg-[#DB5F51]'"></span>
            {{ galleryStats.loaded }} 张
          </div>
        </div>

        <Waterfall ref="waterfall" :list="fileList" :gutter="gutter" :columns="column" row-key="filepath" class="w-full" img-selector="url"
          animation-effect="fadeIn" :animation-duration="1000" :animation-delay="300" backgroundColor="transparent">
          <template #item="{ item }">
            <div
              class="gallery-card group relative flex h-full items-center justify-center overflow-hidden rounded-[12px] border border-white/82 bg-[linear-gradient(180deg,rgba(255,252,248,0.92),rgba(239,244,241,0.78))] backdrop-blur-[14px] transition-[transform,box-shadow,border-color] duration-[320ms] [transition-timing-function:cubic-bezier(0.22,1,0.36,1)] hover:-translate-y-1">
              <LazyImg class="gallery-img overflow-hidden rounded-[12px]" :Pwidth="item.width" :Pheight="item.height"
                :url="item.thumbnail" :preUrl="item.filepath" />
              <div
                class="pointer-events-none absolute left-0 right-0 top-0 z-10 pt-1.5 px-3 text-center truncate rounded-[12px] bg-gradient-to-b from-[rgba(39,50,65,0.55)] to-transparent  text-sm text-white opacity-0 backdrop-blur-[6px] transition-opacity duration-300 group-hover:opacity-100">
                {{ item.filename }}
              </div>
              <div
                class="absolute bottom-0 left-0 right-0 z-10 flex translate-y-[102%] items-center justify-between gap-3 rounded-[12px] bg-[rgba(39,50,65,0.55)] px-3 py-0.5 text-white backdrop-blur-[12px] transition-transform duration-[320ms] [transition-timing-function:cubic-bezier(0.22,1,0.36,1)] group-hover:translate-y-0">
                <div class="min-w-0 overflow-hidden text-ellipsis whitespace-nowrap text-sm text-[#eef4f8]">
                  由 <span class="text-lg text-[#ffd8cb]">{{ item.nickname }}</span> 分享
                </div>
                <div
                  class="inline-flex flex-shrink-0 cursor-pointer items-center rounded-full bg-white/18 text-sm px-2 py-0.5 text-[#ffe3d3] transition-[background-color,transform] duration-200 hover:scale-105 hover:bg-white/28 hover:text-white active:scale-95"
                  @click.stop="downloadFile(item.filepath)">
                  <icon-download class="mr-1 h-4 w-4" />
                  下载
                </div>
              </div>
            </div>
          </template>
        </Waterfall>

        <div v-if="fileList.length === 0 && !loading" class="flex flex-col items-center justify-center py-16 text-slate-400">
          <icon-search class="mb-3 h-10 w-10 opacity-50" />
          <p class="text-[15px]">{{ searchKeyword ? '未找到相关图片，换个关键词试试' : '暂无图片' }}</p>
        </div>

        <div v-if="loading" class="flex items-center justify-center gap-2 py-6 text-sm text-slate-400">
          <icon-loading class="zhuan h-5 w-5 text-primary" />
          <span>{{ fileList.length ? '加载中...' : '首次加载中...' }}</span>
        </div>
        <div v-else-if="isLoadAll && fileList.length" class="py-5 text-center text-[13px] text-slate-400">
          — 已加载全部 {{ fileList.length }} 张图片 —
        </div>
      </section>
    </n-scrollbar>
  </div>
</template>

<script setup lang="ts">
import { throttle } from 'es-toolkit'
import { LazyImg, Waterfall } from '../lib'

definePage({
  name: 'gallery',
  meta: {
    title: '画廊',
  }
})

interface GalleryItem {
  filepath: string
  filename: string
  nickname: string
  width: number
  height: number
}

interface ScrollContainer extends EventTarget {
  scrollTop: number
  scrollHeight: number
  offsetHeight: number
}

const GALLERY_WIDTH_RATIO = 0.82
const PAGE_SIZE = 20
const SCROLL_THRESHOLD = 100

const waterfall = ref<any>(null)
const nav: any = $store.nav.useNavStore()
const boxStyle = ref<Record<string, string>>({})
const fileList = ref<GalleryItem[]>([])
const pn = ref(1)
const ps = ref(PAGE_SIZE)
const loading = ref(false)
const kw = ref('')
const cwidth = ref(240)
const column = ref(5)
const gutter = ref(18)
const isLoadAll = ref(false)
let requestSeq = 0

const searchKeyword = computed(() => kw.value.trim())

const galleryStats = computed(() => {
  let status = '浏览全部'

  if (loading.value) {
    status = '加载中'
  } else if (isLoadAll.value && fileList.value.length > 0) {
    status = '已全部加载'
  } else if (searchKeyword.value) {
    status = '搜索结果'
  }

  return {
    loaded: fileList.value.length,
    columns: column.value,
    status,
    keyword: searchKeyword.value ? `关键词：${searchKeyword.value}` : '关键词：全部图片',
  }
})

function renderWaterfall() {
  waterfall.value?.renderer()
}

function calculateColumns() {
  const totalWidth = window.innerWidth * GALLERY_WIDTH_RATIO
  const col = Math.floor((totalWidth + gutter.value) / (cwidth.value + gutter.value))
  column.value = col > 0 ? col : 1
  renderWaterfall()
}

function updateBoxStyle() {
  boxStyle.value = {
    maxHeight: `calc(100vh - 5px - ${nav.navH}px)`,
  }
}

function appendFileList(list: GalleryItem[]) {
  if (pn.value === 1) {
    fileList.value = list
    return
  }

  list.forEach((item) => {
    fileList.value.push(item)
  })
}

function resetGalleryState() {
  pn.value = 1
  kw.value = ''
  fileList.value = []
  isLoadAll.value = false
}

async function getFileList() {
  if (loading.value) return
  loading.value = true
  const seq = ++requestSeq

  try {
    const res = await $http.file.getFileList({
      keyword: kw.value,
      page_num: pn.value,
      page_size: ps.value,
    })
    const list = res.data as GalleryItem[]

    // 过期请求直接丢弃，避免搜索时旧结果覆盖新结果
    if (seq !== requestSeq) return

    if (list.length < ps.value) {
      isLoadAll.value = true
    }

    appendFileList(list)
  } catch (error) {
    console.error('获取图片列表失败:', error)
  } finally {
    if (seq === requestSeq) {
      loading.value = false
      renderWaterfall()
    }
  }
}

const handleScroll = throttle((e: Event) => {
  if (loading.value || isLoadAll.value) return

  const target = e.target as ScrollContainer | null
  if (!target) return

  const scrollTop = target.scrollTop
  const scrollHeight = target.scrollHeight
  const clientHeight = target.offsetHeight

  if (scrollTop + clientHeight >= scrollHeight - SCROLL_THRESHOLD) {
    pn.value += 1
    getFileList()
  }
}, 300)

function onSearch() {
  pn.value = 1
  kw.value = kw.value.trim()
  isLoadAll.value = false
  // 立即清空旧列表，避免搜索时看到上一批结果
  fileList.value = []
  // 若正在加载中，先解除守卫，让新搜索请求可以发起
  loading.value = false
  requestSeq += 1
  getFileList()
}

function downloadFile(url: string) {
  const link = document.createElement('a')
  link.href = url
  const fileName = url.split('/').pop() || 'downloaded-file'
  link.download = fileName
  link.style.display = 'none'
  document.body.appendChild(link)
  link.click()
  document.body.removeChild(link)
}

onMounted(() => {
  calculateColumns()
  updateBoxStyle()
  getFileList()
  window.addEventListener('resize', handleResize)
})

function handleResize() {
  calculateColumns()
  updateBoxStyle()
}

onUnmounted(() => {
  resetGalleryState()
  window.removeEventListener('resize', handleResize)
})

// 防抖函数

</script>

<style scoped lang="less">
:deep(.gallery-search .n-input) {
  background: rgba(255, 255, 255, 0.74) !important;
  border: 1px solid rgba(255, 255, 255, 0.7) !important;
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.6),
    0 2px 6px rgba(97, 121, 146, 0.05),
    0 10px 24px rgba(97, 121, 146, 0.09) !important;
  backdrop-filter: blur(18px);
  transition:
    border-color 0.25s ease,
    box-shadow 0.25s ease;
}

:deep(.gallery-search .n-input__input-el) {
  color: #314155 !important;
}

:deep(.gallery-search .n-input__placeholder) {
  color: #93a2b3 !important;
}

:deep(.gallery-search .n-input.n-input--focus) {
  border-color: rgba(122, 160, 148, 0.7) !important;
  box-shadow:
    0 0 0 4px rgba(122, 160, 148, 0.12),
    inset 0 1px 0 rgba(255, 255, 255, 0.6),
    0 2px 6px rgba(97, 121, 146, 0.06),
    0 16px 36px rgba(97, 121, 146, 0.14) !important;
}

/* 图片卡片 hover 增强 */
.gallery-card {
  box-shadow:
    0 1px 3px rgba(97, 121, 146, 0.05),
    0 12px 26px rgba(97, 121, 146, 0.09),
    0 32px 60px rgba(178, 128, 88, 0.06),
    inset 0 1px 0 rgba(255, 255, 255, 0.72) !important;
}

.gallery-card:hover {
  border-color: rgba(255, 255, 255, 0.88) !important;
  box-shadow:
    0 2px 6px rgba(97, 121, 146, 0.06),
    0 18px 38px rgba(97, 121, 146, 0.14),
    0 48px 90px rgba(178, 128, 88, 0.1),
    inset 0 1px 0 rgba(255, 255, 255, 0.8) !important;
}

.gallery-img {
  transition: transform 0.45s cubic-bezier(0.22, 1, 0.36, 1);
}

.gallery-card:hover .gallery-img {
  transform: scale(1.045);
}

/* 加载图标旋转 */
.zhuan {
  animation: gallery-spin 1.5s linear infinite;
}

@keyframes gallery-spin {
  from {
    transform: rotate(0deg);
  }

  to {
    transform: rotate(360deg);
  }
}

:deep(.n-image img) {
  border-radius: 1rem !important;
}
:deep(.n-input) {
  --n-border: none !important;
  --n-border-hover: none !important;
  --n-border-focus: none !important;
  --n-box-shadow-focus: none !important;
  background: transparent !important;
}

:deep(.n-input__input-el),
:deep(.n-base-selection-label) {
  color: #314155 !important;
}

</style>
