<template>
  <div class="page-wrapper" ref="rootEl">

    <!-- 操作栏 -->
    <div class="btn-container">
      <el-upload
        :action="`${apiBase}/photoWall/upload`"
        accept="image/jpeg,image/png"
        name="image"
        :headers="{ token: store.state.loginInfo.token }"
        :before-upload="beforeUpload"
        :on-success="uploadSuccess"
        :on-error="uploadError"
        auto-upload
        :show-file-list="false"
        style="margin-right: 10px;">
        <el-tooltip :content="t('api.photoWall.uploadTooltip', { exts: allowUploadExt.join('\u3001') })">
          <el-button type="primary" icon="Upload" :loading="isUploading" v-permission="'photoWall:save'" plain>{{ t('api.photoWall.uploadBtn') }}</el-button>
        </el-tooltip>
      </el-upload>
      <el-button
        v-if="selected.size > 0"
        type="danger"
        icon="Delete"
        plain
        v-permission="'photoWall:delete'"
        @click="deleteSelected">
        {{ t('api.photoWall.deleteSelected', { count: selected.size }) }}
      </el-button>
      <div class="search-btn">
        <el-button link type="primary" :disabled="!photos.length" @click="selectAll" v-if="!isAllSelected">{{ t('api.photoWall.selectAll') }}</el-button>
        <el-button link type="primary" @click="clearSelect" v-else>{{ t('api.photoWall.deselectAll') }}</el-button>
        <el-button link type="primary" :disabled="!photos.length" @click="invertSelect">{{ t('api.photoWall.invertSelect') }}</el-button>
      </div>
    </div>

    <!-- 瀑布流（可滚动区域） -->
    <div class="masonry-scroll">
      <div class="masonry-scene">
        <div
          v-for="(col, ci) in columns"
          :key="ci"
          class="masonry-col">
          <div
            v-for="item in col"
            :key="item._id"
            class="card-wrap"
            :class="{ 'is-selected': selected.has(item._id), 'is-entered': entered.has(item._id) }"
            @click="toggleSelect(item)">

            <div class="card-inner">
              <!-- 图片 -->
              <img
                class="card-img"
                :src="cdnBase ? `${cdnBase}/${item.thumbnail || item.name}` : ''"
                :alt="item.name"
                loading="lazy"
                draggable="false" />

              <!-- 选中角标 -->
              <div class="check-badge">
                <el-icon><Check /></el-icon>
              </div>

              <!-- Hover 浮层 -->
              <div class="card-overlay">
                <div class="overlay-info">
                  <p class="overlay-name" :title="item.name">{{ item.name }}</p>
                  <p class="overlay-size">{{ item.width }} x {{ item.height }}</p>
                </div>
                <el-button-group class="overlay-actions">
                  <el-button size="small" icon="View" plain @click.stop="preview(item)">{{ t('api.photoWall.previewBtn') }}</el-button>
                  <el-button
                    size="small"
                    icon="Delete"
                    type="danger"
                    plain
                    v-permission="'photoWall:delete'"
                    @click.stop="deleteSingle(item)">
                    {{ t('common.delete') }}
                  </el-button>
                </el-button-group>
              </div>
            </div>
          </div>
        </div>
      </div>
    </div>

    <!-- 分页 -->
    <div class="page-container">
      <el-pagination
        background
        :page-sizes="store.state.pageSizeOpts"
        :layout="store.state.pageLayout"
        :current-page="search.pageNum"
        :page-size="search.limit"
        :total="total"
        @size-change="pageSizeChange"
        @current-change="pageChange" />
    </div>

    <!-- 图片预览 -->
    <el-image-viewer
      v-if="previewVisible"
      :url-list="previewUrls"
      :initial-index="previewIndex"
      @close="previewVisible = false" />

  </div>
</template>

<script setup lang="ts">
import { ref, computed, onMounted, onBeforeUnmount, nextTick } from 'vue'
import { useStore } from 'vuex'
import { useI18n } from 'vue-i18n'
import { ElMessage, ElMessageBox } from 'element-plus'
import type { MsgResult } from '@/model/common.dto'
import { Page } from '@/model/common.dto'
import { useBaseList } from '@/model/baselist'
import type PhotoWallModel from '@/model/api/photowall'
import http from '@/utils/http'

const { t } = useI18n()

// --- 常量 ---
const COLUMN_WIDTH = 220  // 每列目标宽度(px)
const COL_GAP = 14        // 列间距(px)

// --- 基础状态 ---
const store = useStore()
const apiBase = import.meta.env.VITE_APP_API_BASE
const rootEl = ref<HTMLElement | null>(null)
const photos = ref<PhotoWallModel[]>([])
const isUploading = ref(false)
const allowUploadExt = ['jpg', 'jpeg', 'png']

class GalleryPage extends Page {
  constructor() { super(); this.limit = 50 }
}
const { loading, total, search, setLoadData, pageChange, pageSizeChange } = useBaseList(new GalleryPage())

const cdnBase = ref('')
const selected = ref<Set<string>>(new Set())
const entered = ref<Set<string>>(new Set())
const previewVisible = ref(false)
const previewUrls = ref<string[]>([])
const previewIndex = ref(0)

// --- 瀑布流分列 ---
const colCount = ref(4)

function recalcCols() {
  if (!rootEl.value) return
  const w = rootEl.value.clientWidth - 32
  colCount.value = Math.max(1, Math.floor((w + COL_GAP) / (COLUMN_WIDTH + COL_GAP)))
}

const columns = computed<PhotoWallModel[][]>(() => {
  const cols: PhotoWallModel[][] = Array.from({ length: colCount.value }, () => [])
  photos.value.forEach((item, i) => {
    cols[i % colCount.value].push(item)
  })
  return cols
})

// --- 数据加载 ---
async function loadData() {
  loading.value = true
  entered.value = new Set()
  try {
    if (!cdnBase.value) {
      cdnBase.value = await http.get('/common/config/picture_cdn')
    }
    const data = await http.get<any, any>('/photoWall/list', {
      params: { pageNum: search.pageNum, limit: search.limit }
    })
    total.value = data.total
    photos.value = data.list as PhotoWallModel[]
    previewUrls.value = photos.value.map(item => `${cdnBase.value}/${item.name}`)
    await nextTick()
    entered.value = new Set(photos.value.map(p => p._id))
  } finally {
    loading.value = false
  }
}
setLoadData(loadData)

// --- 选中 ---
function toggleSelect(item: PhotoWallModel) {
  const s = new Set(selected.value)
  s.has(item._id) ? s.delete(item._id) : s.add(item._id)
  selected.value = s
}

function selectAll() {
  selected.value = new Set(photos.value.map(p => p._id))
}

function invertSelect() {
  const s = new Set<string>()
  photos.value.forEach(p => {
    if (!selected.value.has(p._id)) s.add(p._id)
  })
  selected.value = s
}

function clearSelect() {
  selected.value = new Set()
}

const isAllSelected = computed(() => photos.value.length && selected.value.size === photos.value.length)

// --- 预览 ---
function preview(item: PhotoWallModel) {
  previewIndex.value = photos.value.findIndex(p => p._id === item._id) || 0
  previewVisible.value = true
}

// --- 删除 ---
async function deleteSingle(item: PhotoWallModel) {
  await ElMessageBox.confirm(t('api.photoWall.deleteSingleConfirm', { name: item.name }), t('common.deleteConfirm'), { type: 'warning' })
  await http.delete('/photoWall/delete', { params: { ids: [item._id] } })
  ElMessage.success(t('common.deleteSuccess'))
  loadData()
}

async function deleteSelected() {
  const ids = [...selected.value]
  await ElMessageBox.confirm(t('api.photoWall.deleteMultiConfirm', { count: ids.length }), t('common.deleteConfirm'), { type: 'warning' })
  await http.delete('/photoWall/delete', { params: { ids } })
  selected.value = new Set()
  ElMessage.success(t('common.deleteSuccess'))
  loadData()
}

// --- 上传 ---
function beforeUpload(file: File): boolean {
  if (file.size > 10 << 20) {
    ElMessage.warning(t('common.fileSizeExceeded'))
    return false
  }
  isUploading.value = true
  return true
}
function uploadSuccess(response: MsgResult) {
  isUploading.value = false
  if (response.code === 0) {
    ElMessage.success(t('common.uploadSuccess'))
    loadData()
  } else {
    ElMessage.warning(response.message || t('common.uploadFailed'))
  }
}
function uploadError(error: Error) {
  isUploading.value = false
  ElMessage.error(error.message)
}

// --- 响应式列数 ---
let resizeObserver: ResizeObserver | null = null

onMounted(async () => {
  recalcCols()
  resizeObserver = new ResizeObserver(() => recalcCols())
  if (rootEl.value) resizeObserver.observe(rootEl.value)
  await loadData()
})

onBeforeUnmount(() => {
  resizeObserver?.disconnect()
})
</script>

<style scoped lang="less">
// --- 可滚动瀑布流区域 ---
.masonry-scroll {
  flex: 1;
  overflow-y: auto;
  overflow-x: hidden;
  padding: 4px;
}

.masonry-scene {
  display: flex;
  gap: 14px;
  align-items: flex-start;
}

.masonry-col {
  flex: 1;
  display: flex;
  flex-direction: column;
  gap: 14px;
  min-width: 0;
}

// --- 卡片外壳（选中描边） ---
.card-wrap {
  opacity: 0;
  transform: translateY(20px);
  border-radius: 10px;
  outline: 2px solid transparent;
  outline-offset: 2px;
  transition:
    opacity 0.35s ease,
    transform 0.35s ease,
    outline-color 0.2s ease;
  cursor: pointer;

  &.is-entered {
    opacity: 1;
    transform: translateY(0);
  }

  &.is-selected {
    outline-color: var(--el-color-primary);

    .check-badge {
      opacity: 1;
      transform: scale(1);
    }
  }

  &:hover .card-overlay {
    opacity: 1;
    transform: translateY(0);
  }
  &:hover .overlay-info {
    opacity: 1;
    transform: translateY(0);
  }
  &:hover .overlay-actions {
    opacity: 1;
    transform: translateY(0);
  }
}

// --- 卡片内容 ---
.card-inner {
  position: relative;
  width: 100%;
  min-height: 80px;
  border-radius: 10px;
  overflow: hidden;
  background: var(--el-fill-color-light);
}

.card-img {
  display: block;
  width: 100%;
  height: auto;
  border-radius: 10px;
  transition: transform 0.4s ease;

  .card-wrap:hover & {
    transform: scale(1.04);
  }
}

// --- 选中角标 ---
.check-badge {
  position: absolute;
  top: 8px;
  right: 8px;
  width: 22px;
  height: 22px;
  border-radius: 50%;
  background: var(--el-color-primary);
  color: #fff;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 13px;
  opacity: 0;
  transform: scale(0.5);
  transition: opacity 0.2s ease, transform 0.2s cubic-bezier(0.34, 1.56, 0.64, 1);
}

// --- Hover 浮层 ---
.card-overlay {
  position: absolute;
  inset: 0;
  border-radius: 10px;
  background: linear-gradient(
    to top,
    rgba(0, 0, 0, 0.82) 0%,
    rgba(0, 0, 0, 0.4) 55%,
    rgba(0, 0, 0, 0.08) 100%
  );
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  padding: 12px;
  box-sizing: border-box;
  opacity: 0;
  transform: translateY(6px);
  transition:
    opacity 0.3s ease,
    transform 0.3s ease;
}

.overlay-info {
  opacity: 0;
  transform: translateY(8px);
  transition:
    opacity 0.3s ease 0.04s,
    transform 0.3s ease 0.04s;

  .overlay-name {
    margin: 0 0 3px;
    font-size: 12px;
    color: rgba(255, 255, 255, 0.85);
    word-break: break-all;
    display: -webkit-box;
    line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
    line-height: 1.4;
  }

  .overlay-size {
    margin: 0 0 10px;
    font-size: 12px;
    color: rgba(255, 255, 255, 0.5);
    letter-spacing: 0.5px;
  }
}

.overlay-actions {
  display: flex;
  justify-content: center;
  opacity: 0;
  transform: translateY(8px);
  transition:
    opacity 0.3s ease 0.08s,
    transform 0.3s ease 0.08s;
}
</style>
