<template>
  <div
    class="glow-dot"
    :class="{
      'glow-dot--ghost': isGhost,
      'glow-dot--selected': selected,
      'glow-dot--dimmed': isDimmed,
      'glow-dot--label-above': labelAbove
    }"
    :style="dotStyle"
    @click.stop="onSelect"
  >
    <div class="glow-dot__inner" :style="{ boxShadow: glowShadow }">
      <img
        v-if="imageSrc"
        :src="imageSrc"
        class="glow-dot__image"
        alt=""
      />
    </div>
    <div v-if="!isGhost && event.title" class="glow-dot__label" :style="labelStyle">
      <span class="glow-dot__title" :style="titleStyle">{{ event.title }}</span>
      <span class="glow-dot__date" :style="dateStyle">{{ formattedDate }}</span>
    </div>
  </div>
</template>

<script setup>
import { computed } from 'vue'
import { useEventsStore } from 'stores/events'
import { useSettingsStore } from 'stores/settings'
import { useImageCache } from 'composables/useImageCache'

const props = defineProps({
  event: { type: Object, required: true },
  x: { type: Number, default: 0 },
  isGhost: { type: Boolean, default: false },
  selected: { type: Boolean, default: false }
})

const emit = defineEmits(['select'])
const eventsStore = useEventsStore()
const settingsStore = useSettingsStore()

// Resolve image: cached thumbnail from IndexedDB or fetch & cache
const { resolvedSrc: imageSrc } = props.event.image
  ? useImageCache(props.event.image, props.event.id)
  : { resolvedSrc: computed(() => null) }

const fl = computed(() => settingsStore.floatingLines)
const glowColor = computed(() => eventsStore.getGlowColor(props.event))

// CSS diameter derived from settings (circleRadius is half-size in px)
const dpr = Math.min(window.devicePixelRatio || 1, 2)
const dotSize = computed(() => 2 * fl.value.circleRadius / dpr)

// Y position: emotion +1 → top (20%), 0 → middle (47%), -1 → bottom (74%)

const yPercent = computed(() => 48 - props.event.emotion * 30)

// Label above dot when dot is in lower half, below when in upper half
const labelAbove = computed(() => yPercent.value > 48)

// Format date as "12. Feb 2024"
const MONTH_SHORT = ['Jan', 'Feb', 'Mär', 'Apr', 'Mai', 'Jun', 'Jul', 'Aug', 'Sep', 'Okt', 'Nov', 'Dez']
const formattedDate = computed(() => {
  const d = new Date(props.event.date)
  return `${d.getDate()}. ${MONTH_SHORT[d.getMonth()]} ${d.getFullYear()}`
})

// Label font sizes per setting
const LABEL_FONT = { small: { title: 10, date: 9 }, medium: { title: 12, date: 11 }, large: { title: 14, date: 13 } }
const labelFont = computed(() => LABEL_FONT[fl.value.labelSize] ?? LABEL_FONT.small)
const labelColor = computed(() => fl.value.labelColor ?? '#ffffff')

const labelStyle = computed(() => ({
  maxWidth: labelFont.value.title >= 14 ? '120px' : '90px'
}))
const titleStyle = computed(() => ({
  fontSize: `${labelFont.value.title}px`,
  color: labelColor.value,
  maxWidth: labelFont.value.title >= 14 ? '120px' : '90px'
}))
const dateStyle = computed(() => ({
  fontSize: `${labelFont.value.date}px`,
  color: labelColor.value
}))

const dotStyle = computed(() => ({
  left: `${props.x}px`,
  top: `${yPercent.value}%`,
  width: `${dotSize.value}px`,
  height: `${dotSize.value}px`
}))

// Two-layer box-shadow: tight bright core + wide soft halo
const glowShadow = computed(() => {
  const size = fl.value.glowSize
  const strength = fl.value.glowStrength
  const color = glowColor.value
  const core = alphaHex(Math.min(strength / 3, 1))
  const halo = alphaHex(Math.min(strength / 7, 1))
  return `0 0 ${size}px 0px ${color}${core}, 0 0 ${size * 2.5}px ${size * 0.3}px ${color}${halo}`
})

function alphaHex(a) {
  return Math.round(Math.min(1, Math.max(0, a)) * 255).toString(16).padStart(2, '0')
}

const isDimmed = computed(() =>
  eventsStore.selectedEventId !== null && !props.selected && !props.isGhost
)

function onSelect() {
  if (!props.isGhost) emit('select')
}
</script>

<style scoped>
.glow-dot {
  position: absolute;
  transform: translate(-50%, -50%);
  cursor: pointer;
  z-index: 10;
  transition: opacity 0.3s ease, transform 0.15s ease;
}

.glow-dot__inner {
  position: relative;
  width: 100%;
  height: 100%;
  border-radius: 50%;
  background: #fff;
}

.glow-dot__image {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
  border-radius: 50%;
}

/* States */
.glow-dot--ghost {
  opacity: 1;
  cursor: default;
}



.glow-dot--selected {
  transform: translate(-50%, -50%) scale(1.15);
  z-index: 15;
}

.glow-dot--dimmed {
  opacity: 1;
}

/* Event label (title + date) */
.glow-dot__label {
  position: absolute;
  left: 50%;
  transform: translateX(-50%);
  top: calc(100% + 6px);
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 1px;
  max-width: 90px;
  pointer-events: none;
}

/* When dot is in lower half, show label above */
.glow-dot--label-above .glow-dot__label {
  top: auto;
  bottom: calc(100% + 6px);
}

.glow-dot__title {
  font-size: 10px;
  font-weight: 600;
  opacity: 0.7;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  max-width: 90px;
  text-align: center;
  line-height: 1.2;
}

.glow-dot__date {
  font-size: 9px;
  font-weight: 400;
  opacity: 0.4;
  white-space: nowrap;
  line-height: 1.2;
}
</style>
