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

import { useFormatters } from '@/composables/useFormatters'
import { ROW_HEIGHT, AXIS_HEIGHT, type TimelineItem } from '@/types/timeline'
import type { TimelineNodeHoverPayload } from '@/types/traceTooltip'

const props = defineProps<{
  item: TimelineItem
  index: number
  timeScale: any
  zoomedWidth: number
  isSelected: boolean
  isDimmed: boolean
  isCollapsed: boolean
}>()

const emit = defineEmits<{
  (e: 'toggle-collapse', id: string): void
  (e: 'select-node', id: string): void
  (e: 'hover-node', payload: TimelineNodeHoverPayload): void
  (e: 'leave-node'): void
}>()

const { formatMillis } = useFormatters()

function resolveStart(item: TimelineItem): Date | undefined {
  return item.start ?? item.timestamp ?? item.end
}

function resolveEnd(item: TimelineItem): Date | undefined {
  return item.end ?? item.start ?? item.timestamp
}

const resolvedStart = computed(() => resolveStart(props.item))
const resolvedEnd = computed(() => resolveEnd(props.item))
const hasResolvedRange = computed(() => Boolean(resolvedStart.value && resolvedEnd.value))
const isInstant = computed(() =>
  hasResolvedRange.value ? resolvedEnd.value!.getTime() === resolvedStart.value!.getTime() : false,
)
const startCoord = computed(() => (hasResolvedRange.value ? props.timeScale(resolvedStart.value!) : 0))
const endCoord = computed(() => (hasResolvedRange.value ? props.timeScale(resolvedEnd.value!) : 0))

/**
 * Calculates and formats the duration of an item.
 */
function getDuration(item: TimelineItem) {
  const start = resolveStart(item)
  const end = resolveEnd(item)
  if (!start || !end) return ''
  const diff = end.getTime() - start.getTime()
  if (diff < 1) return ''
  return formatMillis(diff)
}
</script>

<template>
  <g
    v-if="hasResolvedRange"
    class="group/row"
    :transform="`translate(0, ${index * ROW_HEIGHT + AXIS_HEIGHT + 5})`"
    @click="emit('select-node', item.id)"
    @mousemove="emit('hover-node', { item, clientX: $event.clientX, clientY: $event.clientY })"
    @mouseleave="emit('leave-node')"
  >
    <!-- Row Hover Background -->
    <rect
      x="0"
      y="0"
      :width="zoomedWidth"
      :height="ROW_HEIGHT"
      fill="transparent"
      class="group-hover/row:fill-primary/10 transition-colors cursor-pointer"
      :class="isSelected ? 'fill-primary/20' : ''"
    />

    <!-- Duration Bar (or Point) -->
    <circle
      v-if="isInstant"
      :cx="startCoord"
      cy="16"
      r="2"
      :fill="item.color"
      :fill-opacity="isSelected ? 0.75 : 0.5"
      :stroke="item.color"
      stroke-width="2"
      class="transition-opacity duration-300"
      :class="{ 'opacity-100': !isDimmed, 'opacity-40': isDimmed }"
    />
    <rect
      v-else
      :x="startCoord"
      y="4"
      :width="Math.max(endCoord - startCoord, 2)"
      height="24"
      rx="4"
      :fill="item.color"
      :fill-opacity="isSelected ? 0.75 : 0.25"
      :stroke="item.color"
      stroke-width="1"
      class="transition-opacity duration-300"
    />

    <!-- Label and Duration Text (foreignObject for HTML text styling) -->
    <foreignObject
      :x="
        startCoord > zoomedWidth * 0.8
          ? startCoord - 300
          : startCoord
      "
      y="4"
      :width="
        startCoord > zoomedWidth * 0.8
          ? 290
          : Math.max(zoomedWidth - startCoord, 0)
      "
      height="24"
      class="pointer-events-none"
    >
      <div
        class="h-full flex items-center px-2 gap-1.5 text-xs text-white overflow-hidden"
        :class="startCoord > zoomedWidth * 0.8 ? 'justify-end flex-row-reverse' : ''"
      >
        <!-- Collapse/Expand Toggle -->
        <button
          v-if="item.hasChildren"
          class="pointer-events-auto hover:bg-black/20 rounded p-0.5 transition-colors cursor-pointer"
          @click.stop="emit('toggle-collapse', item.id)"
        >
          <i
            class="dku-icon-chevron-right-12 text-black/70 dark:text-white/70 transition-transform duration-200"
            :class="{ 'rotate-90': !isCollapsed }"
          />
        </button>

        <!-- Icon -->
        <i
          :class="[`${item.icon}-16`, 'flex-none opacity-90 text-black/90 dark:text-white/80']"
          :style="{ color: isSelected ? '' : item.color }"
        />

        <span class="text-black/90 dark:text-white/90 truncate">
          {{ item.label }}
        </span>
        <span class="text-black/80 dark:text-white/80 text-[10px] line-clamp-1 font-mono">
          {{ getDuration(item) }}
        </span>
      </div>
    </foreignObject>
  </g>
</template>
