<template>
  <ul class="tree-list">
    <li v-for="node in flatNodes" :key="node.id" :style="{ paddingLeft: `${node.depth * 12}px` }">
      <button
        v-if="node.hasChildren"
        class="card"
        type="button"
        style="margin-right: 6px;"
        @click="toggle(node.id)"
      >
        {{ isCollapsed(node.id) ? '+' : '-' }}
      </button>
      <span>{{ node.nom }}</span>
    </li>
  </ul>
</template>

<script setup lang="ts">
type TreeItem = {
  id: string
  nom: string
  parent_id?: string | null
}

type FlatNode = TreeItem & {
  depth: number
  hasChildren: boolean
}

const props = defineProps<{ items: TreeItem[] }>()

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

const childrenMap = computed(() => {
  const map = new Map<string | null, TreeItem[]>()
  props.items.forEach((item) => {
    const key = item.parent_id || null
    const list = map.get(key) || []
    list.push(item)
    map.set(key, list)
  })
  return map
})

const hasChildren = (id: string) => {
  const list = childrenMap.value.get(id)
  return !!(list && list.length)
}

const buildFlat = (parentId: string | null, depth: number, acc: FlatNode[]) => {
  const children = childrenMap.value.get(parentId) || []
  children
    .slice()
    .sort((a, b) => a.nom.localeCompare(b.nom))
    .forEach((child) => {
      acc.push({
        ...child,
        depth,
        hasChildren: hasChildren(child.id)
      })
      if (!collapsed.value.has(child.id)) {
        buildFlat(child.id, depth + 1, acc)
      }
    })
}

const flatNodes = computed(() => {
  const acc: FlatNode[] = []
  buildFlat(null, 0, acc)
  return acc
})

const toggle = (id: string) => {
  const next = new Set(collapsed.value)
  if (next.has(id)) {
    next.delete(id)
  } else {
    next.add(id)
  }
  collapsed.value = next
}

const isCollapsed = (id: string) => collapsed.value.has(id)
</script>

<style scoped>
.tree-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: 6px;
}
</style>
