<template>
  <v-container fluid class="pa-6">
    <!-- Toolbar -->
    <v-card elevation="0" border rounded="lg" class="mb-4 pa-4">
      <v-row align="center" dense>
        <v-col cols="12" sm="4">
          <v-select
            v-model="selectedServer"
            :items="serverList"
            item-title="name"
            item-value="id"
            label="选择服务器"
            variant="outlined"
            density="compact"
            prepend-inner-icon="mdi-server"
            @update:model-value="onServerChange"
          />
        </v-col>
        <v-col cols="12" sm="4">
          <v-text-field
            v-model="currentPath"
            label="路径"
            variant="outlined"
            density="compact"
            prepend-inner-icon="mdi-folder"
            append-inner-icon="mdi-arrow-right"
            @click:append-inner="browse"
            @keydown.enter="browse"
          />
        </v-col>
        <v-col cols="12" sm="4" class="d-flex ga-2 justify-end">
          <v-btn size="small" variant="tonal" prepend-icon="mdi-upload" @click="showUpload = true">上传</v-btn>
          <v-btn size="small" variant="tonal" prepend-icon="mdi-folder-plus" @click="showMkdir = true">新建目录</v-btn>
          <v-btn size="small" variant="tonal" prepend-icon="mdi-refresh" @click="browse">刷新</v-btn>
        </v-col>
      </v-row>
    </v-card>

    <!-- Breadcrumb -->
    <v-breadcrumbs :items="breadcrumbs" class="pa-0 mb-2">
      <template #divider>/</template>
    </v-breadcrumbs>

    <!-- Batch action bar -->
    <v-card v-if="selectedFileCount > 0" class="mb-4" color="primary" variant="tonal" rounded="lg">
      <v-card-text class="d-flex align-center py-2">
        <span class="text-body-2 mr-4">已选择 {{ selectedFileCount }} 个文件</span>
        <v-spacer />
        <v-btn size="small" variant="text" color="error" @click="batchDelete">批量删除</v-btn>
        <v-btn size="small" variant="text" @click="selectedFiles = []">取消选择</v-btn>
      </v-card-text>
    </v-card>

    <!-- File list -->
    <v-card elevation="0" border rounded="lg">
      <v-data-table
        v-model="selectedFiles"
        :items="files"
        :headers="fileHeaders"
        :loading="loading"
        show-select
        hover
        density="comfortable"
        item-value="name"
        @click:row="onRowClick"
        @contextmenu:row="onRowContext"
      >
        <template #item.name="{ item }">
          <div class="d-flex align-center ga-2">
            <v-icon :color="item.type === 'directory' ? 'amber' : 'blue'" size="20">
              {{ item.type === 'directory' ? 'mdi-folder' : 'mdi-file-outline' }}
            </v-icon>
            <span :class="{ 'font-weight-medium': item.type === 'directory' }">{{ item.name }}</span>
          </div>
        </template>

        <template #item.size="{ item }">
          <span class="text-medium-emphasis">{{ item.type === 'directory' ? '—' : formatSize(item.size) }}</span>
        </template>

        <template #item.modified="{ item }">
          <span class="text-medium-emphasis">{{ item.modified || '—' }}</span>
        </template>

        <template #item.actions="{ item }">
          <div class="d-flex ga-1">
            <v-btn v-if="item.type !== 'directory'" variant="text" size="x-small" density="compact" color="primary" @click.stop="editFile(item)">编辑</v-btn>
            <v-btn v-if="item.type !== 'directory'" variant="text" size="x-small" density="compact" @click.stop="previewFile(item)">查看</v-btn>
            <v-btn v-if="item.type !== 'directory'" variant="text" size="x-small" density="compact" @click.stop="downloadFile(item)">下载</v-btn>
            <v-btn variant="text" size="x-small" color="error" density="compact" @click.stop="confirmDeleteFile(item)">删除</v-btn>
          </div>
        </template>
        <template #no-data>
          <div class="text-center text-medium-emphasis py-6">暂无文件</div>
        </template>
      </v-data-table>
    </v-card>

    <!-- Upload dialog -->
    <v-dialog v-model="showUpload" max-width="500">
      <v-card border>
        <v-card-title>上传文件</v-card-title>
        <v-card-text>
          <v-file-input v-model="uploadFiles" label="选择文件" variant="outlined" multiple show-size />
        </v-card-text>
        <v-card-actions>
          <v-spacer />
          <v-btn variant="text" @click="showUpload = false">取消</v-btn>
          <v-btn color="primary" variant="flat" @click="doUpload" :loading="uploading">上传</v-btn>
        </v-card-actions>
      </v-card>
    </v-dialog>

    <!-- Mkdir dialog -->
    <v-dialog v-model="showMkdir" max-width="400">
      <v-card border>
        <v-card-title>新建目录</v-card-title>
        <v-card-text>
          <v-text-field v-model="mkdirName" label="目录名" variant="outlined" density="compact" />
        </v-card-text>
        <v-card-actions>
          <v-spacer />
          <v-btn variant="text" @click="showMkdir = false">取消</v-btn>
          <v-btn color="primary" variant="flat" @click="doMkdir">创建</v-btn>
        </v-card-actions>
      </v-card>
    </v-dialog>

    <!-- Delete confirm -->
    <v-dialog v-model="showFileDelete" max-width="400">
      <v-card border>
        <v-card-title>确认删除</v-card-title>
        <v-card-text>确定要删除 <strong>{{ deletingFile?.name }}</strong> 吗？</v-card-text>
        <v-card-actions>
          <v-spacer />
          <v-btn variant="text" @click="showFileDelete = false">取消</v-btn>
          <v-btn color="error" variant="flat" @click="doDeleteFile">删除</v-btn>
        </v-card-actions>
      </v-card>
    </v-dialog>

    <!-- Rename dialog -->
    <v-dialog v-model="showRename" max-width="400">
      <v-card border>
        <v-card-title>重命名</v-card-title>
        <v-card-text>
          <v-text-field v-model="newName" label="新名称" variant="outlined" density="compact" :rules="[required('名称')]" autofocus @keydown.enter="doRename" />
        </v-card-text>
        <v-card-actions>
          <v-spacer />
          <v-btn variant="text" @click="showRename = false">取消</v-btn>
          <v-btn color="primary" variant="flat" @click="doRename">确定</v-btn>
        </v-card-actions>
      </v-card>
    </v-dialog>

    <!-- Chmod dialog -->
    <v-dialog v-model="showChmod" max-width="400">
      <v-card border>
        <v-card-title>修改权限</v-card-title>
        <v-card-text>
          <v-text-field v-model="chmodMode" label="权限 (如 755, 644)" variant="outlined" density="compact" :rules="[required('权限'), (v: string) => /^[0-7]{3,4}$/.test(v) || '格式: 3-4位八进制数']" autofocus @keydown.enter="doChmod" />
        </v-card-text>
        <v-card-actions>
          <v-spacer />
          <v-btn variant="text" @click="showChmod = false">取消</v-btn>
          <v-btn color="primary" variant="flat" @click="doChmod">确定</v-btn>
        </v-card-actions>
      </v-card>
    </v-dialog>

    <!-- Context Menu -->
    <v-menu v-model="showContextMenu" :target="[contextX, contextY]" location="bottom start">
      <v-list density="compact" nav>
        <v-list-item v-if="contextFile?.type !== 'directory'" prepend-icon="mdi-pencil" @click="contextAction('edit')">
          <v-list-item-title>编辑</v-list-item-title>
        </v-list-item>
        <v-list-item v-if="contextFile?.type !== 'directory'" prepend-icon="mdi-eye" @click="contextAction('preview')">
          <v-list-item-title>查看</v-list-item-title>
        </v-list-item>
        <v-list-item v-if="contextFile?.type !== 'directory'" prepend-icon="mdi-download" @click="contextAction('download')">
          <v-list-item-title>下载</v-list-item-title>
        </v-list-item>
        <v-divider />
        <v-list-item prepend-icon="mdi-file-rename-box" @click="contextAction('rename')">
          <v-list-item-title>重命名</v-list-item-title>
        </v-list-item>
        <v-list-item prepend-icon="mdi-lock" @click="contextAction('chmod')">
          <v-list-item-title>修改权限</v-list-item-title>
        </v-list-item>
        <v-divider />
        <v-list-item prepend-icon="mdi-delete" @click="contextAction('delete')">
          <v-list-item-title class="text-error">删除</v-list-item-title>
        </v-list-item>
      </v-list>
    </v-menu>

    <!-- Monaco Editor -->
    <MonacoEditor
      v-model="showEditor"
      :file-path="editorFilePath"
      :file-name="editorFileName"
      :file-content="editorContent"
      :server-id="selectedServer ?? 0"
      @saved="browse"
    />
  </v-container>
</template>

<script setup lang="ts">
import { ref, computed, onMounted, defineAsyncComponent } from 'vue'
import { useRoute } from 'vue-router'
import { http } from '@/api'
import { useServerList } from '@/composables/useServerList'
import { useSnackbar } from '@/composables/useSnackbar'
import { required } from '@/utils/validation'
const MonacoEditor = defineAsyncComponent(() => import('@/components/MonacoEditor.vue'))
import type { BrowseResponse, FileEntry } from '@/types/api'

/** Safe path join — avoids double-slash when at root */
function joinPath(base: string, name: string): string {
  return base === '/' ? `/${name}` : `${base}/${name}`
}

const snackbar = useSnackbar()
const { servers: serverList, loadServers } = useServerList()

const route = useRoute()

// ── State ──
const selectedServer = ref<number | null>(null)
const currentPath = ref('/')
const files = ref<FileEntry[]>([])
const loading = ref(false)

// Dialogs
const showUpload = ref(false)
const showMkdir = ref(false)
const showFileDelete = ref(false)
const uploadFiles = ref<File[]>([])
const uploading = ref(false)
const mkdirName = ref('')
const actionLoading = ref(false)
const deletingFile = ref<FileEntry | null>(null)

// Rename
const showRename = ref(false)
const newName = ref('')
const renamingFile = ref<FileEntry | null>(null)

// Chmod
const showChmod = ref(false)
const chmodMode = ref('')
const chmodFile = ref<FileEntry | null>(null)

// Context menu
const showContextMenu = ref(false)
const contextX = ref(0)
const contextY = ref(0)
const contextFile = ref<FileEntry | null>(null)

// Batch select
const selectedFiles = ref<FileEntry[]>([])
const selectedFileCount = computed(() => selectedFiles.value.length)

// Editor
const showEditor = ref(false)
const editorFilePath = ref('')
const editorFileName = ref('')
const editorContent = ref('')

const fileHeaders = [
  { title: '名称', key: 'name' },
  { title: '大小', key: 'size', width: 120 },
  { title: '修改时间', key: 'modified', width: 180 },
  { title: '权限', key: 'permissions', width: 100 },
  { title: '操作', key: 'actions', width: 200, align: 'end' as const },
]

// ── Breadcrumbs ──
const breadcrumbs = computed(() => {
  const parts = currentPath.value.split('/').filter(Boolean)
  const items = [{ title: '/', props: { onClick: () => { currentPath.value = '/'; browse() } } }]
  let path = ''
  for (const p of parts) {
    path += '/' + p
    const finalPath = path
    items.push({ title: p, props: { onClick: () => { currentPath.value = finalPath; browse() } } })
  }
  return items
})

// ── Data loading ──
async function browse() {
  if (!selectedServer.value) return
  loading.value = true
  try {
    const res = await http.post<BrowseResponse | FileEntry[]>('/sync/browse', {
      server_id: selectedServer.value,
      path: currentPath.value,
    })
    // Sort: directories first
    files.value = Array.isArray(res) ? res : (res as BrowseResponse).items || []
    files.value.sort((a, b) => {
      if (a.type === 'directory' && b.type !== 'directory') return -1
      if (a.type !== 'directory' && b.type === 'directory') return 1
      return a.name.localeCompare(b.name)
    })
  } catch {
    files.value = []
    snackbar('浏览目录失败', 'error')
  } finally {
    loading.value = false
  }
}

function onServerChange() {
  currentPath.value = '/'
  browse()
}

function onRowClick(_event: Event, { item }: { item: FileEntry }) {
  if (item.type === 'directory') {
    currentPath.value = currentPath.value === '/' ? `/${item.name}` : `${currentPath.value}/${item.name}`
    browse()
  }
}

function onRowContext(e: MouseEvent, { item }: { item: FileEntry }) {
  e.preventDefault()
  contextFile.value = item
  contextX.value = e.clientX
  contextY.value = e.clientY
  showContextMenu.value = true
}

function contextAction(action: string) {
  showContextMenu.value = false
  if (!contextFile.value) return
  switch (action) {
    case 'edit': editFile(contextFile.value); break
    case 'preview': previewFile(contextFile.value); break
    case 'download': downloadFile(contextFile.value); break
    case 'rename': startRename(contextFile.value); break
    case 'chmod': startChmod(contextFile.value); break
    case 'delete': confirmDeleteFile(contextFile.value); break
  }
}

function startRename(item: FileEntry) {
  renamingFile.value = item
  newName.value = item.name
  showRename.value = true
}

async function doRename() {
  if (!selectedServer.value || !renamingFile.value || !newName.value) return
  try {
    await http.post('/sync/file-ops', {
      server_id: selectedServer.value,
      operation: 'rename',
      path: joinPath(currentPath.value, renamingFile.value.name),
      new_path: joinPath(currentPath.value, newName.value),
    })
    showRename.value = false
    browse()
    snackbar('重命名成功')
  } catch (e: unknown) {
    const msg = e instanceof Error ? e.message : '重命名失败'
    snackbar(msg, 'error')
  }
}

function startChmod(item: FileEntry) {
  chmodFile.value = item
  chmodMode.value = ''
  showChmod.value = true
}

async function doChmod() {
  if (!selectedServer.value || !chmodFile.value || !chmodMode.value) return
  try {
    await http.post('/sync/chmod', {
      server_id: selectedServer.value,
      path: joinPath(currentPath.value, chmodFile.value.name),
      mode: chmodMode.value,
    })
    showChmod.value = false
    browse()
    snackbar('权限已修改')
  } catch (e: unknown) {
    const msg = e instanceof Error ? e.message : '修改权限失败'
    snackbar(msg, 'error')
  }
}

async function batchDelete() {
  if (!selectedServer.value || !selectedFiles.value.length) return
  if (!confirm(`确定删除 ${selectedFiles.value.length} 个文件？`)) return
  for (const f of selectedFiles.value) {
    try {
      await http.post('/sync/file-ops', {
        server_id: selectedServer.value,
        operation: 'delete',
        path: joinPath(currentPath.value, f.name),
      })
    } catch { /* skip individual failures */ }
  }
  selectedFiles.value = []
  browse()
  snackbar('批量删除完成')
}

async function previewFile(item: FileEntry) {
  if (!selectedServer.value) return
  actionLoading.value = true
  try {
    const res = await http.post('/sync/read-file', {
      server_id: selectedServer.value,
      path: joinPath(currentPath.value, item.name),
    })
    alert(typeof res === 'string' ? res : JSON.stringify(res, null, 2))
  } catch (e: any) {
    snackbar(e.message || '读取失败', 'error')
  } finally {
    actionLoading.value = false
  }
}

async function editFile(item: FileEntry) {
  if (!selectedServer.value) return
  actionLoading.value = true
  try {
    const res = await http.post<{ content?: string } | string>('/sync/read-file', {
      server_id: selectedServer.value,
      path: joinPath(currentPath.value, item.name),
    })
    const content = typeof res === 'string' ? res : (res.content ?? JSON.stringify(res, null, 2))
    editorFilePath.value = joinPath(currentPath.value, item.name)
    editorFileName.value = item.name
    editorContent.value = content
    showEditor.value = true
  } catch (e: unknown) {
    const msg = e instanceof Error ? e.message : '读取失败'
    snackbar(msg, 'error')
  } finally {
    actionLoading.value = false
  }
}

async function downloadFile(item: FileEntry) {
  if (!selectedServer.value) return
  try {
    await http.post('/sync/download', {
      server_id: selectedServer.value,
      remote_path: joinPath(currentPath.value, item.name),
    })
    snackbar('下载已开始')
  } catch (e: any) {
    snackbar(e.message || '下载失败', 'error')
  }
}

async function confirmDeleteFile(item: FileEntry) {
  deletingFile.value = item
  showFileDelete.value = true
}

async function doDeleteFile() {
  if (!selectedServer.value || !deletingFile.value) return
  actionLoading.value = true
  try {
    await http.post('/sync/file-ops', {
      server_id: selectedServer.value,
      operation: 'delete',
      path: joinPath(currentPath.value, deletingFile.value.name),
    })
    showFileDelete.value = false
    browse()
    snackbar('已删除')
  } catch (e: any) {
    snackbar(e.message || '删除失败', 'error')
  } finally {
    actionLoading.value = false
  }
}

async function doMkdir() {
  if (!selectedServer.value || !mkdirName.value) return
  actionLoading.value = true
  try {
    await http.post('/sync/file-ops', {
      server_id: selectedServer.value,
      operation: 'mkdir',
      path: joinPath(currentPath.value, mkdirName.value),
    })
    showMkdir.value = false
    mkdirName.value = ''
    browse()
    snackbar('目录已创建')
  } catch (e: any) {
    snackbar(e.message || '创建失败', 'error')
  } finally {
    actionLoading.value = false
  }
}

async function doUpload() {
  if (!selectedServer.value || !uploadFiles.value.length) return
  uploading.value = true
  try {
    const form = new FormData()
    for (const f of uploadFiles.value) form.append('files', f)
    form.append('server_id', String(selectedServer.value))
    form.append('remote_path', currentPath.value)
    await http.upload('/sync/upload', form)
    showUpload.value = false
    uploadFiles.value = []
    browse()
    snackbar('上传成功')
  } catch (e: any) {
    snackbar(e.message || '上传失败', 'error')
  } finally {
    uploading.value = false
  }
}

function formatSize(bytes: number | undefined) {
  if (!bytes) return '—'
  if (bytes < 1024) return bytes + ' B'
  if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'
  return (bytes / 1024 / 1024).toFixed(1) + ' MB'
}


// ── Init ──
onMounted(() => {
  loadServers()
  // Auto-select server from query param
  const qServer = route.query.server_id
  if (qServer) {
    selectedServer.value = Number(qServer)
    browse()
  }
})

</script>
