<script setup>
import { computed, ref } from 'vue'
import TreeNodeItem from './TreeNodeItem.vue'

const props = defineProps({
  nodes: { type: Array, required: true },
  selectedId: { type: String, default: null },
  expandedIds: { type: Set, required: true },
  clipboard: { type: Object, default: null },
  getFileIcon: { type: Function, required: true },
  loading: { type: Boolean, default: false },
  stats: {
    type: Object,
    default: () => ({ fileCount: 0, folderCount: 0, usedBytes: 0 })
  }
})

const emit = defineEmits([
  'select',
  'toggle',
  'create-file',
  'create-folder',
  'rename',
  'remove',
  'copy',
  'cut',
  'paste',
  'context-menu',
  'drop',
  'drag-start',
  'drag-over',
  'upload-files'
])

const renameId = ref(null)
const renameValue = ref('')
const creatingInFolder = ref(null)
const creatingType = ref(null)
const creatingName = ref('')
const keyword = ref('')
const uploadInput = ref(null)

const filteredNodes = computed(() => {
  const text = keyword.value.trim().toLowerCase()
  if (!text) return props.nodes
  const filterChildren = (nodes) => {
    const result = []
    for (const node of nodes) {
      if (node.type === 'folder') {
        const children = filterChildren(node.children || [])
        if (node.name.toLowerCase().includes(text) || children.length > 0) {
          result.push({ ...node, children })
        }
      } else if (node.name.toLowerCase().includes(text)) {
        result.push(node)
      }
    }
    return result
  }
  return filterChildren(props.nodes)
})

function formatBytes(bytes = 0) {
  if (!bytes) return '0 B'
  const units = ['B', 'KB', 'MB', 'GB', 'TB']
  let value = bytes
  let index = 0
  while (value >= 1024 && index < units.length - 1) {
    value /= 1024
    index += 1
  }
  return `${value >= 100 || index === 0 ? value.toFixed(0) : value.toFixed(1)} ${units[index]}`
}

function startRename(node) {
  renameId.value = node.id
  renameValue.value = node.name
}

function finishRename(node) {
  if (renameId.value === node.id && renameValue.value.trim()) {
    emit('rename', node.id, renameValue.value.trim())
  }
  renameId.value = null
  renameValue.value = ''
}

function cancelRename() {
  renameId.value = null
  renameValue.value = ''
}

function startCreate(parentId, type) {
  creatingInFolder.value = parentId
  creatingType.value = type
  creatingName.value = type === 'file' ? 'untitled.md' : ''
}

function finishCreate() {
  const name = creatingName.value.trim()
  if (!name) {
    cancelCreate()
    return
  }
  if (creatingType.value === 'file') emit('create-file', creatingInFolder.value, name)
  else emit('create-folder', creatingInFolder.value, name)
  cancelCreate()
}

function cancelCreate() {
  creatingInFolder.value = null
  creatingType.value = null
  creatingName.value = ''
}

function handleContextMenu(x, y, node) {
  emit('context-menu', x, y, node)
}

function handleDrop(draggedId, targetNode) {
  emit('drop', draggedId, targetNode ? targetNode.id : null)
}

function handleDropRoot(event) {
  event.preventDefault()
  const draggedId = event.dataTransfer.getData('text/plain')
  if (draggedId) emit('drop', draggedId, null)
}

function getIconClass(type, name) {
  if (type === 'folder') return 'icon-folder'
  return `icon-file icon-${props.getFileIcon(name)}`
}

function triggerUpload() {
  uploadInput.value?.click()
}

function handleUpload(event) {
  const files = event.target.files
  if (files?.length) emit('upload-files', files)
  event.target.value = ''
}

function forwardDragStart(event, id) {
  emit('drag-start', event, id)
}

function forwardDragOver(event, id) {
  emit('drag-over', event, id)
}
</script>

<template>
  <div class="file-tree">
    <div class="sidebar-head">
      <div class="sidebar-title-row">
        <div class="sidebar-title-wrap">
          <span class="sidebar-title-icon">
            <svg viewBox="0 0 16 16" width="16" height="16" fill="currentColor"><path d="M1.75 1A1.75 1.75 0 000 2.75v10.5C0 14.216.784 15 1.75 15h12.5A1.75 1.75 0 0016 13.25V2.75A1.75 1.75 0 0014.25 1H1.75zm0 1.5h12.5a.25.25 0 01.25.25v10.5a.25.25 0 01-.25.25H1.75a.25.25 0 01-.25-.25V2.75a.25.25 0 01.25-.25z"/><path d="M4 3.75A.75.75 0 014.75 3h2.5a.75.75 0 010 1.5h-2.5A.75.75 0 014 3.75zm0 3A.75.75 0 014.75 6h6.5a.75.75 0 010 1.5h-6.5A.75.75 0 014 6.75zm0 3a.75.75 0 01.75-.75h6.5a.75.75 0 010 1.5h-6.5A.75.75 0 014 9.75z"/></svg>
                </span>
                <div>
                  <h2>文档模式</h2>
                </div>
              </div>
<button class="upload-btn" type="button" title="上传文件" @click="triggerUpload">
<svg viewBox="0 0 16 16" width="14" height="14" fill="currentColor"><path d="M2.5 12.5a1 1 0 011-1h9a1 1 0 110 2h-9a1 1 0 01-1-1z"/><path d="M8 2l5 5H9.5v4.5h-3V7H3l5-5z"/></svg>
上传
</button>
        <input ref="uploadInput" type="file" multiple class="hidden-input" @change="handleUpload" />
      </div>

      <div class="branch-bar">
        <button class="branch-chip" type="button">
          <svg viewBox="0 0 16 16" width="14" height="14" fill="currentColor"><path d="M1.5 2.75a2.25 2.25 0 114.5 0 2.25 2.25 0 01-1.5 2.122v5.256a2.251 2.251 0 11-1.5 0V4.872A2.251 2.251 0 011.5 2.75zm8.25 0a2.25 2.25 0 114.5 0 2.25 2.25 0 01-1.5 2.122v.378a3.25 3.25 0 01-3.25 3.25h-1v1.628a2.251 2.251 0 11-1.5 0V7.75a.75.75 0 01.75-.75H9.5A1.75 1.75 0 0011.25 5.25v-.378A2.251 2.251 0 019.75 2.75z"/></svg>
          main
        </button>
        <div class="branch-actions">
          <button class="header-icon-btn" type="button" title="新建文件" @click="startCreate(null, 'file')">
            <svg viewBox="0 0 16 16" width="14" height="14" fill="currentColor"><path d="M4.75 1.5a.25.25 0 00-.25.25v12.5c0 .138.112.25.25.25h6.5a.25.25 0 00.25-.25V5.664a.25.25 0 00-.073-.177L8.513 2.573A.25.25 0 008.336 2.5H4.75zm0-1.5h3.586c.464 0 .909.184 1.237.513l2.914 2.914c.329.328.513.773.513 1.237v9.586A1.75 1.75 0 0111.25 16h-6.5A1.75 1.75 0 013 14.25V1.75A1.75 1.75 0 014.75 0z"/><path d="M8 6a.75.75 0 01.75.75v1.5h1.5a.75.75 0 010 1.5h-1.5v1.5a.75.75 0 01-1.5 0v-1.5h-1.5a.75.75 0 010-1.5h1.5v-1.5A.75.75 0 018 6z"/></svg>
          </button>
          <button class="header-icon-btn" type="button" title="新建文件夹" @click="startCreate(null, 'folder')">
            <svg viewBox="0 0 16 16" width="14" height="14" fill="currentColor"><path d="M1.75 1A1.75 1.75 0 000 2.75v8.5C0 12.216.784 13 1.75 13h12.5A1.75 1.75 0 0016 11.25v-6.5A1.75 1.75 0 0014.25 3H7.31l-.97-.97A1.75 1.75 0 005.103 1H1.75zm0 1.5h3.353a.25.25 0 01.177.073l1.409 1.408c.14.141.332.22.53.22h7.03a.25.25 0 01.25.25v6.8a.25.25 0 01-.25.25H1.75a.25.25 0 01-.25-.25v-8.5a.25.25 0 01.25-.25z"/><path d="M8 6a.75.75 0 01.75.75v1h1a.75.75 0 010 1.5h-1v1a.75.75 0 01-1.5 0v-1h-1a.75.75 0 010-1.5h1v-1A.75.75 0 018 6z"/></svg>
          </button>
        </div>
      </div>

      <label class="search-box">
        <svg viewBox="0 0 16 16" width="14" height="14" fill="currentColor"><path d="M10.5 10.5a4.5 4.5 0 10-1 1l3.5 3.5 1-1-3.5-3.5zM6.5 10a3.5 3.5 0 110-7 3.5 3.5 0 010 7z"/></svg>
        <input v-model="keyword" type="text" placeholder="Go to file" />
        <span class="search-shortcut">t</span>
      </label>

      <div class="stats-row">
        <span>{{ stats.folderCount }} 个文件夹</span>
        <span>{{ stats.fileCount }} 个文件</span>
        <span>{{ formatBytes(stats.usedBytes) }}</span>
      </div>
    </div>

    <div class="tree-header">
      <span>Code</span>
      <span class="tree-header-sub">{{ keyword ? `搜索：${keyword}` : '全部文件' }}</span>
    </div>

    <div class="tree-content" @drop="handleDropRoot" @dragover="(event) => event.preventDefault()">
      <div v-if="loading" class="tree-empty">
        <p>正在加载本地文件…</p>
      </div>

      <template v-else-if="filteredNodes.length">
        <TreeNodeItem
          v-for="node in filteredNodes"
          :key="node.id"
          :node="node"
          :level="0"
          :selected-id="selectedId"
          :expanded-ids="expandedIds"
          :clipboard="clipboard"
          :get-icon-class="getIconClass"
          :rename-id="renameId"
          :rename-value="renameValue"
          :creating-in-folder="creatingInFolder"
          :creating-type="creatingType"
          :creating-name="creatingName"
          @select="emit('select', $event)"
          @toggle="emit('toggle', $event)"
          @start-rename="startRename"
          @finish-rename="finishRename"
          @cancel-rename="cancelRename"
          @update:rename-value="renameValue = $event"
          @start-create="startCreate"
          @finish-create="finishCreate"
          @cancel-create="cancelCreate"
          @update:creating-name="creatingName = $event"
          @context-menu="handleContextMenu"
          @drop="handleDrop"
          @drag-start="forwardDragStart"
          @drag-over="forwardDragOver"
        />
      </template>

      <div v-else class="tree-empty">
        <p>{{ keyword ? '没有匹配的文件' : '还没有本地文件' }}</p>
        <div class="tree-empty-actions">
          <button type="button" @click="triggerUpload">上传文件</button>
          <button type="button" @click="startCreate(null, 'folder')">新建文件夹</button>
        </div>
      </div>
    </div>
  </div>
</template>

<style scoped>
.file-tree {
  width: 100%;
  height: 100%;
  display: flex;
  flex-direction: column;
  background: var(--github-bg);
  color: var(--github-text);
}

.sidebar-head {
  padding: 14px 12px 10px;
  border-bottom: 1px solid var(--github-border);
  background: linear-gradient(180deg, rgba(246, 248, 250, 0.96), rgba(255, 255, 255, 0.98));
}

[data-theme='dark'] .sidebar-head {
  background: linear-gradient(180deg, rgba(17, 24, 39, 0.96), rgba(15, 17, 23, 0.98));
}

.sidebar-title-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
}

.sidebar-title-wrap {
  display: flex;
  align-items: center;
  gap: 10px;
}

.sidebar-title-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 34px;
  height: 34px;
  border-radius: 10px;
  background: rgba(9, 105, 218, 0.08);
  color: #0969da;
}

.sidebar-title-wrap h2 {
  margin: 0;
  font-size: 1.05rem;
  font-weight: 700;
}

.sidebar-title-wrap p {
  margin: 2px 0 0;
  font-size: 12px;
  color: var(--github-text-secondary);
}

.upload-btn {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  height: 32px;
  padding: 0 12px;
  border: 1px solid #1f883d;
  border-radius: 8px;
  background: #1f883d;
  color: #fff;
  font-size: 13px;
  font-weight: 600;
  cursor: pointer;
}

.upload-btn:hover {
  background: #1a7f37;
}

.hidden-input {
  display: none;
}

.branch-bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  margin-top: 14px;
}

.branch-chip {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  height: 32px;
  padding: 0 12px;
  border: 1px solid var(--github-border);
  border-radius: 8px;
  background: var(--github-bg);
  color: var(--github-text);
  font-size: 13px;
  font-weight: 600;
}

.branch-actions {
  display: flex;
  gap: 4px;
  padding: 2px;
  border: 1px solid var(--github-border);
  border-radius: 10px;
  background: var(--github-bg);
}

.header-icon-btn {
  width: 28px;
  height: 28px;
  border: 1px solid transparent;
  background: transparent;
}

.header-icon-btn:hover {
  color: var(--github-text);
  background: var(--github-hover);
}

.search-box {
  display: flex;
  align-items: center;
  gap: 8px;
  height: 34px;
  margin-top: 12px;
  padding: 0 10px;
  border: 1px solid var(--github-border);
  border-radius: 8px;
  background: var(--github-bg);
  color: var(--github-text-secondary);
}

.search-box input {
  flex: 1;
  min-width: 0;
  border: none;
  outline: none;
  background: transparent;
  color: var(--github-text);
  font-size: 13px;
}

.search-shortcut {
  padding: 1px 6px;
  border: 1px solid var(--github-border);
  border-radius: 999px;
  font-size: 11px;
  color: var(--github-text-secondary);
}

.stats-row {
  display: flex;
  gap: 10px;
  flex-wrap: wrap;
  margin-top: 10px;
  font-size: 12px;
  color: var(--github-text-secondary);
}

.tree-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  min-height: 38px;
  padding: 0 12px;
  border-bottom: 1px solid var(--github-border);
  font-size: 12px;
  font-weight: 700;
  color: var(--github-text-secondary);
  text-transform: uppercase;
  letter-spacing: 0.06em;
}

.tree-header-sub {
  text-transform: none;
  letter-spacing: 0;
  font-weight: 500;
  color: var(--github-text-secondary);
}

.tree-content {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  overflow-x: hidden;
  overscroll-behavior-y: contain;
  padding: 6px 0 10px;
}

.tree-empty {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 14px;
  padding: 40px 20px;
  color: var(--github-text-secondary);
  text-align: center;
}

.tree-empty p {
  margin: 0;
  font-size: 13px;
}

.tree-empty-actions {
  display: flex;
  gap: 8px;
}

.tree-empty-actions button {
  height: 32px;
  padding: 0 12px;
  border: 1px solid var(--github-border);
  border-radius: 8px;
  background: var(--github-bg);
  color: var(--github-text);
  cursor: pointer;
}

.tree-empty-actions button:hover {
  background: var(--github-hover);
}

.tree-node {
  display: flex;
  align-items: center;
  gap: 6px;
  height: 30px;
  padding-right: 8px;
  font-size: 13px;
  color: var(--github-text);
  cursor: pointer;
  user-select: none;
}

.tree-node:hover {
  background: var(--github-hover);
}

.tree-node.selected {
  background: var(--github-selected);
  color: var(--github-text);
}

.tree-node.clipped {
  opacity: 0.55;
}

.tree-node-new {
  margin: 2px 8px;
  border: 1px dashed var(--github-border);
  border-radius: 8px;
}

.chevron,
.chevron-placeholder {
  width: 20px;
  height: 20px;
  flex-shrink: 0;
}

.icon-folder,
.icon-file {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 16px;
  height: 16px;
  flex-shrink: 0;
}

.icon-folder::before {
  content: '📁';
  font-size: 14px;
}

.icon-file::before {
  content: '📄';
  font-size: 13px;
}

.icon-markdown::before { content: 'Ⓜ'; font-size: 12px; font-weight: 700; color: #0969da; }
.icon-json::before { content: '{ }'; font-size: 8px; font-weight: 700; color: #8250df; }
.icon-javascript::before { content: 'JS'; font-size: 9px; font-weight: 700; color: #9a6700; }
.icon-typescript::before { content: 'TS'; font-size: 9px; font-weight: 700; color: #0969da; }
.icon-css::before { content: 'CSS'; font-size: 7px; font-weight: 700; color: #1f883d; }
.icon-html::before { content: 'HTML'; font-size: 6px; font-weight: 700; color: #bc4c00; }
.icon-python::before { content: 'PY'; font-size: 9px; font-weight: 700; color: #0969da; }
.icon-vue::before { content: 'Vue'; font-size: 8px; font-weight: 700; color: #1f883d; }
.icon-yaml::before { content: 'YML'; font-size: 8px; font-weight: 700; color: #0969da; }
.icon-xml::before { content: '</>'; font-size: 8px; font-weight: 700; color: #bc4c00; }
.icon-csv::before { content: 'CSV'; font-size: 8px; font-weight: 700; color: #1f883d; }
.icon-log::before { content: 'LOG'; font-size: 7px; font-weight: 700; color: #6e7781; }
.icon-sql::before { content: 'SQL'; font-size: 8px; font-weight: 700; color: #8250df; }
.icon-image::before { content: '🖼'; font-size: 13px; }
.icon-pdf::before { content: 'PDF'; font-size: 8px; font-weight: 700; color: #cf222e; }
.icon-word::before { content: 'DOC'; font-size: 7px; font-weight: 700; color: #0969da; }
.icon-ppt::before { content: 'PPT'; font-size: 7px; font-weight: 700; color: #bc4c00; }
.icon-excel::before { content: 'XLS'; font-size: 7px; font-weight: 700; color: #1f883d; }
.icon-zip::before { content: 'ZIP'; font-size: 7px; font-weight: 700; color: #6f42c1; }
.icon-text::before { content: 'TXT'; font-size: 8px; font-weight: 700; color: #6e7781; }

.node-name {
  flex: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.rename-input {
  flex: 1;
  min-width: 0;
  height: 24px;
  padding: 0 8px;
  border: 1px solid #0969da;
  border-radius: 6px;
  outline: none;
  background: var(--github-bg);
  color: var(--github-text);
  font-size: 13px;
}

.node-actions {
  display: flex;
  gap: 4px;
  margin-left: 4px;
  opacity: 0;
  transition: opacity 0.15s ease;
}

.tree-node:hover .node-actions,
.tree-node.selected .node-actions {
  opacity: 1;
}

.header-icon-btn,
.action-btn,
.chevron {
  appearance: none;
  -webkit-appearance: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 0;
  border-radius: 6px;
  color: var(--github-text-secondary);
  cursor: pointer;
  flex-shrink: 0;
  line-height: 0;
}

.chevron {
  margin-left: -2px;
  border: 1px solid transparent;
  background: transparent;
}

.action-btn {
  width: 20px;
  height: 20px;
  border: 1px solid transparent;
  background: transparent;
}

.header-icon-btn svg,
.action-btn svg,
.chevron svg {
  display: block;
}

.header-icon-btn:hover,
.action-btn:hover,
.tree-node:hover .chevron,
.tree-node.selected .chevron {
  background: rgba(9, 105, 218, 0.08);
  color: var(--github-text);
}

.header-icon-btn:focus-visible,
.action-btn:focus-visible,
.chevron:focus-visible {
  outline: none;
  box-shadow: 0 0 0 2px rgba(9, 105, 218, 0.18);
}

.tree-content::-webkit-scrollbar {
  width: 8px;
}

.tree-content::-webkit-scrollbar-thumb {
  background: rgba(99, 110, 123, 0.28);
  border-radius: 999px;
}

@media (max-width: 768px) {
  .tree-content::-webkit-scrollbar {
    width: 0 !important;
    height: 0 !important;
  }
}
</style>
