<script setup lang="ts">
import { computed, ref } from 'vue'
import type { FlatTreeNode } from '@/types/partsTree'
import { usePartsTreeStore } from '@/stores/partsTree'
import { getExplodeService } from '@/services/explodeService'
import { useViewerStore } from '@/stores/viewer'
import ColorPicker from './ColorPicker.vue'

const props = defineProps<{
  node: FlatTreeNode
  searchQuery?: string
}>()

const partsTreeStore = usePartsTreeStore()
const viewerStore = useViewerStore()

const isHovered = computed(() => partsTreeStore.hoveredNodeId === props.node.id)
const isExploded = ref(false)

const indentStyle = computed(() => ({
  paddingLeft: `${props.node.depth * 16 + 8}px`
}))

function handleToggleExpand() {
  if (props.node.hasChildren) {
    partsTreeStore.toggleExpanded(props.node.id)
  }
}

function handleToggleVisible(event: Event) {
  event.stopPropagation()
  partsTreeStore.toggleVisible(props.node.id)
}

function handleToggleExplode(event: Event) {
  event.stopPropagation()

  const service = getExplodeService()
  const nodeUuid = props.node.object.uuid

  if (isExploded.value) {
    service.animateResetPart(nodeUuid, 300)
    isExploded.value = false
  } else {
    service.animateExplodePart(nodeUuid, 100, 300)
    isExploded.value = true
  }

  viewerStore.forceRender()
}

function handleMouseEnter() {
  partsTreeStore.highlightNode(props.node.id)
}

function handleMouseLeave() {
  partsTreeStore.highlightNode(null)
}

function handleColorChanged() {
  viewerStore.forceRender()
}

// Highlight matching text in search
function highlightText(text: string, query: string): string {
  if (!query) return text
  const regex = new RegExp(`(${query.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')})`, 'gi')
  return text.replace(regex, '<mark>$1</mark>')
}

const displayName = computed(() => {
  if (props.searchQuery) {
    return highlightText(props.node.name, props.searchQuery)
  }
  return props.node.name
})
</script>

<template>
  <div
    class="tree-node"
    :class="{ 'is-hovered': isHovered, 'is-hidden': !node.visible }"
    :style="indentStyle"
    @mouseenter="handleMouseEnter"
    @mouseleave="handleMouseLeave"
    @click="handleToggleExpand"
  >
    <span class="expand-icon" :class="{ 'has-children': node.hasChildren }">
      <template v-if="node.hasChildren">
        <svg v-if="node.isExpanded" viewBox="0 0 20 20" fill="currentColor">
          <path fill-rule="evenodd" d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z" clip-rule="evenodd" />
        </svg>
        <svg v-else viewBox="0 0 20 20" fill="currentColor">
          <path fill-rule="evenodd" d="M7.293 14.707a1 1 0 010-1.414L10.586 10 7.293 6.707a1 1 0 011.414-1.414l4 4a1 1 0 010 1.414l-4 4a1 1 0 01-1.414 0z" clip-rule="evenodd" />
        </svg>
      </template>
    </span>

    <span class="node-name" :title="node.name" v-html="displayName"></span>

    <span v-if="node.childCount > 0" class="child-count">
      ({{ node.childCount }})
    </span>

    <button
      class="explode-btn"
      :class="{ 'is-exploded': isExploded }"
      :title="isExploded ? '复位' : '爆炸'"
      @click="handleToggleExplode"
    >
      <svg viewBox="0 0 20 20" fill="currentColor">
        <path v-if="!isExploded" d="M10 2a1 1 0 011 1v4.586l2.293-2.293a1 1 0 111.414 1.414L11.414 10l3.293 3.293a1 1 0 01-1.414 1.414L11 12.414V17a1 1 0 11-2 0v-4.586l-2.293 2.293a1 1 0 01-1.414-1.414L8.586 10 5.293 6.707a1 1 0 011.414-1.414L9 7.586V3a1 1 0 011-1z"/>
        <path v-else d="M10 18a8 8 0 100-16 8 8 0 000 16zM8.707 7.293a1 1 0 00-1.414 1.414L8.586 10l-1.293 1.293a1 1 0 101.414 1.414L10 11.414l1.293 1.293a1 1 0 001.414-1.414L11.414 10l1.293-1.293a1 1 0 00-1.414-1.414L10 8.586 8.707 7.293z"/>
      </svg>
    </button>
    <ColorPicker
      :uuid="node.object.uuid"
      @color-changed="handleColorChanged"
    />
    <button
      class="visibility-btn"
      :class="{ 'is-visible': node.visible }"
      :title="node.visible ? '隐藏' : '显示'"
      @click="handleToggleVisible"
    >
      <svg v-if="node.visible" viewBox="0 0 20 20" fill="currentColor">
        <path d="M10 12a2 2 0 100-4 2 2 0 000 4z" />
        <path fill-rule="evenodd" d="M.458 10C1.732 5.943 5.522 3 10 3s8.268 2.943 9.542 7c-1.274 4.057-5.064 7-9.542 7S1.732 14.057.458 10zM14 10a4 4 0 11-8 0 4 4 0 018 0z" clip-rule="evenodd" />
      </svg>
      <svg v-else viewBox="0 0 20 20" fill="currentColor">
        <path fill-rule="evenodd" d="M3.707 2.293a1 1 0 00-1.414 1.414l14 14a1 1 0 001.414-1.414l-1.473-1.473A10.014 10.014 0 0019.542 10C18.268 5.943 14.478 3 10 3a9.958 9.958 0 00-4.512 1.074l-1.78-1.781zm4.261 4.26l1.514 1.515a2.003 2.003 0 012.45 2.45l1.514 1.514a4 4 0 00-5.478-5.478z" clip-rule="evenodd" />
        <path d="M12.454 16.697L9.75 13.992a4 4 0 01-3.742-3.742L2.335 6.578A9.98 9.98 0 00.458 10c1.274 4.057 5.065 7 9.542 7 .847 0 1.669-.105 2.454-.303z" />
      </svg>
    </button>
  </div>
</template>

<style scoped>
.tree-node {
  display: flex;
  align-items: flex-start;
  gap: var(--space-1);
  padding: 6px 10px;
  cursor: pointer;
  border-radius: var(--radius-md);
  user-select: none;
  transition:
    background-color var(--duration-fast) var(--ease-default),
    transform var(--duration-fast) var(--ease-spring);
}

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

.tree-node:active {
  transform: scale(0.995);
}

.tree-node.is-hovered {
  background: var(--primary-subtle);
  box-shadow: inset 0 0 0 1px var(--primary-color);
}

.tree-node.is-hidden {
  opacity: 0.4;
}

.tree-node.is-hidden .node-name {
  text-decoration: line-through;
  text-decoration-color: var(--text-tertiary);
}

.expand-icon {
  width: 18px;
  height: 18px;
  margin-top: 2px;
  flex-shrink: 0;
  display: flex;
  align-items: center;
  justify-content: center;
}

.expand-icon svg {
  width: 14px;
  height: 14px;
  color: var(--text-tertiary);
  transition:
    transform var(--duration-normal) var(--ease-spring),
    color var(--duration-fast) var(--ease-default);
}

.expand-icon.has-children {
  cursor: pointer;
}

.expand-icon.has-children:hover svg {
  color: var(--text-primary);
  transform: scale(1.1);
}

/* Chevron rotation when expanded */
.tree-node .expand-icon.has-children svg {
  transform: rotate(-90deg);
}

.tree-node:has(.expand-icon.has-children) .expand-icon svg {
  transform: rotate(-90deg);
}

.node-name {
  flex: 1;
  min-width: 60px;
  font-size: 0.8125rem;
  font-weight: 450;
  line-height: 1.4;
  /* 多行截断 - 最多显示2行 */
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
  word-break: break-word;
  transition: color var(--duration-fast) var(--ease-default);
}

.tree-node:hover .node-name {
  color: var(--text-primary);
}

.node-name :deep(mark) {
  background: var(--warning-subtle);
  color: var(--warning-color);
  padding: 1px 4px;
  border-radius: var(--radius-xs);
  font-weight: 600;
}

.child-count {
  font-size: 0.6875rem;
  font-family: var(--font-mono);
  color: var(--text-tertiary);
  padding: 1px 5px;
  background: var(--bg-tertiary);
  border-radius: var(--radius-sm);
  margin-left: var(--space-1);
}

/* Action buttons base */
.visibility-btn,
.explode-btn {
  width: 22px;
  height: 22px;
  padding: 3px;
  background: transparent;
  border: none;
  border-radius: var(--radius-sm);
  cursor: pointer;
  opacity: 0;
  flex-shrink: 0;
  transition:
    opacity var(--duration-fast) var(--ease-default),
    background-color var(--duration-fast) var(--ease-default),
    transform var(--duration-fast) var(--ease-spring);
}

.tree-node:hover .visibility-btn,
.tree-node:hover .explode-btn {
  opacity: 1;
}

.visibility-btn:hover,
.explode-btn:hover {
  background: var(--bg-sunken);
  transform: scale(1.1);
}

.visibility-btn:active,
.explode-btn:active {
  transform: scale(0.95);
}

.visibility-btn svg,
.explode-btn svg {
  width: 16px;
  height: 16px;
  color: var(--text-tertiary);
  transition: color var(--duration-fast) var(--ease-default);
}

.visibility-btn:hover svg {
  color: var(--primary-color);
}

.visibility-btn.is-visible svg {
  color: var(--primary-color);
}

.explode-btn:hover svg {
  color: var(--warning-color);
}

.explode-btn.is-exploded {
  opacity: 1;
}

.explode-btn.is-exploded svg {
  color: var(--warning-color);
  animation: explode-pulse 0.5s ease-out;
}

@keyframes explode-pulse {
  0% { transform: scale(1); }
  50% { transform: scale(1.3); }
  100% { transform: scale(1); }
}
</style>
