<script setup lang="ts">
import { ref, computed, onMounted, onUnmounted } from 'vue'

interface JournalItem {
  id: string
  platform: 'substack' | 'gitea' | 'github' | 'instagram' | 'castopod' | 'blog' | 'linkedin'
  hashtag: string
  date: string
  titre: string
  extrait: string
  url: string
  thumbnail: string | null
}

interface JournalPayload {
  generatedAt: string
  items: JournalItem[]
  counts?: Record<string, number>
}

const items = ref<JournalItem[]>([])
const filters = ref<Record<string, boolean>>({})
const platformFilter = ref<string | null>(null)
const loading = ref(true)
const errored = ref(false)
const empty = ref(false)

const JOURNAL_URL =
  (import.meta as unknown as { env: Record<string, string | undefined> }).env
    .PUBLIC_JOURNAL_URL || 'https://data.trans-former.fr/journal.json'

const STORAGE_KEY = 'tf-hashtag-filters'

const loadFilters = () => {
  try {
    filters.value = JSON.parse(localStorage.getItem(STORAGE_KEY) || '{}')
  } catch {
    filters.value = {}
  }
}

const onFilterChange = (e: Event) => {
  const ce = e as CustomEvent
  if (ce.detail && typeof ce.detail === 'object') {
    filters.value = { ...ce.detail }
  }
}

const onPlatformChange = (e: Event) => {
  const ce = e as CustomEvent
  platformFilter.value = ce.detail?.platform ?? null
}

onMounted(async () => {
  loadFilters()
  window.addEventListener('hashtag-filter-change', onFilterChange as EventListener)
  window.addEventListener('platform-filter-change', onPlatformChange as EventListener)
  try {
    const res = await fetch(JOURNAL_URL, { cache: 'no-store' })
    if (!res.ok) {
      errored.value = true
      return
    }
    const data = (await res.json()) as JournalPayload
    items.value = Array.isArray(data.items) ? data.items : []
    if (items.value.length === 0) empty.value = true
  } catch (e) {
    errored.value = true
    console.error('JournalList fetch failed', e)
  } finally {
    loading.value = false
  }
})

onUnmounted(() => {
  window.removeEventListener('hashtag-filter-change', onFilterChange as EventListener)
  window.removeEventListener('platform-filter-change', onPlatformChange as EventListener)
})

const onItemClick = (item: JournalItem, e: MouseEvent) => {
  if (e.metaKey || e.ctrlKey) {
    window.open(item.url, '_blank', 'noopener')
    return
  }
  e.preventDefault()
  window.dispatchEvent(new CustomEvent('journal-item-click', { detail: { item } }))
}

const visibleItems = computed(() => {
  const keys = Object.keys(filters.value)
  let filtered: JournalItem[]
  if (keys.length === 0) {
    filtered = items.value
  } else {
    const activeKeys = keys.filter((k) => filters.value[k])
    if (activeKeys.length === 0 && keys.some((k) => filters.value[k] === false)) {
      filtered = []
    } else if (activeKeys.length === 0) {
      filtered = items.value
    } else {
      filtered = items.value.filter((it) => activeKeys.includes(it.hashtag))
    }
  }
  if (platformFilter.value) {
    filtered = filtered.filter((it) => it.platform === platformFilter.value)
  }
  return filtered
})

const formatDate = (iso: string) => {
  try {
    const d = new Date(iso)
    if (isNaN(d.getTime())) return ''
    return `${String(d.getDate()).padStart(2, '0')}/${String(d.getMonth() + 1).padStart(2, '0')}`
  } catch {
    return ''
  }
}

const platformLabel = (p: string) => {
  switch (p) {
    case 'gitea':
    case 'github':
      return 'code'
    case 'substack':
      return 'substack'
    case 'instagram':
      return 'insta'
    case 'castopod':
      return 'pod'
    case 'blog':
      return 'blog'
    case 'linkedin':
      return 'linkedin'
    default:
      return p
  }
}
</script>

<template>
  <div class="space-y-3">
    <p v-if="loading" class="text-neutral-400 italic text-xs">
      Chargement du journal...
    </p>
    <p v-else-if="errored" class="text-neutral-400 italic text-xs">
      Journal en cours d'agregation. Reviens dans quelques heures.
    </p>
    <p v-else-if="empty" class="text-neutral-400 italic text-xs">
      Aucun item agrege. Le cron nocturne tourne a 3h.
    </p>
    <p
      v-else-if="!visibleItems.length"
      class="text-neutral-400 italic text-xs"
    >
      Aucun item ; ajuste les filtres.
    </p>
    <article
      v-for="item in visibleItems"
      :key="item.id"
      class="border-b border-neutral-100 pb-3 last:border-b-0"
    >
      <a
        :href="item.url"
        target="_blank"
        rel="noopener noreferrer"
        class="block group"
        @click="onItemClick(item, $event)"
      >
        <div class="flex items-baseline gap-2 text-[11px] text-neutral-500 mb-1">
          <time>{{ formatDate(item.date) }}</time>
          <span class="font-mono text-neutral-700">{{ item.hashtag }}</span>
          <span class="text-neutral-400">{{ platformLabel(item.platform) }}</span>
        </div>
        <h4
          class="text-sm text-neutral-900 group-hover:text-neutral-600 leading-snug"
        >
          {{ item.titre }}
        </h4>
        <p
          v-if="item.extrait"
          class="text-xs text-neutral-500 mt-1 line-clamp-2"
        >
          {{ item.extrait }}
        </p>
        <img
          v-if="item.thumbnail"
          :src="item.thumbnail"
          :alt="item.titre"
          loading="lazy"
          class="mt-2 w-full max-h-32 object-cover rounded"
        />
      </a>
    </article>
  </div>
</template>
