<script setup lang="ts">
import { computed, ref, watch } from 'vue'

interface StatusFile {
  path: string
  status: string
}

interface StatusNode {
  name: string
  path: string
  type: 'file' | 'directory'
  status?: string
  children?: StatusNode[]
  fileCount?: number
}

const props = defineProps<{
  files?: StatusFile[]
  nodes?: StatusNode[]
  selectedPath?: string | null
  depth?: number
}>()

const emit = defineEmits<{
  select: [path: string]
}>()

const expandedDirs = ref<Set<string>>(new Set())

function countFiles(nodes: StatusNode[]): number {
  let count = 0
  for (const n of nodes) {
    if (n.type === 'file') count++
    else if (n.children) count += countFiles(n.children)
  }
  return count
}

function buildTree(files: StatusFile[]): StatusNode[] {
  const root: Record<string, any> = {}

  for (const file of files) {
    const parts = file.path.split('/')
    let current = root

    for (let i = 0; i < parts.length; i++) {
      const part = parts[i]
      if (i === parts.length - 1) {
        current[part] = { __file: true, status: file.status, path: file.path }
      } else {
        if (!current[part] || current[part].__file) {
          current[part] = {}
        }
        current = current[part]
      }
    }
  }

  function toNodes(obj: Record<string, any>, parentPath: string): StatusNode[] {
    const dirs: StatusNode[] = []
    const fileNodes: StatusNode[] = []

    for (const [name, value] of Object.entries(obj)) {
      if (value.__file) {
        fileNodes.push({
          name,
          path: value.path,
          type: 'file',
          status: value.status
        })
      } else {
        const dirPath = parentPath ? `${parentPath}/${name}` : name
        const children = toNodes(value, dirPath)
        const fileCount = countFiles(children)
        dirs.push({
          name,
          path: dirPath,
          type: 'directory',
          children,
          fileCount
        })
      }
    }

    // Compact single-child directories
    for (let i = 0; i < dirs.length; i++) {
      const dir = dirs[i]
      while (
        dir.children &&
        dir.children.length === 1 &&
        dir.children[0].type === 'directory'
      ) {
        const child = dir.children[0]
        dir.name = `${dir.name}/${child.name}`
        dir.path = child.path
        dir.children = child.children
        dir.fileCount = child.fileCount
      }
    }

    return [...dirs, ...fileNodes]
  }

  return toNodes(root, '')
}

// Build tree from files prop (top-level), or use nodes prop (recursive)
const displayNodes = computed(() => {
  if (props.nodes) return props.nodes
  if (props.files) return buildTree(props.files)
  return []
})

// Auto-expand all dirs when files change (top-level only)
watch(() => props.files, (files) => {
  if (!files || props.depth) return
  expandedDirs.value = new Set()
  expandAllNodes(displayNodes.value)
}, { immediate: true })

function expandAllNodes(nodes: StatusNode[]) {
  for (const node of nodes) {
    if (node.type === 'directory') {
      expandedDirs.value.add(node.path)
      if (node.children) expandAllNodes(node.children)
    }
  }
}

function toggleDir(path: string) {
  if (expandedDirs.value.has(path)) {
    expandedDirs.value.delete(path)
  } else {
    expandedDirs.value.add(path)
  }
  expandedDirs.value = new Set(expandedDirs.value)
}

function isExpanded(path: string): boolean {
  return expandedDirs.value.has(path)
}

function handleClick(node: StatusNode) {
  if (node.type === 'directory') {
    toggleDir(node.path)
  } else {
    emit('select', node.path)
  }
}

function getFileIcon(name: string): string {
  const ext = name.split('.').pop()?.toLowerCase() || ''
  const icons: Record<string, string> = {
    ts: 'ts', tsx: 'tsx', js: 'js', jsx: 'jsx',
    vue: 'vue', json: 'json', md: 'md',
    css: 'css', scss: 'scss', html: 'html',
    svg: 'svg', png: 'img', jpg: 'img', jpeg: 'img',
    gif: 'img', ico: 'img', gitignore: 'git',
    env: 'env', yml: 'yml', yaml: 'yml',
    toml: 'toml', lock: 'lock'
  }
  return icons[ext] || 'file'
}

function badgeLabel(status: string): string {
  if (status === 'untracked') return '?'
  return (status[0] || '?').toUpperCase()
}
</script>

<template>
  <div class="status-tree">
    <div v-for="node in displayNodes" :key="node.path" class="tree-node">
      <!-- Directory row -->
      <div
        v-if="node.type === 'directory'"
        class="node-row dir-row"
        @click="handleClick(node)"
      >
        <span class="expand-icon">
          <svg
            :class="{ expanded: isExpanded(node.path) }"
            width="12" height="12" viewBox="0 0 24 24" fill="currentColor"
          >
            <path d="M8 5l8 7-8 7z" />
          </svg>
        </span>
        <span class="folder-icon">
          <svg width="14" height="14" viewBox="0 0 24 24" fill="currentColor">
            <path v-if="isExpanded(node.path)" d="M19 20H5a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2h6l2 2h6a2 2 0 0 1 2 2v10a2 2 0 0 1-2 2z" />
            <path v-else d="M3 6a2 2 0 0 1 2-2h6l2 2h6a2 2 0 0 1 2 2v10a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V6z" />
          </svg>
        </span>
        <span class="node-name">{{ node.name }}</span>
        <span class="dir-count">{{ node.fileCount }}</span>
      </div>

      <!-- File row -->
      <div
        v-else
        :class="['node-row', 'file-row', { selected: selectedPath === node.path }]"
        @click="handleClick(node)"
      >
        <span class="expand-icon spacer"></span>
        <span :class="['status-badge', node.status]">{{ badgeLabel(node.status || '') }}</span>
        <span :class="['file-icon', getFileIcon(node.name)]">
          <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
            <path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z" />
            <polyline points="14 2 14 8 20 8" />
          </svg>
        </span>
        <span class="node-name">{{ node.name }}</span>
      </div>

      <!-- Recursive children -->
      <div v-if="node.type === 'directory' && isExpanded(node.path) && node.children" class="children">
        <StatusTree
          :nodes="node.children"
          :selected-path="selectedPath"
          :depth="(depth || 0) + 1"
          @select="emit('select', $event)"
        />
      </div>
    </div>
  </div>
</template>

<style scoped>
.status-tree {
  font-size: 13px;
  user-select: none;
}

.node-row {
  display: flex;
  align-items: center;
  gap: 0.25rem;
  padding: 0.3rem 0.5rem;
  cursor: pointer;
  border-radius: 4px;
  transition: background 0.15s;
}

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

.node-row.selected {
  background: rgba(99, 102, 241, 0.15);
}

.expand-icon {
  width: 16px;
  height: 16px;
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  color: var(--text-muted);
}

.expand-icon.spacer {
  visibility: hidden;
}

.expand-icon svg {
  transition: transform 0.15s;
}

.expand-icon svg.expanded {
  transform: rotate(90deg);
}

.folder-icon {
  width: 16px;
  height: 16px;
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  color: #f59e0b;
}

.file-icon {
  width: 16px;
  height: 16px;
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  color: var(--text-muted);
}

.file-icon.ts, .file-icon.tsx { color: #3178c6; }
.file-icon.js, .file-icon.jsx { color: #f7df1e; }
.file-icon.vue { color: #42b883; }
.file-icon.json { color: #f5a623; }
.file-icon.md { color: #519aba; }
.file-icon.css, .file-icon.scss { color: #563d7c; }
.file-icon.html { color: #e34c26; }
.file-icon.svg, .file-icon.img { color: #a855f7; }
.file-icon.git { color: #f05032; }
.file-icon.env { color: #ecd53f; }
.file-icon.yml { color: #cb171e; }
.file-icon.lock { color: #6b7280; }

.node-name {
  color: var(--text-primary);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.dir-count {
  margin-left: auto;
  background: var(--bg-hover);
  color: var(--text-muted);
  padding: 0.05rem 0.35rem;
  border-radius: 8px;
  font-size: 11px;
  flex-shrink: 0;
}

.status-badge {
  width: 18px;
  height: 18px;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 3px;
  font-size: 11px;
  font-weight: 600;
  flex-shrink: 0;
}

.status-badge.added {
  background: rgba(34, 197, 94, 0.2);
  color: #22c55e;
}

.status-badge.modified {
  background: rgba(234, 179, 8, 0.2);
  color: #eab308;
}

.status-badge.deleted {
  background: rgba(239, 68, 68, 0.2);
  color: #ef4444;
}

.status-badge.renamed {
  background: rgba(168, 85, 247, 0.2);
  color: #a855f7;
}

.status-badge.untracked {
  background: rgba(107, 114, 128, 0.2);
  color: #6b7280;
}

.children {
  padding-left: 1rem;
}
</style>
