<script setup lang="ts">
import { computed, ref, watch } from 'vue'
import { storeToRefs } from 'pinia'
import { breakpointsTailwind } from '@vueuse/core'
import type { DropdownMenuItem } from '@nuxt/ui'
import type { SearchHit } from '~/types'
import { useHistoryStore, type HistoryItem, HISTORY_LIMIT } from '~/stores/history'
import PublicationDetail from '~/components/PublicationDetail.vue'
import EntrelineaDetail from '~/components/entrelineas/EntrelineaDetail.vue'

/**
 * Pantalla de historial — gemela de `pages/favoritos.vue`.
 *
 * Por qué prácticamente idéntica a Mi lista: el usuario espera la misma
 * ergonomía (lista a la izquierda, panel de detalle a la derecha, búsqueda
 * arriba, mismas acciones de export/import). Si las dos pantallas divergen
 * en patrones, la curva de aprendizaje se duplica sin razón.
 *
 * Diferencias respecto a Mi lista:
 *  - El store es `useHistoryStore` y los items tienen `visitedAt` (no `addedAt`).
 *  - Cada fila muestra "Visto: <fecha>" para que se entienda que el orden
 *    de la lista es por última visita, no por fecha de creación.
 *  - El registro lo hace el detalle al abrirse (`PublicationDetail.vue` y
 *    `EntrelineaDetail.vue` — ambos llaman a `history.visit(...)`).
 */

const history = useHistoryStore()
const { items: histItems, total: histTotal, collections: histCollections } = storeToRefs(history)
const toast = useToast()

const ENTRELINEAS_COLLECTION = 'entrelineas'

const COLLECTION_LABELS: Record<string, string> = {
  activities: 'Actividades',
  conferences: 'Conferencias',
  entrelineas: 'Entre Líneas'
}

function labelFor(c: string): string {
  return COLLECTION_LABELS[c] || c.charAt(0).toUpperCase() + c.slice(1)
}

// Filtros: pestaña por colección o "todos".
const activeCollection = ref<string>('all')

// Reset del filtro si la colección activa se queda sin elementos.
watch(histCollections, (cols) => {
  if (activeCollection.value !== 'all' && !cols.includes(activeCollection.value)) {
    activeCollection.value = 'all'
  }
})

const tabs = computed(() => {
  const items = [{ value: 'all', label: `Todos (${histTotal.value})`, icon: 'i-lucide-history' }]
  for (const c of histCollections.value) {
    const count = histItems.value.filter(it => it.collection === c).length
    items.push({
      value: c,
      label: `${labelFor(c)} (${count})`,
      icon: c === 'activities'
        ? 'i-lucide-calendar-days'
        : c === 'conferences'
          ? 'i-lucide-mic'
          : c === 'entrelineas'
            ? 'i-lucide-book-open'
            : 'i-lucide-folder'
    })
  }
  return items
})

const localQuery = ref('')

const filteredItems = computed<HistoryItem[]>(() => {
  let list = histItems.value
  if (activeCollection.value !== 'all') {
    list = list.filter(it => it.collection === activeCollection.value)
  }
  const q = localQuery.value.trim().toLowerCase()
  if (q) {
    list = list.filter((it) => {
      const t = (it.hit?.title || '').toLowerCase()
      return t.includes(q)
    })
  }
  return list
})

// ---- Selección y panel de detalle --------------------------------------

const selected = ref<HistoryItem | null>(null)

const selectedHit = computed<SearchHit | null>(() => selected.value?.hit ?? null)
const selectedCollection = computed<string | undefined>(() => selected.value?.collection)

const isEntrelinea = computed(() => selectedCollection.value === ENTRELINEAS_COLLECTION)

/** El SearchHit guardado de una entrelínea conserva todos los campos del
 *  documento original. Lo casteamos a un objeto plano para EntrelineaDetail. */
const selectedEntrelineaDoc = computed<Record<string, unknown> | null>(() => {
  if (!isEntrelinea.value || !selectedHit.value) return null
  return selectedHit.value as unknown as Record<string, unknown>
})

const isPanelOpen = computed({
  get() { return !!selected.value },
  set(v: boolean) { if (!v) selected.value = null }
})

const {
  detailDocument,
  detailDocumentLoading,
  detailParagraphs,
  detailParagraphsLoading,
  fetchDetail,
  clearDetail,
} = usePublicationFetch()

watch(selected, (item) => {
  if (!item || item.collection === ENTRELINEAS_COLLECTION) {
    clearDetail()
    return
  }
  fetchDetail(item.hit, item.collection)
})

// Si el item seleccionado desaparece del historial (eliminado desde otra
// pestaña o desde aquí mismo), cerramos el panel de detalle.
watch(histItems, (items) => {
  if (!selected.value) return
  const stillThere = items.find(it =>
    it.collection === selected.value!.collection
    && String(it._id) === String(selected.value!._id))
  if (!stillThere) selected.value = null
})

const breakpoints = useBreakpoints(breakpointsTailwind)
const isMobile = breakpoints.smaller('lg')

// ---- Helpers de fila ---------------------------------------------------

function safeDate(hit: SearchHit) {
  const d = hit.date ?? hit.isodate
  if (!d) return ''
  const ts = typeof d === 'string' ? new Date(d).getTime() : (d as number) * 1000
  if (!Number.isFinite(ts)) return ''
  return formatDate(ts / 1000)
}

function hasDate(hit: SearchHit) {
  return hit.date != null || hit.isodate != null
}

/** Etiqueta corta y humana para `visitedAt`. Tres tramos:
 *   - menos de un minuto: "ahora"
 *   - mismo día: "hoy HH:mm"
 *   - cualquier otro: fecha completa
 *  Mejor que "hace 3 horas" porque a) no requiere recomputar cada minuto,
 *  b) deja claro de un vistazo si la entrada es del día o de antes. */
function formatVisited(ts: number): string {
  if (!Number.isFinite(ts)) return ''
  const now = Date.now()
  const diffMs = now - ts
  if (diffMs < 60_000) return 'hace un momento'

  const d = new Date(ts)
  const today = new Date()
  const sameDay = d.getFullYear() === today.getFullYear()
    && d.getMonth() === today.getMonth()
    && d.getDate() === today.getDate()

  const hh = String(d.getHours()).padStart(2, '0')
  const mm = String(d.getMinutes()).padStart(2, '0')
  if (sameDay) return `hoy ${hh}:${mm}`

  const yesterday = new Date(today)
  yesterday.setDate(yesterday.getDate() - 1)
  const sameYesterday = d.getFullYear() === yesterday.getFullYear()
    && d.getMonth() === yesterday.getMonth()
    && d.getDate() === yesterday.getDate()
  if (sameYesterday) return `ayer ${hh}:${mm}`

  const day = String(d.getDate()).padStart(2, '0')
  const month = String(d.getMonth() + 1).padStart(2, '0')
  return `${day}/${month}/${d.getFullYear()} ${hh}:${mm}`
}

function removeItem(it: HistoryItem, ev: Event) {
  ev.stopPropagation()
  history.remove(it.collection, it._id)
  toast.add({
    title: 'Eliminado del historial',
    description: it.hit?.title,
    icon: 'i-lucide-trash-2',
    color: 'neutral',
    duration: 1500
  })
}

// ---- Exportar / Compartir ----------------------------------------------

async function copyHistory() {
  if (!histTotal.value) return
  const ok = await history.copyJsonToClipboard()
  toast.add({
    title: ok ? 'Historial copiado al portapapeles' : 'No se pudo copiar',
    description: ok ? 'Pégalo en otro lugar para guardarlo.' : 'Tu navegador bloqueó el acceso al portapapeles.',
    icon: ok ? 'i-lucide-clipboard-check' : 'i-lucide-triangle-alert',
    color: ok ? 'primary' : 'error',
    duration: 2400
  })
}

function downloadHistory() {
  if (!histTotal.value) return
  history.downloadJson()
  toast.add({
    title: 'Descargando tu historial',
    icon: 'i-lucide-download',
    color: 'primary',
    duration: 1500
  })
}

const showClearConfirm = ref(false)
function confirmClear() {
  history.clear()
  showClearConfirm.value = false
  toast.add({
    title: 'Historial vaciado',
    icon: 'i-lucide-trash-2',
    color: 'neutral',
    duration: 1500
  })
}

// ---- Importar ----------------------------------------------------------

const showImport = ref(false)
const importMode = ref<'merge' | 'replace'>('merge')
const importText = ref('')
const importFileInput = ref<HTMLInputElement | null>(null)
const importing = ref(false)

function openImport() {
  importText.value = ''
  importMode.value = 'merge'
  showImport.value = true
}

function pickImportFile() {
  importFileInput.value?.click()
}

async function onImportFile(ev: Event) {
  const input = ev.target as HTMLInputElement
  const file = input.files?.[0]
  if (!file) return
  importing.value = true
  try {
    const result = await history.importFromFile(file, importMode.value)
    toast.add({
      title: `Importados ${result.added}`,
      description: result.skipped
        ? `${result.skipped} ya estaban en tu historial${result.invalid ? `, ${result.invalid} inválidos` : ''}.`
        : result.invalid
          ? `${result.invalid} inválidos.`
          : 'Tu historial se actualizó.',
      icon: 'i-lucide-history',
      color: 'primary',
      duration: 2800
    })
    showImport.value = false
  } catch (e) {
    toast.add({
      title: 'No se pudo importar',
      description: (e as Error)?.message || 'Archivo inválido.',
      icon: 'i-lucide-triangle-alert',
      color: 'error',
      duration: 3200
    })
  } finally {
    importing.value = false
    input.value = ''
  }
}

function applyTextImport() {
  if (!importText.value.trim()) return
  importing.value = true
  try {
    const result = history.importFromJson(importText.value, importMode.value)
    toast.add({
      title: `Importados ${result.added}`,
      description: result.skipped
        ? `${result.skipped} ya estaban en tu historial${result.invalid ? `, ${result.invalid} inválidos` : ''}.`
        : result.invalid
          ? `${result.invalid} inválidos.`
          : 'Tu historial se actualizó.',
      icon: 'i-lucide-history',
      color: 'primary',
      duration: 2800
    })
    showImport.value = false
  } catch (e) {
    toast.add({
      title: 'No se pudo importar',
      description: (e as Error)?.message || 'JSON inválido.',
      icon: 'i-lucide-triangle-alert',
      color: 'error',
      duration: 3200
    })
  } finally {
    importing.value = false
  }
}

// Menú compacto para móvil — los iconos sueltos del navbar son ambiguos sin
// tooltip (que no aparece en touch), así que en pantallas chicas los
// agrupamos en un dropdown con etiquetas explícitas.
const mobileActions = computed<DropdownMenuItem[][]>(() => [[
  {
    label: 'Importar historial',
    icon: 'i-lucide-upload',
    onSelect: () => openImport()
  },
  {
    label: 'Copiar al portapapeles',
    icon: 'i-lucide-clipboard-copy',
    disabled: !histTotal.value,
    onSelect: () => copyHistory()
  },
  {
    label: 'Descargar (.json)',
    icon: 'i-lucide-download',
    disabled: !histTotal.value,
    onSelect: () => downloadHistory()
  }
], [
  {
    label: 'Vaciar historial',
    icon: 'i-lucide-trash-2',
    color: 'error',
    disabled: !histTotal.value,
    onSelect: () => { showClearConfirm.value = true }
  }
]])

/** Aviso de cercanía al tope. El store recorta a `HISTORY_LIMIT`; mostramos
 *  un hint discreto cuando estamos a menos del 10% del tope para que el
 *  usuario sepa por qué las entradas antiguas pueden desaparecer. */
const nearLimit = computed(() => histTotal.value >= Math.floor(HISTORY_LIMIT * 0.9))
</script>

<template>
  <UDashboardPanel
    id="history-list"
    :default-size="32"
    :min-size="24"
    :max-size="44"
    resizable
  >
    <UDashboardNavbar title="Historial">
      <template #leading>
        <UDashboardSidebarCollapse />
      </template>

      <template #trailing>
        <UBadge v-if="histTotal" :label="histTotal" variant="subtle" />
      </template>

      <template #right>
        <!-- Desktop: iconos individuales con tooltip -->
        <div class="hidden sm:flex items-center gap-0.5">
          <UTooltip text="Importar historial">
            <UButton
              icon="i-lucide-upload"
              color="neutral"
              variant="ghost"
              size="sm"
              aria-label="Importar historial"
              @click="openImport"
            />
          </UTooltip>
          <UTooltip text="Copiar historial al portapapeles">
            <UButton
              icon="i-lucide-clipboard-copy"
              color="neutral"
              variant="ghost"
              size="sm"
              :disabled="!histTotal"
              aria-label="Copiar historial"
              @click="copyHistory"
            />
          </UTooltip>
          <UTooltip text="Descargar historial (.json)">
            <UButton
              icon="i-lucide-download"
              color="neutral"
              variant="ghost"
              size="sm"
              :disabled="!histTotal"
              aria-label="Descargar historial"
              @click="downloadHistory"
            />
          </UTooltip>
          <UTooltip text="Vaciar historial">
            <UButton
              icon="i-lucide-trash-2"
              color="error"
              variant="ghost"
              size="sm"
              :disabled="!histTotal"
              aria-label="Vaciar historial"
              @click="showClearConfirm = true"
            />
          </UTooltip>
        </div>

        <!-- Móvil: un único botón con menú etiquetado -->
        <UDropdownMenu :items="mobileActions" :content="{ align: 'end' }" class="sm:hidden">
          <UButton
            icon="i-lucide-ellipsis-vertical"
            color="neutral"
            variant="ghost"
            size="sm"
            aria-label="Más acciones"
          />
        </UDropdownMenu>
      </template>
    </UDashboardNavbar>

    <div class="px-4 sm:px-6 py-3 border-b border-default flex flex-col gap-2.5">
      <UInput
        v-model="localQuery"
        icon="i-lucide-search"
        placeholder="Filtrar historial por título..."
        size="md"
        class="w-full"
      />
      <div class="-mx-4 sm:mx-0 px-4 sm:px-0 flex gap-1.5 overflow-x-auto pb-0.5 scrollbar-thin">
        <UButton
          v-for="t in tabs"
          :key="t.value"
          :icon="t.icon"
          :label="t.label"
          size="xs"
          class="shrink-0"
          :color="activeCollection === t.value ? 'primary' : 'neutral'"
          :variant="activeCollection === t.value ? 'soft' : 'ghost'"
          @click="activeCollection = t.value"
        />
      </div>
      <p
        v-if="nearLimit"
        class="flex items-center gap-1 text-[11px] text-warning"
      >
        <UIcon name="i-lucide-info" class="size-3" />
        El historial guarda hasta {{ HISTORY_LIMIT }} entradas. Al superarlo, las más antiguas se eliminan automáticamente.
      </p>
    </div>

    <div class="overflow-y-auto divide-y divide-default flex-1">
      <div
        v-if="!filteredItems.length"
        class="flex flex-col items-center justify-center gap-3 py-12 sm:py-16 text-dimmed text-sm px-6 text-center"
      >
        <UIcon name="i-lucide-history" class="size-10" />
        <template v-if="!histTotal">
          <p class="font-medium text-toned">
            Tu historial está vacío
          </p>
          <p class="max-w-xs">
            Cada vez que abras el detalle de un resultado, se guardará aquí
            automáticamente.
          </p>
          <UButton
            icon="i-lucide-upload"
            label="Importar un historial compartido"
            variant="soft"
            size="sm"
            class="mt-1"
            @click="openImport"
          />
        </template>
        <p v-else>
          No hay coincidencias en tu historial para este filtro.
        </p>
      </div>

      <div
        v-for="(it, index) in filteredItems"
        :key="`${it.collection}-${it._id}-${index}`"
      >
        <div
          class="p-4 sm:px-6 text-sm cursor-pointer border-l-2 transition-colors text-toned"
          :class="selected && selected.collection === it.collection && String(selected._id) === String(it._id)
            ? 'border-primary bg-primary/10'
            : 'border-transparent hover:border-primary hover:bg-primary/5'"
          @click="selected = it"
        >
          <div class="flex items-start justify-between gap-2 mb-1">
            <div class="min-w-0 flex-1">
              <div class="flex gap-2">
                <UBadge
                  :label="labelFor(it.collection)"
                  size="sm"
                  variant="subtle"
                  color="neutral"
                  class="mb-1 uppercase"
                />
                <UBadge
                  v-if="it.hit?.filter"
                  :label="it.hit?.filter"
                  size="sm"
                  variant="subtle"
                  color="neutral"
                  class="mb-1 uppercase"
                />
                <UBadge
                  v-if="it.hit?.type"
                  :label="it.hit?.type"
                  size="sm"
                  variant="subtle"
                  color="neutral"
                  class="mb-1 uppercase"
                />
              </div>
              <div class="text-sm font-semibold line-clamp-2">
                {{ it.collection === ENTRELINEAS_COLLECTION
                  ? (it.hit?.title || 'Sin título')
                  : (it.hit?.origin || it.hit?.title || 'Sin título') }}
              </div>
            </div>
            <UButton
              icon="i-lucide-trash-2"
              color="neutral"
              variant="ghost"
              size="sm"
              class="-mt-1 -me-1 shrink-0"
              aria-label="Eliminar del historial"
              @click="(ev: MouseEvent) => removeItem(it, ev)"
            />
          </div>

          <p class="flex flex-wrap items-center gap-x-2 gap-y-0.5 text-xs text-muted">
            <span class="inline-flex items-center gap-1 text-[11px] text-dimmed">
              <UIcon name="i-lucide-clock" class="size-3" />
              Visto: {{ formatVisited(it.visitedAt) }}
            </span>
            <USeparator v-if="hasDate(it.hit)" orientation="vertical" class="h-3 hidden sm:block" />
            <span v-if="hasDate(it.hit)">{{ safeDate(it.hit) }}</span>
            <USeparator v-if="formatLocation(it.hit)" orientation="vertical" class="h-3 hidden sm:block" />
            <span class="truncate">{{ formatLocation(it.hit) }}</span>
          </p>
        </div>
      </div>
    </div>
  </UDashboardPanel>

  <!-- Entrelíneas → componente propio (imagen ImageKit + texto). -->
  <EntrelineaDetail
    v-if="selected && !isMobile && isEntrelinea"
    :document="selectedEntrelineaDoc!"
    :collection="selectedCollection"
    @close="selected = null"
  />
  <!-- Resto (actividades, conferencias) → detalle completo con párrafos. -->
  <PublicationDetail
    v-else-if="selected && !isMobile"
    :document="detailDocument"
    :document-loading="detailDocumentLoading"
    :paragraphs="detailParagraphs"
    :paragraphs-loading="detailParagraphsLoading"
    :collection="selectedCollection!"
    @close="selected = null"
  />
  <div v-else-if="!selected" class="hidden lg:flex flex-1 items-center justify-center">
    <div class="flex flex-col items-center gap-2 text-dimmed">
      <UIcon name="i-lucide-history" class="size-16" />
      <p class="text-sm">
        Selecciona un elemento para ver el detalle
      </p>
    </div>
  </div>

  <ClientOnly>
    <USlideover v-if="isMobile" v-model:open="isPanelOpen">
      <template #content>
        <EntrelineaDetail
          v-if="selected && isEntrelinea"
          :document="selectedEntrelineaDoc!"
          :collection="selectedCollection"
          @close="selected = null"
        />
        <PublicationDetail
          v-else-if="selected"
          :document="detailDocument"
          :document-loading="detailDocumentLoading"
          :paragraphs="detailParagraphs"
          :paragraphs-loading="detailParagraphsLoading"
          :collection="selectedCollection!"
          @close="selected = null"
        />
      </template>
    </USlideover>
  </ClientOnly>

  <!-- Confirmación de vaciado ------------------------------------------- -->
  <UModal v-model:open="showClearConfirm" title="Vaciar historial">
    <template #body>
      <p class="text-sm text-toned">
        Esto eliminará las <strong>{{ histTotal }}</strong> entradas guardadas en este dispositivo.
        La acción no se puede deshacer (a menos que tengas un export previo).
        Tu lista de favoritos no se ve afectada.
      </p>
    </template>
    <template #footer>
      <div class="flex flex-col-reverse sm:flex-row sm:justify-end gap-2 w-full">
        <UButton
          color="neutral"
          variant="ghost"
          label="Cancelar"
          block
          class="sm:w-auto"
          @click="showClearConfirm = false"
        />
        <UButton
          color="error"
          label="Vaciar historial"
          icon="i-lucide-trash-2"
          block
          class="sm:w-auto"
          @click="confirmClear"
        />
      </div>
    </template>
  </UModal>

  <!-- Importar ---------------------------------------------------------- -->
  <UModal v-model:open="showImport" title="Importar historial" :ui="{ footer: 'justify-end' }">
    <template #body>
      <div class="flex flex-col gap-4">
        <p class="text-sm text-muted">
          Carga un historial exportado desde un archivo
          <code class="px-1 rounded bg-elevated text-toned font-mono text-xs">.json</code>
          o pega su contenido.
        </p>

        <UButton
          color="primary"
          variant="soft"
          icon="i-lucide-file-up"
          label="Subir archivo .json"
          size="md"
          block
          @click="pickImportFile"
        />

        <USeparator label="o pega el contenido" />

        <div>
          <p class="text-xs font-medium text-toned mb-1.5">
            ¿Qué hacer si ya tienes historial?
          </p>
          <div class="grid grid-cols-2 gap-1.5">
            <UButton
              label="Combinar"
              icon="i-lucide-merge"
              size="sm"
              block
              :color="importMode === 'merge' ? 'primary' : 'neutral'"
              :variant="importMode === 'merge' ? 'soft' : 'outline'"
              @click="importMode = 'merge'"
            />
            <UButton
              label="Reemplazar"
              icon="i-lucide-replace"
              size="sm"
              block
              :color="importMode === 'replace' ? 'primary' : 'neutral'"
              :variant="importMode === 'replace' ? 'soft' : 'outline'"
              @click="importMode = 'replace'"
            />
          </div>
          <p class="text-xs text-dimmed mt-1.5">
            {{ importMode === 'merge'
              ? 'Conserva el historial actual y añade las entradas nuevas.'
              : 'Borra el historial actual y lo sustituye por el importado.' }}
          </p>
        </div>

        <UTextarea
          v-model="importText"
          :rows="6"
          placeholder='{"version":1,"items":[ ... ]}'
          class="w-full font-mono text-xs"
        />

        <input
          ref="importFileInput"
          type="file"
          accept="application/json,.json"
          class="hidden"
          @change="onImportFile"
        >
      </div>
    </template>
    <template #footer>
      <div class="flex flex-col-reverse sm:flex-row sm:justify-end gap-2 w-full">
        <UButton
          color="neutral"
          variant="ghost"
          label="Cancelar"
          block
          class="sm:w-auto"
          @click="showImport = false"
        />
        <UButton
          color="primary"
          icon="i-lucide-history"
          label="Importar desde texto"
          :loading="importing"
          :disabled="!importText.trim() || importing"
          block
          class="sm:w-auto"
          @click="applyTextImport"
        />
      </div>
    </template>
  </UModal>
</template>
