<script setup lang="ts">
import { computed, reactive, watchEffect, onMounted } from 'vue'
import { useColor, useMates, useGun, currentRoom, gunAvatar, user } from '#composables';
import type { Mate } from "../composables"
import ForceGraph from 'force-graph';

import { ref } from 'vue'
import { useResizeObserver } from '@vueuse/core'

export interface Rec {
  source: string
  target: string
  emoji: string
  back: string
}

const graph = ref(null)


//https://github.com/vasturiano/force-graph

const emit = defineEmits(['user'])

const colorDeep = useColor('deep')
const gun = useGun()

const guests: Record<string, {
  pub: string
  name: string
  color: string
  links: Record<string, Mate>
}> = reactive({})

gun
  .user(currentRoom.pub)
  .get("space")
  .map()
  .once(async (d, k) => {
    guests[k] = {
      pub: k,
      name: await gun.user(k).get('profile').get('name').then(),
      color: colorDeep.hex(k),
      links: useMates(k)
    }
  })



const links = computed(() => {
  let arr: Rec[] = []
  Object.values(guests).forEach(node => {
    Object.entries(node.links).forEach(link => {
      if (!guests[link[0]] || !link[1].text) return
      arr.push({
        source: node.pub,
        target: link[0],
        emoji: link[1].emoji,
        back: link[1].back
      })
    })
  })
  return arr
})

const Graph = ForceGraph()
  .width(600)
  .nodeId('pub')
  .nodeColor('color')
  .nodeVal(node => {
    //@ts-expect-error types not extended...
    if (node.pub == user.pub) {
      return 10
    } else {
      return 1 // Object.keys(node.links).length + 1
    }
  })
  .nodeRelSize(4)
  .linkDirectionalArrowLength(4)
  .linkDirectionalArrowRelPos(1)
  .linkLabel('emoji')
  .linkCurvature(0.2)
  .linkColor(link => {
    //@ts-expect-error not extended...
    return colorDeep.hex(link.source?.pub || 0)
  })
  .linkWidth((link: Rec) => {
    if (link.back) return 3
    return 1
  })
  .onNodeDragEnd(node => {
    node.fx = node.x;
    node.fy = node.y;
  }).onNodeClick(node => {
    // Center/zoom on node
    Graph.centerAt(node.x, node.y, 1000);
    Graph.zoom(4, 2000);
  })
  .onNodeClick(node => {
    //@ts-expect-error
    emit('user', node.pub)
  });

onMounted(() => {
  Graph(document.getElementById('graph'))
})

//@ts-expect-error
watchEffect(() => Graph.graphData({ nodes: Object.values(guests), links: links.value }))

useResizeObserver(graph, (entries) => {
  const entry = entries[0]
  const { width, height } = entry.contentRect
  Graph.width(width);
  Graph.height(height)
})

</script>

<template lang="pug">
.bg-light-700.dark-bg-dark-500.overflow-none.w-full.max-w-90vw.max-h-90vh.h-full(ref="graph")
  #graph
</template>