<script setup>
  import mqtt from 'mqtt'
import { ref, watch, onMounted, onUnmounted } from 'vue'
  import { inject } from 'vue'

  const mqttRef = inject('mqtt')

  const props = defineProps({
    deviceId: String,
  })

  const nodes = ref([])
  const filters = ref({})
  const filterMode = ref({ label: 'Lenient', value: 'lenient' })

  const changedKeys = ref({})
  let propertyTree = {}

  function buildNodes(obj, path = '') {
    return Object.entries(obj).map(([key, val]) => {
      const fullKey = path ? `${path}/${key}` : key

      const hasChildren = Object.keys(val).some((k) => k !== 'value' && k !== '_value')

      return {
        key: fullKey,
        data: {
          name: key,
          value: val.value ?? val._value,
        },
        children: hasChildren
          ? buildNodes(
              Object.fromEntries(
                Object.entries(val).filter(([k]) => k !== 'value' && k !== '_value'),
              ),
              fullKey,
            )
          : undefined,
      }
    })
  }

  function insertProperty(pathParts, value) {
    let node = propertyTree
    const fullKey = pathParts.join('/')

    pathParts.forEach((part, i) => {
      const isLeaf = i === pathParts.length - 1

      if (!node[part]) {
        node[part] = {}
      }

      // If this node used to be a leaf, convert it into a branch
      if (node[part].value !== undefined && !isLeaf) {
        node[part] = { _value: node[part].value }
      }

      if (isLeaf) {
        node[part].value = value
      } else {
        node = node[part]
      }
    })

    // flash logic
    changedKeys.value[fullKey] = true
    setTimeout(() => {
      delete changedKeys.value[fullKey]
    }, 600)

    nodes.value = buildNodes(propertyTree)
  }

  watch(
    () => props.deviceId,
    () => {
      propertyTree = {}
      nodes.value = []
    },
  )

  onMounted(() => {
    mqttRef.value.subscribe(`device/${props.deviceId}/property/#`, (payload, topic) => {
      const parts = topic.split('/')

      const device = parts[1]
      const propertyPath = parts.slice(3)

      if (device !== props.deviceId) return

      insertProperty(propertyPath, payload)
    })
  })

  onUnmounted(() => {
    mqttRef.value.unsubscribe(`device/${props.deviceId}/property/#`)
  })
</script>

<template>
  <div class="layout-card col-item-2">
    <TreeTable :value="nodes" :filters="filters" :filterMode="filterMode.value">
      <template #header>
        <div class="flex products-header">
          <span class="products-title">Properties</span>
          <IconField class="search-field">
            <InputIcon class="pi pi-search" />
            <InputText v-model="filters['global']" placeholder="Filter by..." />
          </IconField>
        </div>
      </template>
      <template #empty> No properties available.</template>
      <Column field="name" header="Name" expander style="min-width: 12rem">
        <!-- <template #filter>
          <InputText v-model="filters['name']" type="text" placeholder="Filter by name" />
        </template> -->
      </Column>
      <Column field="value" header="Value" style="min-width: 12rem">
        <!-- <template #filter>
          <InputText v-model="filters['value']" type="text" placeholder="Filter by value" />
        </template> -->
        <template #body="{ node }">
          <span :class="{ 'flash-cell': changedKeys[node.key] }">
            {{ node.data.value }}
          </span>
        </template>
      </Column>
    </TreeTable>
  </div>
</template>

<style scoped>
  .flash-cell {
    animation: flash-bg 0.6s ease;
    border-radius: 6px;
  }

  @keyframes flash-bg {
    0% {
      background-color: var(--p-primary-color);
      color: var(--p-primary-color-text);
    }
    100% {
      background-color: transparent;
      color: inherit;
    }
  }
</style>
