<template>
  <div class="file-list-page" :class="{ 'preview-open': previewOn && previewRow }">
    <!-- 头部 -->
    <div class="page-header">
      <div class="header-left">
        <h2>{{ t('File') }}</h2>
      </div>
      <div class="header-right">
        <FileListToolbar
          :entity="entity"
          :search-query="searchQuery"
          :view-mode="viewMode"
          :preview-on="previewOn"
          :selected-keys="selectedKeys"
          :loading="loading"
          :can-edit="canEditList"
          :card-size="cardSize"
          :file-type-filter="fileTypeFilter"
          @update:search-query="searchQuery = $event"
          @update:view-mode="handleViewModeChange"
          @update:preview-on="previewOn = $event"
          @update:card-size="cardSize = $event"
          @update:file-type-filter="fileTypeFilter = $event"
          @reload="reload"
          @create="openUploadDialog"
          @create-folder="showNewFolderDialog = true"
          @delete-selected="handleDeleteSelected"
        />
      </div>
    </div>

    <!-- 内容区：左侧列表 + 右侧预览面板 -->
    <div class="content-wrapper">
      <!-- 左侧：视图内容 -->
      <div class="left-panel">
        <!-- 面包屑导航 -->
        <div v-if="folderBreadcrumb.length > 0" class="folder-breadcrumb">
          <button class="breadcrumb-item" @click="navigateToBreadcrumb(-1)">{{ t('Home') }}</button>
          <template v-for="(crumb, idx) in folderBreadcrumb" :key="crumb.name">
            <Icon icon="tabler:chevron-right" :size="14" class="breadcrumb-sep" />
            <button
              class="breadcrumb-item"
              :class="{ active: idx === folderBreadcrumb.length - 1 }"
              @click="navigateToBreadcrumb(idx)"
            >{{ crumb.label }}</button>
          </template>
        </div>
        <!-- 加载状态 -->
        <div v-if="loading && rows.length === 0" class="loading-state">
          <Icon icon="tabler:loader-2" :size="28" class="spin-icon" />
          <span>{{ t('Loading...') }}</span>
        </div>
        <!-- 空状态 -->
        <div v-else-if="rows.length === 0" class="empty-state">
          <Icon icon="tabler:file-off" :size="48" />
          <p>{{ t('No Results found') }}</p>
        </div>
        <!-- 数据视图 -->
        <template v-else>
          <!-- 顶部轻微加载指示 -->
          <div v-if="loading" class="loading-bar">
            <Icon icon="tabler:loader-2" :size="16" class="spin-icon" />
          </div>

          <!-- List 视图 -->
          <ListView
            v-if="viewMode === 'list'"
            :rows="rows"
            :columns="listColumns"
            :selected-keys="selectedKeys"
            :preview-name="previewRow?.name || ''"
            @row-click="handleRowClick"
            @toggle-selection="toggleSelection"
            @toggle-select-all="toggleSelectAll"
          >
            <template #actions="{ row }">
              <div class="row-actions">
                <button class="action-icon-btn" @click.stop="goToDetail(row)" title="View">
                  <Icon icon="tabler:eye" :size="15" />
                </button>
                <button class="action-icon-btn" @click.stop="handleDownload(row)" title="Download">
                  <Icon icon="tabler:download" :size="15" />
                </button>
                <button class="action-icon-btn action-danger" @click.stop="deleteSingle(row)" title="Delete">
                  <Icon icon="tabler:trash" :size="15" />
                </button>
              </div>
            </template>
          </ListView>

          <!-- Card 视图 -->
          <div v-if="viewMode === 'card'" class="card-wrapper">
          <CardView
            :rows="rows"
            :selected-keys="selectedKeys"
            :preview-name="previewRow?.name || ''"
            :card-size="cardSize"
            @row-click="handleRowClick"
            @toggle-selection="toggleSelection"
          >
            <template #actions="{ row }">
              <div class="row-actions">
                <button class="action-icon-btn" @click.stop="goToDetail(row)" title="View">
                  <Icon icon="tabler:eye" :size="15" />
                </button>
                <button class="action-icon-btn" @click.stop="handleDownload(row)" title="Download">
                  <Icon icon="tabler:download" :size="15" />
                </button>
                <button class="action-icon-btn action-danger" @click.stop="deleteSingle(row)" title="Delete">
                  <Icon icon="tabler:trash" :size="15" />
                </button>
              </div>
            </template>
          </CardView>
          </div>

          <!-- Masonry 视图 -->
          <div v-if="viewMode === 'masonry'" class="masonry-wrapper">
          <MasonryView
            :rows="rows"
            :selected-keys="selectedKeys"
            :preview-name="previewRow?.name || ''"
            @row-click="handleRowClick"
            @toggle-selection="toggleSelection"
          >
            <template #actions="{ row }">
              <div class="row-actions">
                <button class="action-icon-btn" @click.stop="goToDetail(row)" title="View">
                  <Icon icon="tabler:eye" :size="15" />
                </button>
                <button class="action-icon-btn" @click.stop="handleDownload(row)" title="Download">
                  <Icon icon="tabler:download" :size="15" />
                </button>
                <button class="action-icon-btn action-danger" @click.stop="deleteSingle(row)" title="Delete">
                  <Icon icon="tabler:trash" :size="15" />
                </button>
              </div>
            </template>
          </MasonryView>
          </div>

          <!-- 分页 -->
          <div class="list-pagination">
            <n-pagination v-model:page="page" :page-count="pageCount" size="small" />
          </div>
        </template>
      </div>

      <!-- 拖拽分割线 -->
      <div v-if="previewOn && previewRow" class="resize-handle" @mousedown="startResize"></div>

      <!-- 右侧：预览面板 -->
      <div v-if="previewOn && previewRow" class="right-panel" :style="panelWidth > 0 ? { width: panelWidth + 'px' } : { flex: '0 0 45%' }">
        <FilePreview
          :row="previewRow"
          @close="closePreview"
          @download="handleDownload"
          @delete="deleteSingle"
        />
      </div>
    </div>

    <!-- 上传对话框 -->
    <FileUploadDialog
      v-model:show="showUploadDialog"
      :pagetype="entity"
      :folder="currentFolder || 'Home'"
      @uploaded="onUploaded"
    />

    <!-- 新建文件夹对话框 -->
    <n-modal v-model:show="showNewFolderDialog" preset="dialog" :title="t('New Folder')" :show-icon="false" style="width: 400px">
      <n-input v-model:value="newFolderName" placeholder="" @keydown.enter="createFolder" />
      <template #action>
        <n-button @click="showNewFolderDialog = false">{{ t('Cancel') }}</n-button>
        <n-button type="primary" :disabled="!newFolderName.trim()" @click="createFolder">{{ t('Create') }}</n-button>
      </template>
    </n-modal>
  </div>
</template>

<script setup lang="ts">
import { onMounted, ref, computed, watch } from 'vue'
import { useRoute, useRouter } from 'vue-router'
import { NPagination, NModal, NButton, NInput, useMessage, useDialog } from 'naive-ui'
import { Icon } from '@iconify/vue'
import axios from 'axios'
import { t } from '@/shared/i18n'
import { usePageTypeSlug } from '@/shared/utils/slug'
import { usePermissionStore } from '@/shared/stores/permissions'
import FileListToolbar from './file_list_toolbar.vue'
import ListView from './list_view.vue'
import CardView from './card_view.vue'
import MasonryView from './masonry_view.vue'
import FilePreview from './file_preview.vue'
import FileUploadDialog from './FileUploadDialog.vue'

// ===== 路由与权限 =====
const route = useRoute()
const router = useRouter()
const message = useMessage()
const dialog = useDialog()
const permissionStore = usePermissionStore()
const { pagetypeSlug, entity } = usePageTypeSlug(route)
const canEditList = computed(() => permissionStore.canWrite(entity.value))

// ===== 视图状态 =====
type ViewMode = 'list' | 'card' | 'masonry'
type CardSize = 'S' | 'M' | 'L'

const viewMode = ref<ViewMode>((localStorage.getItem('fileListViewMode') as ViewMode) || 'list')
const cardSize = ref<CardSize>((localStorage.getItem('fileListCardSize') as CardSize) || 'M')
const fileTypeFilter = ref('')
const previewOn = ref(localStorage.getItem('fileListPreviewOn') === 'true')

// ===== 列表状态 =====
const searchQuery = ref('')
const loading = ref(false)
const rows = ref<any[]>([])
const page = ref(Number(route.query.page) || 1)
const pageSize = ref(parseInt(localStorage.getItem('itemsPerPage') || '20'))
const total = ref(0)
const selectedKeys = ref<string[]>([])
const pageCount = computed(() => {
  if (total.value === 0) return 1
  return Math.max(1, Math.ceil(total.value / pageSize.value))
})

// ===== 文件夹导航 =====
const currentFolder = ref('')
const folderBreadcrumb = ref<{ name: string; label: string }[]>([])
const showNewFolderDialog = ref(false)
const newFolderName = ref('')

// ===== 预览状态 =====
const previewRow = ref<any | null>(null)

// ===== 拖拽面板 =====
const panelWidth = ref(0)

// ===== 文件上传 =====

// ===== 列表列定义 =====
const listColumns = computed(() => [
  { key: 'file_name', title: t('File Name'), width: 'minmax(180px, 2fr)' },
  { key: 'file_type', title: t('Type'), width: '80px' },
  { key: 'file_size', title: t('Size'), width: '90px' },
  { key: 'modified', title: t('Modified'), width: '150px' },
])

// ===== 持久化 =====
watch(viewMode, v => localStorage.setItem('fileListViewMode', v))
watch(cardSize, v => localStorage.setItem('fileListCardSize', v))
watch(previewOn, v => localStorage.setItem('fileListPreviewOn', String(v)))
watch(fileTypeFilter, () => { page.value = 1; loadData() })

// ===== 数据加载 =====
const FILE_FIELDS = ['name', 'file_name', 'file_type', 'file_size', 'file_url', 'thumbnail_url', 'is_folder', 'is_private', 'folder', 'owner', 'modified_by', 'modified', 'creation', 'attached_to_pagetype', 'attached_to_name', 'description', 'content_hash', 'title']

async function loadData() {
  loading.value = true
  try {
    const filterConditions: any[] = []

    // 文件类型过滤
    if (fileTypeFilter.value) {
      const typeMap: Record<string, string[]> = {
        image: ['jpg', 'jpeg', 'png', 'gif', 'webp', 'svg', 'bmp', 'ico'],
        document: ['pdf', 'doc', 'docx', 'xls', 'xlsx', 'ppt', 'pptx', 'txt', 'md', 'csv'],
        video: ['mp4', 'avi', 'mov', 'mkv', 'webm'],
        audio: ['mp3', 'wav', 'flac', 'aac', 'ogg'],
        archive: ['zip', 'rar', '7z', 'tar', 'gz'],
      }
      const exts = typeMap[fileTypeFilter.value]
      if (exts) {
        filterConditions.push(['file_type', 'in', exts])
      } else if (fileTypeFilter.value === 'folder') {
        filterConditions.push(['is_folder', '=', 1])
      }
    }

    // 搜索
    if (searchQuery.value) {
      filterConditions.push(['file_name', 'like', `%${searchQuery.value}%`])
    }

    // 文件夹导航：只显示当前文件夹下的文件
    if (currentFolder.value) {
      filterConditions.push(['folder', '=', currentFolder.value])
    } else {
      // 根目录：只显示属于 Home 的文件（folder 为 Home 或空）
      filterConditions.push(['folder', '=', 'Home'])
    }

    const params: any = {
      fields: JSON.stringify(FILE_FIELDS),
      limit_start: (page.value - 1) * pageSize.value,
      limit_page_length: pageSize.value + 1,
      order_by: 'is_folder desc, modified desc',
    }

    if (filterConditions.length > 0) {
      params.filters = JSON.stringify(filterConditions)
    }

    const res = await axios.get(`/api/data/${encodeURIComponent(entity.value)}`, { params })
    const allRows = res.data?.data || []

    if (res.data?.total) {
      rows.value = allRows
      total.value = res.data.total
    } else {
      const hasMore = allRows.length > pageSize.value
      rows.value = hasMore ? allRows.slice(0, pageSize.value) : allRows
      total.value = (page.value - 1) * pageSize.value + rows.value.length + (hasMore ? 1 : 0)
    }

    // 保存列表状态到 sessionStorage，供详情页工具栏导航使用
    saveListState()
  } catch (error) {
    console.error('Load files error:', error)
    message.error(t('Load failed'))
  } finally {
    loading.value = false
  }
}

function reload() { loadData() }

// 保存列表状态到 sessionStorage，供详情页 prev/next 导航使用
function saveListState() {
  const state = {
    rowNames: rows.value.map((r: any) => r.name),
    page: page.value,
    sortBy: 'modified',
    sortOrder: 'desc',
    filters: [],
    folderMap: Object.fromEntries(rows.value.filter((r: any) => r.is_folder).map((r: any) => [r.name, true])),
  }
  try {
    sessionStorage.setItem(`list-state:${entity.value}`, JSON.stringify(state))
  } catch {}
}

// ===== 行交互 =====
function handleRowClick(row: any) {
  // 文件夹：始终跳转到该文件夹（而非预览）
  if (row.is_folder) {
    navigateToFolder(row)
    return
  }
  if (previewOn.value) {
    openPreview(row)
  } else {
    // 跳转详情页
    router.push({
      name: 'PageTypeDetail',
      params: { entity: pagetypeSlug.value, id: row.name },
    })
  }
}

function openPreview(row: any) {
  previewRow.value = row
}

// ===== 文件夹导航 =====
function navigateToFolder(row: any) {
  // 进入子文件夹
  folderBreadcrumb.value.push({ name: row.name, label: row.file_name || row.name })
  currentFolder.value = row.name
  page.value = 1
  selectedKeys.value = []
  closePreview()
  loadData()
}

function navigateToBreadcrumb(index: number) {
  if (index === -1) {
    // 根目录
    currentFolder.value = ''
    folderBreadcrumb.value = []
  } else {
    const target = folderBreadcrumb.value[index]
    currentFolder.value = target.name
    folderBreadcrumb.value = folderBreadcrumb.value.slice(0, index + 1)
  }
  page.value = 1
  selectedKeys.value = []
  closePreview()
  loadData()
}

async function createFolder() {
  const name = newFolderName.value.trim()
  if (!name) return
  try {
    await axios.post('/api/action/jingrow.core.api.file.create_new_folder', {
      file_name: name,
      folder: currentFolder.value || 'Home',
    })
    message.success(t('Created successfully'))
    showNewFolderDialog.value = false
    newFolderName.value = ''
    await loadData()
  } catch (error: any) {
    message.error(error?.response?.data?.exception || t('Operation failed'))
  }
}

function goToDetail(row: any) {
  if (row.is_folder) {
    navigateToFolder(row)
    return
  }
  router.push({
    name: 'PageTypeDetail',
    params: { entity: pagetypeSlug.value, id: row.name },
  })
}

function closePreview() {
  previewRow.value = null
}

// ===== 选择 =====
function toggleSelection(name: string) {
  const i = selectedKeys.value.indexOf(name)
  if (i > -1) selectedKeys.value.splice(i, 1)
  else selectedKeys.value.push(name)
}

function toggleSelectAll() {
  if (selectedKeys.value.length === rows.value.length) {
    selectedKeys.value = []
  } else {
    selectedKeys.value = rows.value.map(r => r.name)
  }
}

// ===== 视图切换 =====
function handleViewModeChange(mode: ViewMode) {
  viewMode.value = mode
  // Masonry 模式自动开启预览（图片浏览场景）
  // 其他模式保持当前预览状态
}

// ===== 删除 =====
async function handleDeleteSelected() {
  if (selectedKeys.value.length === 0) return
  dialog.warning({
    title: t('Delete Selected Records'),
    content: `${t('Are you sure you want to delete')} ${selectedKeys.value.length} ${t('selected record(s)? This action cannot be undone.')}`,
    positiveText: t('Delete'),
    negativeText: t('Cancel'),
    onPositiveClick: async () => {
      loading.value = true
      try {
        const { deleteRecords } = await import('@/shared/api/common')
        const res = await deleteRecords(entity.value, selectedKeys.value)
        if (res.success) {
          message.success(t('Deleted successfully'))
          selectedKeys.value = []
          if (previewRow.value && !rows.value.some(r => r.name === previewRow.value?.name)) {
            closePreview()
          }
          await loadData()
        } else {
          message.error(res.message || t('Delete failed'))
        }
      } catch { message.error(t('Delete failed')) }
      finally { loading.value = false }
    }
  })
}

async function deleteSingle(row: any) {
  dialog.warning({
    title: t('Delete Record'),
    content: t('Are you sure you want to delete this record? This action cannot be undone.'),
    positiveText: t('Delete'),
    negativeText: t('Cancel'),
    onPositiveClick: async () => {
      try {
        const { deleteRecords } = await import('@/shared/api/common')
        const res = await deleteRecords(entity.value, [row.name])
        if (res.success) {
          message.success(t('Deleted successfully'))
          if (previewRow.value?.name === row.name) closePreview()
          await loadData()
        } else { message.error(t('Delete failed')) }
      } catch { message.error(t('Delete failed')) }
    }
  })
}

// ===== 下载 =====
function handleDownload(row: any) {
  if (!row?.file_url) return
  const link = document.createElement('a')
  link.href = row.file_url.startsWith('/') ? row.file_url : `/${row.file_url}`
  link.download = row.file_name || 'download'
  link.click()
}

// ===== 上传 =====
const showUploadDialog = ref(false)

function openUploadDialog() {
  showUploadDialog.value = true
}

function onUploaded() {
  showUploadDialog.value = false
  loadData()
}

// ===== 拖拽面板 =====
function startResize(e: MouseEvent) {
  e.preventDefault()
  const wrapperEl = (e.currentTarget as HTMLElement).closest('.content-wrapper') as HTMLElement
  if (!wrapperEl) return
  const startX = e.clientX
  const panelEl = wrapperEl.querySelector('.right-panel') as HTMLElement
  const startWidth = panelEl?.clientWidth || Math.round(wrapperEl.clientWidth * 0.45)
  const minWidth = 280
  const maxWidth = Math.round(wrapperEl.clientWidth * 0.7)

  function onMouseMove(ev: MouseEvent) {
    const delta = startX - ev.clientX
    let newWidth = startWidth + delta
    newWidth = Math.max(minWidth, Math.min(newWidth, maxWidth))
    panelWidth.value = newWidth
  }

  function onMouseUp() {
    document.removeEventListener('mousemove', onMouseMove)
    document.removeEventListener('mouseup', onMouseUp)
    document.body.style.cursor = ''
    document.body.style.userSelect = ''
  }

  document.addEventListener('mousemove', onMouseMove)
  document.addEventListener('mouseup', onMouseUp)
  document.body.style.cursor = 'col-resize'
  document.body.style.userSelect = 'none'
}

// ===== 分页 =====
watch(page, () => {
  loadData()
  const currentPage = route.query.page
  const newPage = String(page.value)
  if (currentPage !== newPage) {
    router.replace({ query: { ...route.query, page: page.value > 1 ? page.value : undefined } }).catch(() => {})
  }
})

// ===== 搜索防抖 =====
let searchTimer: any = null
watch(searchQuery, () => {
  clearTimeout(searchTimer)
  searchTimer = setTimeout(() => { page.value = 1; loadData() }, 300)
})

// ===== 路由变化 =====
watch(() => route.params.entity, async (newEntity, oldEntity) => {
  if (newEntity !== oldEntity) {
    page.value = 1
    searchQuery.value = ''
    selectedKeys.value = []
    closePreview()
    await loadData()
  }
})

// ===== 初始化 =====
onMounted(() => {
  loadData()
})
</script>

<style scoped>
.file-list-page {
  padding: 0;
  height: calc(100vh - 104px);
  display: flex;
  flex-direction: column;
  background: #f8fafc;
  overflow: hidden;
}

.page-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 16px 24px;
  background: #fff;
  border-bottom: 1px solid #e5e7eb;
  flex-shrink: 0;
}

.header-left h2 {
  font-size: 20px;
  font-weight: 600;
  color: #111827;
  margin: 0;
}

.header-right {
  display: flex;
  align-items: center;
}

/* 内容区 */
.content-wrapper {
  flex: 1;
  min-height: 0;
  display: flex;
  overflow: hidden;
}

.left-panel {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  overflow: hidden;
  background: #fff;
}

/* 面包屑导航 */
.folder-breadcrumb {
  display: flex;
  align-items: center;
  gap: 4px;
  padding: 0 24px;
  height: 45px;
  box-sizing: border-box;
  border-bottom: 1px solid #f0f0f0;
  font-size: 13px;
  flex-shrink: 0;
}

.breadcrumb-item {
  background: none;
  border: none;
  color: #6b7280;
  cursor: pointer;
  padding: 2px 6px;
  border-radius: 4px;
  font-size: 13px;
  transition: all 0.15s;
}

.breadcrumb-item:hover { background: #f3f4f6; color: #374151; }
.breadcrumb-item.active { color: #111827; font-weight: 600; cursor: default; }
.breadcrumb-item.active:hover { background: transparent; }

.breadcrumb-sep { color: #d1d5db; flex-shrink: 0; }

.file-list-page.preview-open .left-panel {
  min-width: 300px;
}

/* 拖拽分割线 */
.resize-handle {
  width: 4px;
  cursor: col-resize;
  background: transparent;
  flex-shrink: 0;
  transition: background 0.15s;
  z-index: 5;
}

.resize-handle:hover { background: #3b82f6; }

/* 右侧预览面板 */
.right-panel {
  flex-shrink: 0;
  min-width: 280px;
  max-width: 70%;
  overflow: hidden;
  border-left: 1px solid #e5e7eb;
}

/* Card/Masonry 外层容器（需要间距） */
.card-wrapper {
  padding: 16px;
  flex: 1;
  min-height: 0;
  overflow-y: auto;
}

.masonry-wrapper {
  padding: 16px;
  flex: 1;
  min-height: 0;
  overflow-y: auto;
}

/* 加载状态 */
.loading-state {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  padding: 80px 0;
  gap: 12px;
  color: #9ca3af;
}

.loading-bar {
  position: absolute;
  top: 8px;
  right: 8px;
  z-index: 10;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 28px;
  height: 28px;
  background: rgba(255,255,255,0.95);
  border-radius: 50%;
  box-shadow: 0 2px 8px rgba(0,0,0,0.1);
  color: #3b82f6;
}

.spin-icon {
  animation: spin 0.8s linear infinite;
}

@keyframes spin { to { transform: rotate(360deg); } }

.empty-state {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  padding: 80px 0;
  gap: 12px;
  color: #9ca3af;
}

.empty-state p { font-size: 15px; margin: 0; }

/* 分页 */
.list-pagination {
  display: flex;
  justify-content: center;
  padding: 12px;
  border-top: 1px solid #f0f0f0;
  flex-shrink: 0;
}

/* 行操作按钮 */
.row-actions {
  display: flex;
  align-items: center;
  gap: 2px;
}

.action-icon-btn {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 26px;
  height: 26px;
  border: none;
  border-radius: 5px;
  background: transparent;
  color: #6b7280;
  cursor: pointer;
  transition: all 0.15s;
}

.action-icon-btn:hover { background: #f3f4f6; color: #374151; }
.action-icon-btn.action-danger:hover { background: #fee2e2; color: #dc2626; }
</style>
