<script setup>
import { computed } from 'vue'

const props = defineProps({
  node: { type: Object, required: true },
  level: { type: Number, required: true },
  selectedId: { type: String, default: null },
  expandedIds: { type: Object, required: true },
  clipboard: { type: Object, default: null },
  getIconClass: { type: Function, required: true },
  renameId: { type: String, default: null },
  renameValue: { type: String, default: '' },
  creatingInFolder: { type: String, default: null },
  creatingType: { type: String, default: null },
  creatingName: { type: String, default: '' }
})

const emit = defineEmits([
  'select',
  'toggle',
  'start-rename',
  'finish-rename',
  'cancel-rename',
  'update:rename-value',
  'start-create',
  'finish-create',
  'cancel-create',
  'update:creating-name',
  'context-menu',
  'drop',
  'drag-start',
  'drag-over'
])

const isSelected = computed(() => props.node.id === props.selectedId)
const isExpanded = computed(() => props.expandedIds?.has(props.node.id))
const isClipped = computed(() => {
  if (!props.clipboard) return false
  return props.clipboard.node?.id === props.node.id || props.clipboard.nodeId === props.node.id
})
const isRenaming = computed(() => props.renameId === props.node.id)
const isCreating = computed(() => props.creatingInFolder === props.node.id)
const paddingLeft = computed(() => `${props.level * 16 + 12}px`)
const createPaddingLeft = computed(() => `${(props.level + 1) * 16 + 12}px`)

function handleContextMenu(event) {
  event.preventDefault()
  event.stopPropagation()
  emit('context-menu', event.clientX, event.clientY, props.node)
}

function handleDrop(event) {
  event.preventDefault()
  event.stopPropagation()
  const draggedId = event.dataTransfer.getData('text/plain')
  if (draggedId) emit('drop', draggedId, props.node)
}

function handleDragStart(event) {
  event.dataTransfer.effectAllowed = 'move'
  event.dataTransfer.setData('text/plain', props.node.id)
  emit('drag-start', event, props.node.id)
}

function handleDragOver(event) {
  event.preventDefault()
  emit('drag-over', event, props.node.id)
}

function forwardStartCreate(id, type) {
  emit('start-create', id, type)
}

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

function forwardDrop(id, node) {
  emit('drop', id, node)
}

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

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

<template>
  <div
    class="tree-node"
    :class="{ selected: isSelected, clipped: isClipped }"
    :style="{ paddingLeft }"
    draggable="true"
    @click="emit('select', node.id)"
    @contextmenu="handleContextMenu"
    @dragstart="handleDragStart"
    @dragover="handleDragOver"
    @drop="handleDrop"
  >
    <button
      v-if="node.type === 'folder'"
      class="chevron"
      type="button"
      @click.stop="emit('toggle', node.id)"
    >
      <svg v-if="isExpanded" viewBox="0 0 16 16" width="14" height="14" fill="currentColor"><path d="M4 6l4 4 4-4z" /></svg>
      <svg v-else viewBox="0 0 16 16" width="14" height="14" fill="currentColor"><path d="M6 4l4 4-4 4z" /></svg>
    </button>
    <span v-else class="chevron-placeholder"></span>

    <span :class="getIconClass(node.type, node.name)"></span>

    <input
      v-if="isRenaming"
      class="rename-input"
      :value="renameValue"
      @input="emit('update:rename-value', $event.target.value)"
      @keydown.enter="emit('finish-rename', node)"
      @keydown.esc="emit('cancel-rename')"
      @blur="emit('finish-rename', node)"
    />
    <span v-else class="node-name">{{ node.name }}</span>

    <div v-if="node.type === 'folder'" class="node-actions">
      <button class="action-btn" type="button" title="新建文件" @click.stop="emit('start-create', node.id, 'file')">
        <svg viewBox="0 0 16 16" width="13" height="13" 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="action-btn" type="button" title="新建文件夹" @click.stop="emit('start-create', node.id, 'folder')">
        <svg viewBox="0 0 16 16" width="13" height="13" 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>

  <div v-if="isCreating" class="tree-node tree-node-new" :style="{ paddingLeft: createPaddingLeft }">
    <span class="chevron-placeholder"></span>
    <span :class="creatingType === 'folder' ? 'icon-folder' : 'icon-file'"></span>
    <input
      class="rename-input"
      :value="creatingName"
      :placeholder="creatingType === 'folder' ? '输入文件夹名称' : '输入文件名，例如 note.md'"
      @input="emit('update:creating-name', $event.target.value)"
      @keydown.enter="emit('finish-create')"
      @keydown.esc="emit('cancel-create')"
      @blur="emit('finish-create')"
    />
  </div>

  <template v-if="node.type === 'folder' && isExpanded">
    <TreeNodeItem
      v-for="child in node.children || []"
      :key="child.id"
      :node="child"
      :level="level + 1"
      :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="emit('start-rename', $event)"
      @finish-rename="emit('finish-rename', $event)"
      @cancel-rename="emit('cancel-rename')"
      @update:rename-value="emit('update:rename-value', $event)"
      @start-create="forwardStartCreate"
      @finish-create="emit('finish-create')"
      @cancel-create="emit('cancel-create')"
      @update:creating-name="emit('update:creating-name', $event)"
      @context-menu="forwardContextMenu"
      @drop="forwardDrop"
      @drag-start="forwardDragStart"
      @drag-over="forwardDragOver"
    />
  </template>
</template>

<style scoped>
.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;
}

.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;
}

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

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

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