<script setup lang="ts">
export interface CategoryNode {
  id: string
  name: string
  image?: string
  count?: number
  defaultCardType?: string | null
  children?: CategoryNode[]
}

const props = defineProps<{
  node: CategoryNode
  activeId?: string
  level?: number
  expandedIds: Set<string>
}>()

const emit = defineEmits<{
  select: [id: string]
  contextmenu: [node: CategoryNode, event: MouseEvent]
  toggleExpand: [id: string]
  dropCard: [categoryId: string | null, categoryName: string]
}>()

defineOptions({ name: 'IndexCategoryTreeNode' })

const level = computed(() => props.level ?? 0)
const hasChildren = computed(() => !!props.node.children && props.node.children.length > 0)
const isExpanded = computed(() => props.expandedIds.has(props.node.id))
const isActive = computed(() => props.activeId === props.node.id)
const dragOver = ref(false)

const imgLoaded = ref(false)
const imgFailed = ref(false)

function onClick() {
  emit('select', props.node.id)
}

function onDragOver(e: DragEvent) {
  if (!e.dataTransfer?.types.includes('application/x-card-id')) return
  e.preventDefault()
  e.dataTransfer.dropEffect = 'move'
  dragOver.value = true
}

function onDragLeave() {
  dragOver.value = false
}

function onDrop(e: DragEvent) {
  dragOver.value = false
  if (!e.dataTransfer?.types.includes('application/x-card-id')) return
  emit('dropCard', props.node.id === '__uncategorized__' ? null : props.node.id, props.node.name)
}

function onContextMenu(event: MouseEvent) {
  event.preventDefault()
  event.stopPropagation()
  emit('contextmenu', props.node, event)
}
</script>

<template>
  <div class="tree-node">
    <div
      class="tree-row"
      :class="{ active: isActive, 'drag-over': dragOver }"
      :style="{ paddingLeft: `${10 + level * 14}px` }"
      @click="onClick"
      @contextmenu="onContextMenu"
      @dragover="onDragOver"
      @dragleave="onDragLeave"
      @drop="onDrop"
    >
      <button
        v-if="hasChildren"
        class="tree-chevron"
        :class="{ expanded: isExpanded }"
        @click.stop="emit('toggleExpand', node.id)"
      >
        <Icon name="lucide:chevron-right" />
      </button>
      <span v-else class="tree-chevron-spacer" />

      <div class="tree-thumb">
        <img
          v-if="node.image && !imgFailed"
          :src="node.image"
          :alt="node.name"
          loading="lazy"
          :class="{ loaded: imgLoaded }"
          @load="imgLoaded = true"
          @error="imgFailed = true"
        >
        <span v-else class="tree-thumb-fallback">
          <Icon name="lucide:folder" />
        </span>
      </div>

      <span class="tree-name">{{ node.name }}</span>
      <span v-if="typeof node.count === 'number'" class="tree-count">{{ node.count }}</span>
    </div>

    <div v-if="hasChildren && isExpanded" class="tree-children">
      <IndexCategoryTreeNode
        v-for="child in node.children"
        :key="child.id"
        :node="child"
        :active-id="activeId"
        :level="level + 1"
        :expanded-ids="expandedIds"
        @select="(id) => emit('select', id)"
        @contextmenu="(n, e) => emit('contextmenu', n, e)"
        @toggle-expand="(id) => emit('toggleExpand', id)"
        @drop-card="(catId, catName) => emit('dropCard', catId, catName)"
      />
    </div>
  </div>
</template>

<style scoped>
.tree-node {
  display: flex;
  flex-direction: column;
}

.tree-row {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 6px 8px 6px 10px;
  border-radius: 8px;
  cursor: pointer;
  user-select: none;
  transition: background 0.12s ease;
  margin-right: 6px;
}

.tree-row:hover {
  background: var(--color-surface-soft);
}

.tree-row.active {
  background: var(--color-surface-card);
}

.tree-row.drag-over {
  background: rgba(204, 120, 92, 0.12);
  outline: 2px dashed var(--color-primary);
  outline-offset: -2px;
}

.tree-row.active .tree-name {
  color: var(--color-ink);
}

.tree-chevron {
  width: 22px;
  height: 22px;
  display: flex;
  align-items: center;
  justify-content: center;
  background: none;
  border: none;
  cursor: pointer;
  color: var(--color-muted-soft);
  padding: 0;
  flex-shrink: 0;
  border-radius: 5px;
  transition: transform 0.18s ease, color 0.12s ease, background 0.12s ease;
}

.tree-chevron :deep(svg) {
  width: 14px;
  height: 14px;
}

.tree-chevron:hover {
  color: var(--color-ink);
  background: var(--color-surface-card);
}

.tree-chevron.expanded {
  transform: rotate(90deg);
}

.tree-chevron-spacer {
  width: 22px;
  height: 22px;
  flex-shrink: 0;
}

.tree-thumb {
  position: relative;
  width: 22px;
  height: 22px;
  border-radius: 5px;
  overflow: hidden;
  background: var(--color-surface-card);
  flex-shrink: 0;
  display: flex;
  align-items: center;
  justify-content: center;
}

.tree-thumb img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  opacity: 0;
  transition: opacity 0.3s ease;
}

.tree-thumb img.loaded {
  opacity: 1;
}

.tree-thumb-fallback {
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--color-muted-soft);
}

.tree-thumb-fallback :deep(svg) {
  width: 14px;
  height: 14px;
}

.tree-name {
  flex: 1;
  font-family: var(--font-body);
  font-size: 13px;
  font-weight: 500;
  color: var(--color-body);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.tree-row:hover .tree-name {
  color: var(--color-ink);
}

.tree-count {
  font-family: var(--font-body);
  font-size: 11px;
  font-weight: 500;
  color: var(--color-muted-soft);
  background: transparent;
  padding: 0 4px;
  flex-shrink: 0;
}

.tree-row.active .tree-count {
  color: var(--color-primary);
}

.tree-children {
  display: flex;
  flex-direction: column;
}
</style>
