<script setup lang="ts">
import { NButton, NInput, NPopconfirm, NPopselect, NSpace, NTag } from 'naive-ui'

import type { DataTableColumns, DropdownOption } from 'naive-ui'
import type { RowData } from 'naive-ui/es/data-table/src/interface'

import file from '@/api/panel/file'
import TheIcon from '@/components/custom/TheIcon.vue'
import EventBus from '@/utils/event'
import { checkName, checkPath, getExt, getFilename, getIconByExt, isCompress } from '@/utils/file'
import EditModal from '@/views/file/EditModal.vue'
import type { Marked } from '@/views/file/types'

const loading = ref(false)
const sort = ref<string>('')
const path = defineModel<string>('path', { type: String, required: true })
const selected = defineModel<any[]>('selected', { type: Array, default: () => [] })
const marked = defineModel<Marked[]>('marked', { type: Array, default: () => [] })
const compress = defineModel<boolean>('compress', { type: Boolean, required: true })
const permission = defineModel<boolean>('permission', { type: Boolean, required: true })
const editorModal = ref(false)
const editorFile = ref('')

const showDropdown = ref(false)
const selectedRow = ref<any>()
const dropdownX = ref(0)
const dropdownY = ref(0)

const renameModal = ref(false)
const renameModel = ref({
  source: '',
  target: ''
})
const unCompressModal = ref(false)
const unCompressModel = ref({
  path: '',
  file: ''
})

const options = computed<DropdownOption[]>(() => {
  if (selectedRow.value == null) return []
  return [
    {
      label: selectedRow.value.dir ? '打开' : '编辑',
      key: selectedRow.value.dir ? 'open' : 'edit'
    },
    { label: '复制', key: 'copy' },
    { label: '移动', key: 'move' },
    { label: '权限', key: 'permission' },
    {
      label: selectedRow.value.dir ? '压缩' : '下载',
      key: selectedRow.value.dir ? 'compress' : 'download'
    },
    {
      label: '解压',
      key: 'uncompress',
      show: isCompress(selectedRow.value.full),
      disabled: !isCompress(selectedRow.value.full)
    },
    { label: '重命名', key: 'rename' },
    { label: () => h('span', { style: { color: 'red' } }, '删除'), key: 'delete' }
  ]
})

const columns: DataTableColumns<RowData> = [
  {
    type: 'selection',
    fixed: 'left'
  },
  {
    title: '名称',
    key: 'name',
    minWidth: 180,
    defaultSortOrder: false,
    sorter: 'default',
    render(row) {
      let icon = 'bi:file-earmark'
      if (row.dir) {
        icon = 'bi:folder'
      } else {
        icon = getIconByExt(getExt(row.name))
      }

      return h(
        NSpace,
        {
          class: 'table-name',
          onClick: () => {
            if (row.dir) {
              path.value = row.full
            } else {
              editorFile.value = row.full
              editorModal.value = true
            }
          }
        },
        () => [
          h(TheIcon, { icon, size: 24, color: `var(--primary-color)` }),
          h('span', null, {
            default: () => {
              if (row.symlink) {
                return row.name + ' -> ' + row.link
              } else {
                return row.name
              }
            }
          })
        ]
      )
    }
  },
  {
    title: '权限',
    key: 'mode',
    minWidth: 80,
    render(row: any): any {
      return h(
        NTag,
        { type: 'success', size: 'small', bordered: false },
        { default: () => row.mode }
      )
    }
  },
  {
    title: '所有者 / 组',
    key: 'owner/group',
    minWidth: 120,
    render(row: any): any {
      return h('div', null, [
        h(NTag, { type: 'primary', size: 'small', bordered: false }, { default: () => row.owner }),
        ' / ',
        h(NTag, { type: 'primary', size: 'small', bordered: false }, { default: () => row.group })
      ])
    }
  },
  {
    title: '大小',
    key: 'size',
    minWidth: 80,
    render(row: any): any {
      return h(NTag, { type: 'info', size: 'small', bordered: false }, { default: () => row.size })
    }
  },
  {
    title: '修改时间',
    key: 'modify',
    minWidth: 200,
    render(row: any): any {
      return h(
        NTag,
        { type: 'warning', size: 'small', bordered: false },
        { default: () => row.modify }
      )
    }
  },
  {
    title: '操作',
    key: 'action',
    width: 340,
    render(row) {
      return h(
        NSpace,
        {},
        {
          default: () => [
            h(
              NButton,
              {
                size: 'small',
                type: row.dir ? 'success' : 'primary',
                tertiary: true,
                onClick: () => {
                  if (!row.dir && !row.symlink) {
                    editorFile.value = row.full
                    editorModal.value = true
                  } else {
                    path.value = row.full
                  }
                }
              },
              {
                default: () => {
                  if (!row.dir && !row.symlink) {
                    return '编辑'
                  } else {
                    return '打开'
                  }
                }
              }
            ),
            h(
              NButton,
              {
                size: 'small',
                type: row.dir ? 'primary' : 'info',
                tertiary: true,
                onClick: () => {
                  if (row.dir) {
                    selected.value = [row.full]
                    compress.value = true
                  } else {
                    window.open('/api/file/download?path=' + encodeURIComponent(row.full))
                  }
                }
              },
              {
                default: () => {
                  if (row.dir) {
                    return '压缩'
                  } else {
                    return '下载'
                  }
                }
              }
            ),
            h(
              NButton,
              {
                type: 'warning',
                size: 'small',
                tertiary: true,
                onClick: () => {
                  renameModel.value.source = getFilename(row.name)
                  renameModel.value.target = getFilename(row.name)
                  renameModal.value = true
                }
              },
              { default: () => '重命名' }
            ),
            h(
              NPopconfirm,
              {
                onPositiveClick: () => {
                  file.delete(row.full).then(() => {
                    window.$message.success('删除成功')
                    EventBus.emit('file:refresh')
                  })
                },
                onNegativeClick: () => {}
              },
              {
                default: () => {
                  return '确定删除吗？'
                },
                trigger: () => {
                  return h(
                    NButton,
                    {
                      size: 'small',
                      type: 'error',
                      tertiary: true
                    },
                    { default: () => '删除' }
                  )
                }
              }
            ),
            h(
              NPopselect,
              {
                options: [
                  { label: '复制', value: 'copy' },
                  { label: '移动', value: 'move' },
                  { label: '权限', value: 'permission' },
                  { label: '压缩', value: 'compress' },
                  { label: '解压', value: 'uncompress', disabled: !isCompress(row.name) }
                ],
                onUpdateValue: (value) => {
                  switch (value) {
                    case 'copy':
                      marked.value = [
                        {
                          name: row.name,
                          source: row.full,
                          type: 'copy'
                        }
                      ]
                      window.$message.success('标记成功，请前往目标路径粘贴')
                      break
                    case 'move':
                      marked.value = [
                        {
                          name: row.name,
                          source: row.full,
                          type: 'move'
                        }
                      ]
                      window.$message.success('标记成功，请前往目标路径粘贴')
                      break
                    case 'permission':
                      selected.value = [row.full]
                      permission.value = true
                      break
                    case 'compress':
                      selected.value = [row.full]
                      compress.value = true
                      break
                    case 'uncompress':
                      unCompressModel.value.file = row.full
                      unCompressModel.value.path = path.value
                      unCompressModal.value = true
                      break
                  }
                }
              },
              {
                default: () => {
                  return h(
                    NButton,
                    {
                      tertiary: true,
                      size: 'small'
                    },
                    { default: () => '更多' }
                  )
                }
              }
            )
          ]
        }
      )
    }
  }
]

const rowProps = (row: any) => {
  return {
    onContextmenu: (e: MouseEvent) => {
      e.preventDefault()
      showDropdown.value = false
      nextTick().then(() => {
        showDropdown.value = true
        selectedRow.value = row
        dropdownX.value = e.clientX
        dropdownY.value = e.clientY
      })
    }
  }
}

const data = ref<RowData[]>([])

const pagination = reactive({
  page: 1,
  pageCount: 1,
  pageSize: 100,
  itemCount: 0,
  showQuickJumper: true,
  showSizePicker: true,
  pageSizes: [100, 200, 500, 1000, 1500, 2000, 5000]
})

const handlePageSizeChange = (pageSize: number) => {
  pagination.pageSize = pageSize
  handlePageChange(1)
}

const handlePageChange = async (page: number) => {
  loading.value = true
  await getList(path.value, page, pagination.pageSize!).finally(() => {
    loading.value = false
  })
}

const handleRefresh = async () => {
  loading.value = true
  await getList(path.value, pagination.page, pagination.pageSize!).finally(() => {
    loading.value = false
  })
}

const getList = async (path: string, page: number, limit: number) => {
  await file.list(path, page, limit, sort.value).then((res) => {
    data.value = res.data.items
    pagination.page = page
    pagination.itemCount = res.data.total
    pagination.pageCount = res.data.total / pagination.pageSize! + 1
  })
}

const handleRename = () => {
  const source = path.value + '/' + renameModel.value.source
  const target = path.value + '/' + renameModel.value.target
  if (!checkName(renameModel.value.source) || !checkName(renameModel.value.target)) {
    window.$message.error('名称不合法')
    return
  }

  file.move(source, target).then(() => {
    window.$message.success('重命名成功')
    renameModal.value = false
    EventBus.emit('file:refresh')
  })
}

const handleUnCompress = () => {
  // 移除首位的 / 去检测
  if (
    !unCompressModel.value.path.startsWith('/') ||
    !checkPath(unCompressModel.value.path.slice(1))
  ) {
    window.$message.error('路径不合法')
    return
  }
  const message = window.$message.loading('正在解压中...', {
    duration: 0
  })
  file
    .unCompress(unCompressModel.value.file, unCompressModel.value.path)
    .then(() => {
      message?.destroy()
      window.$message.success('解压成功')
      unCompressModal.value = false
      EventBus.emit('file:refresh')
    })
    .catch(() => {
      message?.destroy()
      window.$message.error('解压失败')
    })
}

const onChecked = (rowKeys: any) => {
  selected.value = rowKeys
}

const handleSelect = (key: string) => {
  switch (key) {
    case 'open':
      path.value = selectedRow.value.full
      break
    case 'edit':
      editorFile.value = selectedRow.value.full
      editorModal.value = true
      break
    case 'copy':
      marked.value = [
        {
          name: selectedRow.value.name,
          source: selectedRow.value.full,
          type: 'copy'
        }
      ]
      window.$message.success('标记成功，请前往目标路径粘贴')
      break
    case 'move':
      marked.value = [
        {
          name: selectedRow.value.name,
          source: selectedRow.value.full,
          type: 'move'
        }
      ]
      window.$message.success('标记成功，请前往目标路径粘贴')
      break
    case 'permission':
      selected.value = [selectedRow.value.full]
      permission.value = true
      break
    case 'compress':
      selected.value = [selectedRow.value.full]
      compress.value = true
      break
    case 'download':
      window.open('/api/file/download?path=' + encodeURIComponent(selectedRow.value.full))
      break
    case 'uncompress':
      unCompressModel.value.file = selectedRow.value.full
      unCompressModel.value.path = path.value
      unCompressModal.value = true
      break
    case 'rename':
      renameModel.value.source = getFilename(selectedRow.value.name)
      renameModel.value.target = getFilename(selectedRow.value.name)
      renameModal.value = true
      break
    case 'delete':
      file.delete(selectedRow.value.full).then(() => {
        window.$message.success('删除成功')
        EventBus.emit('file:refresh')
      })
      break
  }
  onCloseDropdown()
}

const onCloseDropdown = () => {
  selectedRow.value = null
  showDropdown.value = false
}

const handleSorterChange = (sorter: {
  columnKey: string | number | null
  order: 'ascend' | 'descend' | false
}) => {
  if (!sorter || sorter.columnKey === 'name') {
    if (!loading.value) {
      switch (sorter.order) {
        case 'ascend':
          sort.value = 'asc'
          handleRefresh()
          break
        case 'descend':
          sort.value = 'desc'
          handleRefresh()
          break
        default:
          sort.value = ''
          handleRefresh()
          break
      }
    }
  }
}

onMounted(() => {
  watch(
    path,
    () => {
      handlePageChange(1)
      EventBus.emit('push-history', path.value)
    },
    { immediate: true }
  )
  EventBus.on('file:refresh', handleRefresh)
})

onUnmounted(() => {
  EventBus.off('file:refresh', handleRefresh)
})
</script>

<template>
  <n-data-table
    remote
    striped
    virtual-scroll
    size="small"
    :scroll-x="1200"
    :columns="columns"
    :data="data"
    :row-props="rowProps"
    :loading="loading"
    :pagination="pagination"
    :row-key="(row: any) => row.full"
    :checked-row-keys="selected"
    max-height="60vh"
    @update:page="handlePageChange"
    @update:page-size="handlePageSizeChange"
    @update:sorter="handleSorterChange"
    @update:checked-row-keys="onChecked"
  />
  <n-dropdown
    placement="bottom-start"
    trigger="manual"
    :x="dropdownX"
    :y="dropdownY"
    :options="options"
    :show="showDropdown"
    :on-clickoutside="onCloseDropdown"
    @select="handleSelect"
  />
  <edit-modal v-model:show="editorModal" v-model:file="editorFile" />
  <n-modal
    v-model:show="renameModal"
    preset="card"
    :title="'重命名 - ' + renameModel.source"
    style="width: 60vw"
    size="huge"
    :bordered="false"
    :segmented="false"
  >
    <n-flex vertical>
      <n-form>
        <n-form-item label="新名称">
          <n-input v-model:value="renameModel.target" />
        </n-form-item>
      </n-form>
      <n-button type="primary" @click="handleRename">保存</n-button>
    </n-flex>
  </n-modal>
  <n-modal
    v-model:show="unCompressModal"
    preset="card"
    :title="'解压缩 - ' + unCompressModel.file"
    style="width: 60vw"
    size="huge"
    :bordered="false"
    :segmented="false"
  >
    <n-flex vertical>
      <n-form>
        <n-form-item label="解压到">
          <n-input v-model:value="unCompressModel.path" />
        </n-form-item>
      </n-form>
      <n-button type="primary" @click="handleUnCompress">解压</n-button>
    </n-flex>
  </n-modal>
</template>

<style scoped lang="scss">
:deep(.table-name) {
  cursor: pointer;
}

:deep(.table-name:hover) {
  color: var(--primary-color);
  opacity: 0.6;
}
</style>
