<script lang="ts" setup>
import type { FileApi, FolderApi, ShareApi } from '#/api/core';

import { computed, onMounted, ref, watch } from 'vue';

import { Page } from '@vben/common-ui';

import {
  Button,
  Dropdown,
  Input,
  Menu,
  message,
  Modal,
  Popconfirm,
  Progress,
  Select,
  Space,
  Spin,
  Table,
  Tag,
  Tree,
  Upload,
} from 'ant-design-vue';

import {
  abortMultipartUploadApi,
  completeMultipartUploadApi,
  createBucketApi,
  createFolderApi,
  createShareApi,
  deleteBucketApi,
  deleteFileApi,
  deleteFolderApi,
  deleteShareApi,
  downloadFileApi,
  getFileContentApi,
  getFilePreviewApi,
  getFolderApi,
  getFolderTreeApi,
  initMultipartUploadApi,
  listBucketsApi,
  listFilesApi,
  moveFileApi,
  renameFolderApi,
  uploadFileApi,
  uploadPartApi,
  uploadToFolderApi,
} from '#/api/core';

// ============ 常量 ============

const MULTIPART_THRESHOLD = 10 * 1024 * 1024; // 10MB 以上分片
const PART_SIZE = 5 * 1024 * 1024; // 每片 5MB
const MAX_SIMPLE_UPLOAD = 100 * 1024 * 1024; // 100MB 上限

// ============ 状态 ============

const buckets = ref<string[]>([]);
const selectedBucket = ref<string>('');

// 文件夹树
const folderTree = ref<FolderApi.Folder[]>([]);
const selectedFolderId = ref<string | null>(null);
const expandedFolderIds = ref<string[]>([]);
const folderLoading = ref(false);

// 当前文件夹内容
const currentSubFolders = ref<FolderApi.Folder[]>([]);
const currentFiles = ref<FileApi.FileMeta[]>([]);
const contentLoading = ref(false);

// S3 原始文件（根目录无文件夹时回退）
const s3Files = ref<FileApi.FileInfo[]>([]);
const continuationToken = ref<string | null>(null);
const s3Loading = ref(false);

// 上传
const uploading = ref(false);
const uploadProgress = ref(0);
const uploadFileName = ref('');
const dragActive = ref(false);

// 预览
const previewVisible = ref(false);
const previewLoading = ref(false);
const previewUrl = ref('');
const previewContent = ref('');
const previewType = ref<'image' | 'pdf' | 'text' | null>(null);
const previewFileName = ref('');

// 弹窗
const createFolderVisible = ref(false);
const newFolderName = ref('');
const renameFolderVisible = ref(false);
const renameFolderId = ref('');
const renameFolderName = ref('');
const moveFileVisible = ref(false);
const moveFileId = ref('');
const moveTargetFolderId = ref('');
const shareVisible = ref(false);
const shareForm = ref({
  resourceId: '',
  resourceType: 'file' as string,
  password: '',
  maxDownloads: undefined as number | undefined,
});
const shareResult = ref<ShareApi.ShareLink | null>(null);
const createBucketVisible = ref(false);
const newBucketName = ref('');

// ============ 工具函数 ============

function formatFileSize(bytes: number): string {
  if (bytes === 0) return '0 B';
  const units = ['B', 'KB', 'MB', 'GB', 'TB'];
  const i = Math.floor(Math.log(bytes) / Math.log(1024));
  return `${(bytes / 1024 ** i).toFixed(1)} ${units[i]}`;
}

function formatTime(iso: string): string {
  if (!iso) return '-';
  return new Date(iso).toLocaleString();
}

function getFileExt(name: string): string {
  const parts = name.split('.');
  return parts.length > 1 ? parts.at(-1)!.toLowerCase() : '';
}

function getFileIcon(name: string): string {
  const ext = getFileExt(name);
  const map: Record<string, string> = {
    jpg: '🖼️', jpeg: '🖼️', png: '🖼️', gif: '🖼️', webp: '🖼️', svg: '🖼️',
    pdf: '📄', doc: '📝', docx: '📝', xls: '📊', xlsx: '📊',
    ppt: '📊', pptx: '📊', zip: '📦', rar: '📦', '7z': '📦',
    mp4: '🎬', mp3: '🎵', wav: '🎵', md: '📋', txt: '📋',
    json: '📋', yaml: '📋', yml: '📋', xml: '📋', csv: '📋',
  };
  return map[ext] || '📎';
}

function isPreviewable(name: string): boolean {
  const ext = getFileExt(name);
  return ['jpg', 'jpeg', 'png', 'gif', 'webp', 'svg', 'pdf', 'md', 'txt', 'json', 'yaml', 'yml', 'xml', 'csv'].includes(ext);
}

function getPreviewType(name: string): 'image' | 'pdf' | 'text' {
  const ext = getFileExt(name);
  if (['jpg', 'jpeg', 'png', 'gif', 'webp', 'svg'].includes(ext)) return 'image';
  if (ext === 'pdf') return 'pdf';
  return 'text';
}

// ============ 文件夹树构建 ============

function buildTreeNodes(folders: FolderApi.Folder[]): any[] {
  const map = new Map<string, any>();
  const roots: any[] = [];

  for (const f of folders) {
    map.set(f.ID, { key: f.ID, title: f.Name, children: [], isLeaf: false });
  }

  for (const f of folders) {
    const node = map.get(f.ID)!;
    if (f.ParentID && map.has(f.ParentID)) {
      map.get(f.ParentID)!.children.push(node);
    } else {
      roots.push(node);
    }
  }

  return roots;
}

// ============ 数据加载 ============

async function loadBuckets() {
  try {
    const resp = await listBucketsApi();
    buckets.value = resp?.buckets ?? [];
    if (buckets.value.length > 0 && !selectedBucket.value) {
      selectedBucket.value = buckets.value[0]!;
    }
  } catch {
    // handled by interceptor
  }
}

async function loadFolderTree() {
  folderLoading.value = true;
  try {
    const resp = await getFolderTreeApi();
    folderTree.value = resp ?? [];
    if (folderTree.value.length > 0) {
      expandedFolderIds.value = folderTree.value.map((f) => f.ID);
    }
  } catch {
    // handled by interceptor
  } finally {
    folderLoading.value = false;
  }
}

async function loadFolderContent(folderId: string) {
  contentLoading.value = true;
  try {
    const resp = await getFolderApi(folderId);
    currentSubFolders.value = resp?.SubFolders ?? [];
    currentFiles.value = resp?.Files ?? [];
  } catch {
    // handled by interceptor
  } finally {
    contentLoading.value = false;
  }
}

async function loadS3Files(append = false) {
  if (!selectedBucket.value) return;
  s3Loading.value = true;
  try {
    const params: Record<string, any> = { bucket_name: selectedBucket.value, max_keys: 50 };
    if (append && continuationToken.value) params.token = continuationToken.value;
    const result = await listFilesApi(params as any);
    if (append) {
      s3Files.value = [...s3Files.value, ...(result?.Files ?? [])];
    } else {
      s3Files.value = result?.Files ?? [];
    }
    continuationToken.value = result?.NextContinuationToken ?? null;
  } catch {
    // handled by interceptor
  } finally {
    s3Loading.value = false;
  }
}

async function loadCurrentContent() {
  if (selectedFolderId.value) {
    currentSubFolders.value = [];
    currentFiles.value = [];
    await loadFolderContent(selectedFolderId.value);
  } else {
    s3Files.value = [];
    continuationToken.value = null;
    await loadS3Files();
  }
}

// ============ 分片上传 ============

async function multipartUpload(file: File) {
  const objectKey = `${Date.now()}_${file.name}`;
  uploadFileName.value = file.name;
  uploadProgress.value = 0;

  try {
    const initResp = await initMultipartUploadApi(selectedBucket.value, objectKey);
    const uploadId = initResp!.upload_id;

    const totalParts = Math.ceil(file.size / PART_SIZE);
    const parts: { part_number: number; etag: string }[] = [];

    for (let i = 0; i < totalParts; i++) {
      const start = i * PART_SIZE;
      const end = Math.min(start + PART_SIZE, file.size);
      const blob = file.slice(start, end);

      const partResp = await uploadPartApi(selectedBucket.value, objectKey, uploadId, i + 1, blob);
      parts.push({ part_number: i + 1, etag: partResp!.etag });
      uploadProgress.value = Math.round(((i + 1) / totalParts) * 100);
    }

    await completeMultipartUploadApi(selectedBucket.value, objectKey, uploadId, parts);
    message.success(`${file.name} 上传成功`);
  } catch {
    try {
      await abortMultipartUploadApi(selectedBucket.value, `${Date.now()}_${file.name}`, '');
    } catch {
      // ignore abort error
    }
    throw new Error('上传失败');
  }
}

// ============ 上传处理 ============

async function handleUpload(file: File) {
  if (!selectedBucket.value) {
    message.warning('请先选择存储桶');
    return;
  }

  if (file.size > MAX_SIMPLE_UPLOAD) {
    message.error('文件大小不能超过 100MB');
    return;
  }

  uploading.value = true;
  uploadProgress.value = 0;
  uploadFileName.value = file.name;

  try {
    if (file.size >= MULTIPART_THRESHOLD) {
      // 分片上传
      await multipartUpload(file);
    } else if (selectedFolderId.value) {
      // 上传到当前文件夹
      await uploadToFolderApi(selectedFolderId.value, selectedBucket.value, file);
      message.success(`${file.name} 上传成功`);
    } else {
      // 简单上传到 bucket 根目录
      await uploadFileApi(selectedBucket.value, file);
      message.success(`${file.name} 上传成功`);
    }

    loadCurrentContent();
    if (!selectedFolderId.value) {
      loadFolderTree();
    }
  } catch {
    message.error(`${file.name} 上传失败`);
  } finally {
    uploading.value = false;
    uploadProgress.value = 0;
    uploadFileName.value = '';
  }
}

function handleCustomUpload(options: any) {
  handleUpload(options.file as File);
}

function handleDrop(e: DragEvent) {
  dragActive.value = false;
  const files = e.dataTransfer?.files;
  if (files && files.length > 0) {
    handleUpload(files[0]!);
  }
}

// ============ 文件夹操作 ============

async function handleCreateFolder() {
  if (!newFolderName.value.trim()) return;
  try {
    await createFolderApi({
      name: newFolderName.value.trim(),
      parent_id: selectedFolderId.value || undefined,
    });
    message.success('文件夹创建成功');
    createFolderVisible.value = false;
    newFolderName.value = '';
    await loadFolderTree();
    if (selectedFolderId.value) {
      await loadFolderContent(selectedFolderId.value);
    }
  } catch {
    message.error('创建文件夹失败');
  }
}

async function handleRenameFolder() {
  if (!renameFolderName.value.trim()) return;
  try {
    await renameFolderApi(renameFolderId.value, { name: renameFolderName.value.trim() });
    message.success('重命名成功');
    renameFolderVisible.value = false;
    await loadFolderTree();
    if (selectedFolderId.value) {
      await loadFolderContent(selectedFolderId.value);
    }
  } catch {
    message.error('重命名失败');
  }
}

async function handleDeleteFolder(folderId: string) {
  try {
    await deleteFolderApi(folderId);
    message.success('文件夹已删除');
    if (selectedFolderId.value === folderId) {
      selectedFolderId.value = null;
    }
    await loadFolderTree();
    await loadCurrentContent();
  } catch {
    message.error('删除文件夹失败');
  }
}

function handleFolderSelect(selectedKeys: any[]) {
  if (selectedKeys.length > 0) {
    selectedFolderId.value = String(selectedKeys[0]);
  } else {
    selectedFolderId.value = null;
  }
}

function openRenameFolder(folderId: string, currentName: string) {
  renameFolderId.value = folderId;
  renameFolderName.value = currentName;
  renameFolderVisible.value = true;
}

// ============ 文件操作 ============

async function handleDeleteFile(fileId: string, fileName: string) {
  try {
    // 数据库文件通过 S3 key 删除
    const file = currentFiles.value.find((f) => f.ID === fileId);
    if (file) {
      await deleteFileApi(file.S3Bucket, file.S3Key);
    }
    message.success(`${fileName} 已删除`);
    loadCurrentContent();
  } catch {
    message.error('删除文件失败');
  }
}

async function handleDeleteS3File(key: string) {
  try {
    await deleteFileApi(selectedBucket.value, key);
    message.success('文件已删除');
    loadS3Files();
  } catch {
    message.error('删除文件失败');
  }
}

async function handleDownload(file: FileApi.FileMeta) {
  try {
    const blob = await downloadFileApi(file.S3Bucket, file.S3Key);
    const url = URL.createObjectURL(new Blob([blob as any]));
    const a = document.createElement('a');
    a.href = url;
    a.download = file.Name;
    a.click();
    URL.revokeObjectURL(url);
  } catch {
    message.error('下载失败');
  }
}

async function handleDownloadS3(key: string) {
  try {
    const blob = await downloadFileApi(selectedBucket.value, key);
    const url = URL.createObjectURL(new Blob([blob as any]));
    const a = document.createElement('a');
    a.href = url;
    a.download = key.split('/').pop() || key;
    a.click();
    URL.revokeObjectURL(url);
  } catch {
    message.error('下载失败');
  }
}

async function handlePreview(file: FileApi.FileMeta) {
  previewFileName.value = file.Name;
  previewType.value = getPreviewType(file.Name);
  previewVisible.value = true;
  previewLoading.value = true;
  previewUrl.value = '';
  previewContent.value = '';

  try {
    if (previewType.value === 'text') {
      const resp = await getFileContentApi(file.S3Bucket, file.S3Key);
      previewContent.value = resp?.content ?? '';
    } else {
      const resp = await getFilePreviewApi(file.S3Bucket, file.S3Key);
      previewUrl.value = resp?.url ?? '';
    }
  } catch {
    message.error('预览加载失败');
  } finally {
    previewLoading.value = false;
  }
}

async function handlePreviewS3(key: string) {
  previewFileName.value = key.split('/').pop() || key;
  previewType.value = getPreviewType(key);
  previewVisible.value = true;
  previewLoading.value = true;
  previewUrl.value = '';
  previewContent.value = '';

  try {
    if (previewType.value === 'text') {
      const resp = await getFileContentApi(selectedBucket.value, key);
      previewContent.value = resp?.content ?? '';
    } else {
      const resp = await getFilePreviewApi(selectedBucket.value, key);
      previewUrl.value = resp?.url ?? '';
    }
  } catch {
    message.error('预览加载失败');
  } finally {
    previewLoading.value = false;
  }
}

// ============ 移动文件 ============

function openMoveFile(fileId: string) {
  moveFileId.value = fileId;
  moveTargetFolderId.value = '';
  moveFileVisible.value = true;
}

async function handleMoveFile() {
  if (!moveTargetFolderId.value) {
    message.warning('请选择目标文件夹');
    return;
  }
  try {
    await moveFileApi(moveFileId.value, moveTargetFolderId.value);
    message.success('文件已移动');
    moveFileVisible.value = false;
    loadCurrentContent();
  } catch {
    message.error('移动文件失败');
  }
}

// ============ 分享操作 ============

function openShare(resourceId: string, resourceType: string) {
  shareForm.value = { resourceId, resourceType, password: '', maxDownloads: undefined };
  shareResult.value = null;
  shareVisible.value = true;
}

async function handleCreateShare() {
  try {
    const params: ShareApi.CreateShareParams = {
      resource_type: shareForm.value.resourceType,
      resource_id: shareForm.value.resourceId,
    };
    if (shareForm.value.password) params.password = shareForm.value.password;
    if (shareForm.value.maxDownloads) params.max_downloads = shareForm.value.maxDownloads;
    const resp = await createShareApi(params);
    shareResult.value = resp ?? null;
    message.success('分享链接已创建');
  } catch {
    message.error('创建分享失败');
  }
}

async function handleDeleteShare(shareId: string) {
  try {
    await deleteShareApi(shareId);
    message.success('分享已取消');
  } catch {
    message.error('取消分享失败');
  }
}

function copyShareLink(token: string) {
  const link = `${window.location.origin}/share/${token}`;
  navigator.clipboard.writeText(link).then(() => {
    message.success('链接已复制到剪贴板');
  }).catch(() => {
    message.error('复制失败');
  });
}

// ============ Bucket 操作 ============

async function handleCreateBucket() {
  if (!newBucketName.value.trim()) return;
  try {
    await createBucketApi(newBucketName.value.trim());
    message.success('存储桶创建成功');
    createBucketVisible.value = false;
    newBucketName.value = '';
    await loadBuckets();
    if (buckets.value.length > 0) {
      selectedBucket.value = buckets.value.at(-1)!;
    }
  } catch {
    message.error('创建存储桶失败');
  }
}

async function handleDeleteBucket() {
  if (!selectedBucket.value) return;
  try {
    await deleteBucketApi(selectedBucket.value);
    message.success('存储桶已删除');
    await loadBuckets();
    selectedBucket.value = buckets.value[0] ?? '';
  } catch {
    message.error('删除存储桶失败');
  }
}

// ============ 表格列 ============

// 子文件夹列
const subFolderColumns = [
  { title: '文件夹名称', dataIndex: 'Name', key: 'Name', ellipsis: true },
  { title: '创建时间', dataIndex: 'CreatedAt', key: 'CreatedAt', width: 180 },
  { title: '操作', key: 'actions', width: 250 },
];

// 数据库文件列
const fileColumns = [
  { title: '文件名', dataIndex: 'Name', key: 'Name', ellipsis: true },
  { title: '大小', dataIndex: 'Size', key: 'Size', width: 120 },
  { title: '类型', dataIndex: 'ContentType', key: 'ContentType', width: 160 },
  { title: '更新时间', dataIndex: 'UpdatedAt', key: 'UpdatedAt', width: 180 },
  { title: '操作', key: 'actions', width: 300 },
];

// S3 文件列
const s3FileColumns = [
  { title: '文件名', dataIndex: 'Key', key: 'Key', ellipsis: true },
  { title: '大小', dataIndex: 'Size', key: 'Size', width: 120 },
  { title: '修改时间', dataIndex: 'LastModified', key: 'LastModified', width: 200 },
  { title: '操作', key: 'actions', width: 200 },
];

// 移动目标文件夹选项（扁平化）
const moveFolderOptions = computed(() => {
  const options: { label: string; value: string }[] = [];
  function walk(folders: FolderApi.Folder[], prefix: string) {
    for (const f of folders) {
      if (f.ID !== moveFileId.value) {
        options.push({ label: `${prefix}${f.Name}`, value: f.ID });
        const children = folderTree.value.filter((c) => c.ParentID === f.ID);
        walk(children, `${prefix}${f.Name} / `);
      }
    }
  }
  const roots = folderTree.value.filter((f) => !f.ParentID);
  walk(roots, '');
  return options;
});

const shareBaseUrl = computed(() => `${typeof window !== 'undefined' ? window.location.origin : ''}/share/`)

const hasMore = computed(() => !selectedFolderId.value && continuationToken.value !== null);

// ============ 生命周期 ============

watch(selectedBucket, () => {
  selectedFolderId.value = null;
  currentSubFolders.value = [];
  currentFiles.value = [];
  s3Files.value = [];
  continuationToken.value = null;
  if (selectedBucket.value) {
    loadFolderTree();
    loadS3Files();
  }
});

watch(selectedFolderId, () => {
  currentSubFolders.value = [];
  currentFiles.value = [];
  if (selectedFolderId.value) {
    loadFolderContent(selectedFolderId.value);
  } else if (selectedBucket.value) {
    loadS3Files();
  }
});

onMounted(() => {
  loadBuckets();
});
</script>

<template>
  <Page auto-content-height>
    <div class="flex h-full">
      <!-- 左侧：文件夹树 -->
      <div class="w-[260px] shrink-0 border-r border-gray-200 p-3 dark:border-gray-700">
        <div class="mb-3 flex items-center justify-between">
          <span class="text-sm font-semibold">文件夹</span>
          <Button size="small" @click="createFolderVisible = true">新建</Button>
        </div>
        <Spin :spinning="folderLoading">
          <Tree
            v-if="folderTree.length > 0"
            :tree-data="buildTreeNodes(folderTree)"
            :selected-keys="selectedFolderId ? [selectedFolderId] : []"
            :expanded-keys="expandedFolderIds"
            block-node
            @select="handleFolderSelect"
            @expand="(keys: any) => expandedFolderIds = keys"
          >
            <template #title="{ title, key }">
              <Dropdown :trigger="['contextmenu']">
                <span>📁 {{ title }}</span>
                <template #overlay>
                  <Menu>
                    <Menu.Item @click="openRenameFolder(String(key), String(title))">
                      重命名
                    </Menu.Item>
                    <Menu.Item>
                      <Popconfirm title="确定删除此文件夹？" @confirm="handleDeleteFolder(String(key))">
                        <span class="text-red-500">删除</span>
                      </Popconfirm>
                    </Menu.Item>
                  </Menu>
                </template>
              </Dropdown>
            </template>
          </Tree>
          <div v-else class="py-4 text-center text-gray-400 text-sm">
            暂无文件夹
          </div>
        </Spin>
      </div>

      <!-- 右侧：工具栏 + 文件列表 -->
      <div class="flex-1 overflow-auto p-4">
        <!-- 工具栏 -->
        <div class="mb-4 flex flex-wrap items-center gap-3">
          <Select
            v-model:value="selectedBucket"
            placeholder="选择存储桶"
            class="min-w-[180px]"
            :options="buckets.map((b) => ({ label: b, value: b }))"
          />

          <Button @click="createBucketVisible = true">新建存储桶</Button>

          <Popconfirm
            v-if="selectedBucket"
            :title="`确定删除存储桶 ${selectedBucket}？`"
            @confirm="handleDeleteBucket"
          >
            <Button danger>删除存储桶</Button>
          </Popconfirm>

          <div class="flex-1" />

          <!-- 上传区域 -->
          <Upload
            :custom-request="handleCustomUpload"
            :show-upload-list="false"
            :disabled="!selectedBucket || uploading"
          >
            <Button :loading="uploading" type="primary">
              {{ uploading ? `上传中 ${uploadProgress}%` : '上传文件' }}
            </Button>
          </Upload>

          <Button @click="loadCurrentContent">刷新</Button>
        </div>

        <!-- 上传进度条 -->
        <div v-if="uploading" class="mb-4">
          <div class="mb-1 text-sm text-gray-500">
            正在上传: {{ uploadFileName }}
          </div>
          <Progress :percent="uploadProgress" :stroke-color="{ '0%': '#108ee9', '100%': '#87d068' }" />
        </div>

        <!-- 拖拽上传区域 -->
        <div
          v-if="!dragActive"
          class="mb-4 rounded-lg border-2 border-dashed border-gray-300 p-3 text-center text-gray-400 text-sm transition-colors hover:border-blue-400 hover:text-blue-400 dark:border-gray-600"
          @dragenter.prevent="dragActive = true"
          @dragover.prevent
          @drop.prevent="handleDrop"
        >
          拖拽文件到此处上传
        </div>
        <div
          v-else
          class="mb-4 rounded-lg border-2 border-dashed border-blue-500 bg-blue-50 p-3 text-center text-blue-500 text-sm dark:bg-blue-900/20"
          @dragleave.prevent="dragActive = false"
          @dragover.prevent
          @drop.prevent="handleDrop"
        >
          松开鼠标上传文件
        </div>

        <!-- 当前路径面包屑 -->
        <div v-if="selectedFolderId" class="mb-3 flex items-center gap-1 text-sm">
          <a class="cursor-pointer text-blue-500" @click="selectedFolderId = null">根目录</a>
          <template v-if="selectedFolderId">
            <span class="text-gray-400">/</span>
            <span>{{ folderTree.find(f => f.ID === selectedFolderId)?.Name ?? '文件夹' }}</span>
          </template>
        </div>

        <!-- 有文件夹选中时：显示子文件夹 + 文件 -->
        <template v-if="selectedFolderId">
          <Spin :spinning="contentLoading">
            <!-- 子文件夹 -->
            <Table
              v-if="currentSubFolders.length > 0"
              :columns="subFolderColumns"
              :data-source="currentSubFolders"
              :pagination="false"
              row-key="ID"
              size="small"
              class="mb-2"
            >
              <template #bodyCell="{ column, record }">
                <template v-if="column.key === 'Name'">
                  <span class="cursor-pointer text-blue-500" @click="selectedFolderId = record.ID">
                    📁 {{ record.Name }}
                  </span>
                </template>
                <template v-else-if="column.key === 'CreatedAt'">
                  {{ formatTime(record.CreatedAt) }}
                </template>
                <template v-else-if="column.key === 'actions'">
                  <Space>
                    <Button size="small" @click="selectedFolderId = record.ID">打开</Button>
                    <Button size="small" @click="openRenameFolder(record.ID, record.Name)">重命名</Button>
                    <Popconfirm title="确定删除？" @confirm="handleDeleteFolder(record.ID)">
                      <Button danger size="small">删除</Button>
                    </Popconfirm>
                  </Space>
                </template>
              </template>
            </Table>

            <!-- 文件列表 -->
            <Table
              :columns="fileColumns"
              :data-source="currentFiles"
              :pagination="false"
              row-key="ID"
              size="small"
            >
              <template #bodyCell="{ column, record }">
                <template v-if="column.key === 'Name'">
                  <span class="mr-1">{{ getFileIcon(record.Name) }}</span>
                  <span>{{ record.Name }}</span>
                </template>
                <template v-else-if="column.key === 'Size'">
                  {{ formatFileSize(record.Size) }}
                </template>
                <template v-else-if="column.key === 'ContentType'">
                  <Tag>{{ record.ContentType || '未知' }}</Tag>
                </template>
                <template v-else-if="column.key === 'UpdatedAt'">
                  {{ formatTime(record.UpdatedAt) }}
                </template>
                <template v-else-if="column.key === 'actions'">
                  <Space>
                    <Button size="small" @click="handleDownload(record as FileApi.FileMeta)">下载</Button>
                    <Button v-if="isPreviewable(record.Name)" size="small" @click="handlePreview(record as FileApi.FileMeta)">预览</Button>
                    <Button size="small" @click="openMoveFile(record.ID)">移动</Button>
                    <Button size="small" @click="openShare(record.ID, 'file')">分享</Button>
                    <Popconfirm :title="`确定删除 ${record.Name}？`" @confirm="handleDeleteFile(record.ID, record.Name)">
                      <Button danger size="small">删除</Button>
                    </Popconfirm>
                  </Space>
                </template>
              </template>
              <template #emptyText>
                <div class="py-6 text-gray-400">此文件夹暂无文件</div>
              </template>
            </Table>
          </Spin>
        </template>

        <!-- 无文件夹选中时：显示 S3 原始文件列表 -->
        <template v-else>
          <Spin :spinning="s3Loading">
            <Table
              :columns="s3FileColumns"
              :data-source="s3Files"
              :pagination="false"
              row-key="Key"
              size="small"
            >
              <template #bodyCell="{ column, record }">
                <template v-if="column.key === 'Key'">
                  <span class="mr-1">{{ getFileIcon(record.Key) }}</span>
                  <span>{{ record.Key }}</span>
                </template>
                <template v-else-if="column.key === 'Size'">
                  {{ formatFileSize(record.Size) }}
                </template>
                <template v-else-if="column.key === 'LastModified'">
                  {{ formatTime(record.LastModified) }}
                </template>
                <template v-else-if="column.key === 'actions'">
                  <Space>
                    <Button size="small" @click="handleDownloadS3(record.Key)">下载</Button>
                    <Button v-if="isPreviewable(record.Key)" size="small" @click="handlePreviewS3(record.Key)">预览</Button>
                    <Popconfirm :title="`确定删除 ${record.Key}？`" @confirm="handleDeleteS3File(record.Key)">
                      <Button danger size="small">删除</Button>
                    </Popconfirm>
                  </Space>
                </template>
              </template>
              <template #emptyText>
                <div class="py-6 text-gray-400">暂无文件</div>
              </template>
            </Table>

            <div v-if="hasMore" class="mt-4 text-center">
              <Button :loading="s3Loading" @click="loadS3Files(true)">加载更多</Button>
            </div>
          </Spin>
        </template>
      </div>
    </div>

    <!-- 预览弹窗 -->
    <Modal v-model:open="previewVisible" :title="previewFileName" width="800px" :footer="null">
      <Spin :spinning="previewLoading">
        <div v-if="previewType === 'image'" class="text-center">
          <img :src="previewUrl" class="max-w-full" :alt="previewFileName" />
        </div>
        <div v-else-if="previewType === 'pdf'">
          <iframe :src="previewUrl" class="h-[600px] w-full" />
        </div>
        <div v-else-if="previewType === 'text'">
          <pre class="max-h-[600px] overflow-auto rounded bg-gray-50 p-4 text-sm dark:bg-gray-800">{{ previewContent }}</pre>
        </div>
      </Spin>
    </Modal>

    <!-- 新建文件夹弹窗 -->
    <Modal v-model:open="createFolderVisible" title="新建文件夹" @ok="handleCreateFolder">
      <div class="py-4">
        <Input
          v-model:value="newFolderName"
          placeholder="请输入文件夹名称"
          @press-enter="handleCreateFolder"
        />
      </div>
    </Modal>

    <!-- 重命名文件夹弹窗 -->
    <Modal v-model:open="renameFolderVisible" title="重命名文件夹" @ok="handleRenameFolder">
      <div class="py-4">
        <Input
          v-model:value="renameFolderName"
          placeholder="请输入新名称"
          @press-enter="handleRenameFolder"
        />
      </div>
    </Modal>

    <!-- 移动文件弹窗 -->
    <Modal v-model:open="moveFileVisible" title="移动文件" @ok="handleMoveFile">
      <div class="py-4">
        <Select
          v-model:value="moveTargetFolderId"
          placeholder="选择目标文件夹"
          class="w-full"
          :options="moveFolderOptions"
        />
      </div>
    </Modal>

    <!-- 分享弹窗 -->
    <Modal v-model:open="shareVisible" :title="shareResult ? '分享链接' : '创建分享'" :footer="shareResult ? null : undefined" @ok="handleCreateShare">
      <div v-if="!shareResult" class="py-4 space-y-3">
        <div>
          <label class="mb-1 block text-sm">密码保护（可选）</label>
          <Input v-model:value="shareForm.password" placeholder="留空则无需密码" />
        </div>
        <div>
          <label class="mb-1 block text-sm">最大下载次数（可选）</label>
          <Input
            v-model:value="shareForm.maxDownloads"
            type="number"
            placeholder="留空则不限制"
          />
        </div>
      </div>
      <div v-else class="py-4 space-y-3">
        <div class="rounded-lg bg-green-50 p-3 dark:bg-green-900/20">
          <div class="mb-1 text-sm text-gray-500">分享链接</div>
          <div class="flex items-center gap-2">
            <code class="flex-1 rounded bg-white px-2 py-1 text-sm dark:bg-gray-800">
              {{ shareBaseUrl + shareResult.Token }}
            </code>
            <Button size="small" type="primary" @click="copyShareLink(shareResult.Token)">复制</Button>
          </div>
        </div>
        <div v-if="shareResult.Password" class="text-sm">
          <span class="text-gray-500">密码：</span>
          <code>{{ shareResult.Password }}</code>
        </div>
        <div class="text-sm text-gray-500">
          创建时间: {{ formatTime(shareResult.CreatedAt) }}
          <span v-if="shareResult.ExpiresAt"> | 过期时间: {{ formatTime(shareResult.ExpiresAt) }}</span>
        </div>
        <div class="mt-2">
          <Popconfirm title="确定取消此分享？" @confirm="handleDeleteShare(shareResult.ID)">
            <Button danger size="small">取消分享</Button>
          </Popconfirm>
        </div>
      </div>
    </Modal>

    <!-- 新建存储桶弹窗 -->
    <Modal v-model:open="createBucketVisible" title="新建存储桶" @ok="handleCreateBucket">
      <div class="py-4">
        <Input
          v-model:value="newBucketName"
          placeholder="请输入存储桶名称"
          @press-enter="handleCreateBucket"
        />
      </div>
    </Modal>
  </Page>
</template>
