import { useEffect, useState, useMemo, useRef } from 'react'
import { useNavigate } from 'react-router-dom'
import { useJourneyStore } from '../store/journeyStore'
import { journeyApi } from '../api/client'
import Navbar from '../components/Layout/Navbar'
import { useToast } from '../components/shared/Toast'
import { useTranslation } from '../i18n'
import {
  Plus, Search, Sparkles, Calendar, MapPin, BookOpen, Camera,
  Check, X, ChevronRight, RefreshCw, Users,
} from 'lucide-react'
import type { Journey } from '../store/journeyStore'
import { computeJourneyLifecycle } from '../utils/journeyLifecycle'

const GRADIENTS = [
  'linear-gradient(135deg, #0F172A 0%, #6366F1 45%, #EC4899 100%)',
  'linear-gradient(135deg, #1E293B 0%, #7C3AED 50%, #F59E0B 100%)',
  'linear-gradient(135deg, #134E5E 0%, #71B280 100%)',
  'linear-gradient(135deg, #2D1B69 0%, #11998E 100%)',
  'linear-gradient(135deg, #4B134F 0%, #C94B4B 100%)',
  'linear-gradient(135deg, #373B44 0%, #4286F4 100%)',
]

function pickGradient(id: number): string {
  return GRADIENTS[id % GRADIENTS.length]
}

function timeAgo(timestamp: number, t: (k: string, p?: any) => string): string {
  const diff = Date.now() - timestamp
  const hours = Math.floor(diff / 3600000)
  if (hours < 1) return t('common.justNow')
  if (hours < 24) return t('common.hoursAgo', { count: hours })
  const days = Math.floor(hours / 24)
  return t('common.daysAgo', { count: days })
}

export default function JourneyPage() {
  const navigate = useNavigate()
  const toast = useToast()
  const { t } = useTranslation()
  const { journeys, loading, loadJourneys, createJourney } = useJourneyStore()

  const [showCreate, setShowCreate] = useState(false)
  const [newTitle, setNewTitle] = useState('')
  const [availableTrips, setAvailableTrips] = useState<any[]>([])
  const [selectedTripIds, setSelectedTripIds] = useState<Set<number>>(new Set())
  const [searchOpen, setSearchOpen] = useState(false)
  const [searchQuery, setSearchQuery] = useState('')
  const searchInputRef = useRef<HTMLInputElement>(null)

  // suggestion
  const [suggestions, setSuggestions] = useState<any[]>([])
  const [dismissedSuggestions, setDismissedSuggestions] = useState<Set<number>>(new Set())

  useEffect(() => {
    loadJourneys()
    journeyApi.suggestions().then(d => setSuggestions(d.trips || [])).catch(() => {})
  }, [])

  const activeSuggestion = suggestions.find(s => !dismissedSuggestions.has(s.id))

  const activeJourney = useMemo(() => {
    if (searchQuery.trim()) return null
    return journeys.find(j => {
      const j2 = j as any
      return computeJourneyLifecycle(j.status, j2.trip_date_min, j2.trip_date_max) === 'live'
    }) || null
  }, [journeys, searchQuery])

  const filteredJourneys = useMemo(() => {
    const q = searchQuery.trim().toLowerCase()
    if (!q) return journeys.filter(j => j.id !== activeJourney?.id)
    return journeys.filter(j => {
      const inTitle = j.title.toLowerCase().includes(q)
      const inSubtitle = j.subtitle?.toLowerCase().includes(q) ?? false
      return inTitle || inSubtitle
    })
  }, [journeys, activeJourney, searchQuery])

  const openCreateModal = async (preSelectedTripId?: number) => {
    setShowCreate(true)
    setNewTitle('')
    const initial = new Set<number>()
    if (preSelectedTripId) initial.add(preSelectedTripId)
    setSelectedTripIds(initial)
    try {
      const data = await journeyApi.availableTrips()
      setAvailableTrips(data.trips || [])
    } catch {}
  }

  const handleCreate = async () => {
    if (!newTitle.trim()) return
    try {
      const j = await createJourney({
        title: newTitle.trim(),
        trip_ids: [...selectedTripIds],
      })
      setShowCreate(false)
      navigate(`/journey/${j.id}`)
    } catch {
      toast.error(t('journey.createError'))
    }
  }

  const totalPlaces = useMemo(() => {
    return availableTrips.filter(t => selectedTripIds.has(t.id)).reduce((sum: number, t: any) => sum + (t.place_count || 0), 0)
  }, [availableTrips, selectedTripIds])

  return (
    <div className="min-h-screen bg-zinc-50 dark:bg-zinc-950">
      <Navbar />
      <div style={{ paddingTop: 'var(--nav-h, 56px)' }}>
        <div className="max-w-[1440px] mx-auto">

          {/* Header — mobile */}
          <div className="md:hidden px-5 pt-5 pb-4 flex flex-col gap-2">
            <div className="flex items-center gap-2">
              <button
                onClick={() => {
                  if (searchOpen) {
                    setSearchOpen(false)
                    setSearchQuery('')
                  } else {
                    setSearchOpen(true)
                    setTimeout(() => searchInputRef.current?.focus(), 50)
                  }
                }}
                className="w-10 h-10 rounded-xl border border-zinc-200 dark:border-zinc-700 bg-white dark:bg-zinc-800 flex items-center justify-center text-zinc-500 hover:bg-zinc-50 dark:hover:bg-zinc-700 flex-shrink-0"
              >
                {searchOpen ? <X size={15} /> : <Search size={15} />}
              </button>
              <button
                onClick={() => openCreateModal()}
                className="flex-1 flex items-center justify-center gap-2 py-2.5 rounded-xl bg-zinc-900 dark:bg-white text-white dark:text-zinc-900 text-[14px] font-semibold active:scale-[0.98] transition-transform"
              >
                <Plus size={16} strokeWidth={2.5} />
                {t('journey.frontpage.createJourney')}
              </button>
            </div>
            {searchOpen && (
              <input
                ref={searchInputRef}
                value={searchQuery}
                onChange={e => setSearchQuery(e.target.value)}
                onKeyDown={e => { if (e.key === 'Escape') { setSearchQuery(''); setSearchOpen(false) } }}
                placeholder={t('journey.search.placeholder')}
                className="w-full px-3.5 py-2.5 border border-zinc-200 dark:border-zinc-700 rounded-xl text-[14px] bg-white dark:bg-zinc-800 text-zinc-900 dark:text-white focus:border-zinc-400 focus:outline-none"
              />
            )}
          </div>

          {/* Header — desktop (unified toolbar) */}
          <div className="hidden md:block px-8 pt-10 pb-7">
            <div style={{
              background: 'var(--bg-tertiary)', borderRadius: 18,
              border: '1px solid var(--border-primary)',
              boxShadow: '0 1px 3px rgba(0,0,0,0.06), 0 1px 2px rgba(0,0,0,0.04)',
              padding: '14px 16px 14px 22px',
              display: 'flex', alignItems: 'center', gap: 16, flexWrap: 'wrap',
            }}>
              <h2 style={{ margin: 0, fontSize: 18, fontWeight: 600, color: 'var(--text-primary)', letterSpacing: '-0.01em', flexShrink: 0 }}>
                {t('journey.title')}
              </h2>
              <div style={{ width: 1, height: 22, background: 'var(--border-faint)', flexShrink: 0 }} />
              <span style={{ fontSize: 13, color: 'var(--text-muted)' }}>
                {t('journey.frontpage.subtitle')}
              </span>

              <div style={{ display: 'inline-flex', gap: 6, alignItems: 'center', marginLeft: 'auto', flexShrink: 0 }}>
                <button
                  onClick={() => openCreateModal()}
                  style={{
                    appearance: 'none', border: 'none', cursor: 'pointer', fontFamily: 'inherit',
                    display: 'inline-flex', alignItems: 'center', gap: 6,
                    padding: '9px 14px', borderRadius: 10, fontSize: 13, fontWeight: 500,
                    background: 'var(--accent)', color: 'var(--accent-text)', flexShrink: 0,
                    marginLeft: 2,
                    transition: 'opacity 0.15s ease',
                  }}
                  onMouseEnter={e => e.currentTarget.style.opacity = '0.88'}
                  onMouseLeave={e => e.currentTarget.style.opacity = '1'}
                >
                  <Plus size={14} strokeWidth={2.5} />
                  {t('journey.frontpage.createJourney')}
                </button>
              </div>
            </div>
          </div>

          <div className="px-4 md:px-8 pb-16">

            {/* Suggestion banner */}
            {activeSuggestion && (
              <div className="relative rounded-2xl overflow-hidden mb-8" style={{ background: 'linear-gradient(135deg, #1E293B 0%, #334155 100%)' }}>
                <div className="absolute inset-0 pointer-events-none hidden md:block" style={{ background: 'radial-gradient(circle at 85% 50%, rgba(99,102,241,0.4), transparent 50%), radial-gradient(circle at 100% 100%, rgba(236,72,153,0.3), transparent 50%)' }} />
                <div className="absolute inset-0 pointer-events-none md:hidden" style={{ background: 'radial-gradient(circle at 80% 20%, rgba(99,102,241,0.5), transparent 60%), radial-gradient(circle at 20% 90%, rgba(236,72,153,0.35), transparent 60%)' }} />
                <div className="relative flex flex-col md:flex-row md:items-center justify-between gap-4 md:gap-6 p-5 text-white">
                  <div className="flex items-center gap-3.5">
                    <div className="w-10 h-10 rounded-[10px] bg-white/15 backdrop-blur flex items-center justify-center flex-shrink-0">
                      <Sparkles size={18} />
                    </div>
                    <div>
                      <div className="text-[10px] font-semibold tracking-[0.12em] uppercase opacity-70">{t("journey.frontpage.suggestionLabel")}</div>
                      <div className="text-[13px] mt-0.5">
                        <span dangerouslySetInnerHTML={{ __html: t('journey.frontpage.suggestionText', { title: activeSuggestion.title }) }} />
                      </div>
                    </div>
                  </div>
                  <div className="flex items-center gap-2 flex-shrink-0">
                    <button
                      onClick={() => setDismissedSuggestions(prev => new Set([...prev, activeSuggestion.id]))}
                      className="px-3 py-1.5 rounded-lg bg-white/10 border border-white/20 text-[12px] font-medium text-white hover:bg-white/20"
                    >
                      {t('journey.frontpage.dismiss')}
                    </button>
                    <button
                      onClick={() => openCreateModal(activeSuggestion.id)}
                      className="px-3 py-1.5 rounded-lg !bg-white !text-zinc-900 text-[12px] font-medium hover:!bg-zinc-100"
                    >
                      {t('journey.frontpage.createJourney')}
                    </button>
                  </div>
                </div>
              </div>
            )}

            {/* Active Journey Hero */}
            {activeJourney && (
              <div className="mb-10">
                <div className="flex items-center justify-between mb-3">
                  <span className="text-[11px] font-bold tracking-[0.14em] uppercase text-zinc-500">{t("journey.frontpage.activeJourney")}</span>
                  <span className="text-[11px] text-zinc-400 flex items-center gap-1.5">
                    <span className="w-1.5 h-1.5 rounded-full bg-emerald-500 animate-pulse" />
                    {t('journey.frontpage.updated', { time: timeAgo(activeJourney.updated_at, t) })}
                  </span>
                </div>

                <div
                  onClick={() => navigate(`/journey/${activeJourney.id}`)}
                  className="relative rounded-3xl overflow-hidden cursor-pointer transition-[transform,box-shadow] duration-300 ease-[cubic-bezier(0.23,1,0.32,1)] hover:-translate-y-1 hover:shadow-xl h-[340px] md:h-[400px]"
                  style={{ background: pickGradient(activeJourney.id) }}
                >
                  {/* Cover image */}
                  {activeJourney.cover_image && (
                    <div className="absolute inset-0 z-[1]">
                      <img src={`/uploads/${activeJourney.cover_image}`} className="w-full h-full object-cover" alt="" />
                      <div className="absolute inset-0" style={{ background: pickGradient(activeJourney.id), opacity: 0.45 }} />
                    </div>
                  )}

                  {/* Gradient overlays */}
                  <div className="absolute inset-0 pointer-events-none z-[2]" style={{ background: 'radial-gradient(circle at 15% 20%, rgba(236,72,153,0.35), transparent 40%), radial-gradient(circle at 85% 80%, rgba(251,146,60,0.3), transparent 45%), radial-gradient(circle at 50% 50%, rgba(99,102,241,0.25), transparent 50%)' }} />
                  <div className="absolute inset-0 pointer-events-none z-[2]" style={{ background: 'linear-gradient(180deg, transparent 0%, transparent 50%, rgba(0,0,0,0.4) 100%), linear-gradient(90deg, rgba(0,0,0,0.15) 0%, transparent 50%)' }} />

                  <div className="relative h-full p-6 md:p-8 flex flex-col z-[3] text-white">
                    {/* Top badges */}
                    <div className="flex items-center justify-between">
                      <div className="flex items-center gap-2">
                        <span className="inline-flex items-center gap-2 px-3 py-1.5 bg-white/12 backdrop-blur-sm border border-white/15 rounded-full text-[10px] font-semibold uppercase tracking-[0.08em]">
                          <span className="w-1.5 h-1.5 rounded-full bg-emerald-500 shadow-[0_0_6px_rgba(16,185,129,0.6)] animate-pulse" />
                          {t('journey.frontpage.live')}
                        </span>
                        <span className="inline-flex items-center gap-1.5 px-3 py-1.5 bg-white/12 backdrop-blur-sm border border-white/15 rounded-full text-[10px] font-medium">
                          <RefreshCw size={10} />
                          {t('journey.frontpage.synced')}
                        </span>
                      </div>
                    </div>

                    {/* Middle — title */}
                    <div className="flex-1 flex flex-col justify-center py-4">
                      {activeJourney.subtitle && (
                        <p className="text-[13px] font-medium opacity-85 mb-3">{activeJourney.subtitle}</p>
                      )}
                      <h2 className="text-[40px] md:text-[56px] font-extrabold tracking-[-0.035em] leading-[0.95] mb-3" style={{ textShadow: '0 2px 30px rgba(0,0,0,0.15)' }}>
                        {activeJourney.title}
                      </h2>
                    </div>

                    {/* Bottom stats */}
                    <div className="flex items-end justify-between gap-6">
                      <div className="flex gap-7">
                        {[
                          { val: (activeJourney as any).entry_count ?? '--', label: t("journey.stats.entries") },
                          { val: (activeJourney as any).photo_count ?? '--', label: t("journey.stats.photos") },
                          { val: (activeJourney as any).place_count ?? '--', label: t("journey.stats.places") },
                        ].map(s => (
                          <div key={s.label} className="flex flex-col gap-1">
                            <span className="text-[28px] font-extrabold tracking-[-0.02em] leading-none">{s.val}</span>
                            <span className="text-[10px] uppercase tracking-[0.12em] opacity-70 font-semibold">{s.label}</span>
                          </div>
                        ))}
                      </div>
                      <span className="hidden md:inline-flex items-center gap-1.5 px-3 py-1.5 bg-white/15 backdrop-blur-sm rounded-full text-[11px] font-medium">
                        {t('journey.frontpage.continueWriting')}<ChevronRight size={12} />
                      </span>
                    </div>
                  </div>
                </div>
              </div>
            )}

            {/* Search results info */}
            {searchQuery.trim() && (
              <div className="mb-4 flex items-center gap-2">
                <span className="text-[13px] text-zinc-500">
                  {filteredJourneys.length === 0
                    ? t('journey.search.noResults', { query: searchQuery.trim() })
                    : `${filteredJourneys.length} ${t('journey.frontpage.journeys')}`}
                </span>
              </div>
            )}

            {/* All Journeys */}
            {!searchQuery.trim() && (
              <div className="mb-4 flex items-center justify-between">
                <span className="text-[11px] font-bold tracking-[0.14em] uppercase text-zinc-500">{t("journey.frontpage.allJourneys")}</span>
                <span className="text-[11px] text-zinc-400">{journeys.length} {t('journey.frontpage.journeys')}</span>
              </div>
            )}

            {loading && journeys.length === 0 ? (
              <div className="flex justify-center py-16">
                <div className="w-6 h-6 border-2 border-zinc-300 border-t-zinc-900 rounded-full animate-spin" />
              </div>
            ) : (
              <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4 md:gap-[18px]">
                {filteredJourneys.map(j => (
                  <JourneyCard key={j.id} journey={j} onClick={() => navigate(`/journey/${j.id}`)} />
                ))}

                {/* Create card */}
                <button
                  onClick={() => openCreateModal()}
                  className="group min-h-[320px] rounded-2xl border-[1.5px] border-dashed border-zinc-200 dark:border-zinc-700 bg-white dark:bg-zinc-900 flex flex-col items-center justify-center gap-2.5 hover:border-zinc-400 hover:bg-zinc-50 dark:hover:bg-zinc-800 transition-[border-color,background-color,transform] duration-200 ease-[cubic-bezier(0.23,1,0.32,1)] cursor-pointer hover:-translate-y-0.5"
                >
                  <div className="w-14 h-14 rounded-full bg-zinc-100 dark:bg-zinc-800 flex items-center justify-center text-zinc-400 group-hover:bg-white dark:group-hover:bg-zinc-700 transition-[background-color,transform] group-hover:rotate-90 duration-300 ease-[cubic-bezier(0.23,1,0.32,1)]">
                    <Plus size={22} />
                  </div>
                  <span className="text-[14px] font-semibold text-zinc-700 dark:text-zinc-300">{t("journey.frontpage.createNew")}</span>
                  <span className="text-[12px] text-zinc-400 max-w-[180px] text-center leading-snug">{t("journey.frontpage.createNewSub")}</span>
                </button>
              </div>
            )}
          </div>
        </div>
      </div>

      {/* Create Modal */}
      {showCreate && (
        <div className="fixed inset-0 z-[200] flex items-center justify-center p-5" style={{ background: 'rgba(9,9,11,0.6)', backdropFilter: 'blur(6px)' }}>
          <div className="bg-white dark:bg-zinc-900 rounded-2xl shadow-[0_20px_40px_rgba(0,0,0,0.2)] max-w-[640px] w-full max-h-[90vh] flex flex-col overflow-hidden" style={{ paddingBottom: 'var(--bottom-nav-h)' }}>

            {/* Header */}
            <div className="px-7 pt-6 pb-5 border-b border-zinc-200 dark:border-zinc-700">
              <h2 className="text-[18px] font-bold tracking-[-0.01em] text-zinc-900 dark:text-white">{t("journey.frontpage.createJourney")}</h2>
              <p className="text-[13px] text-zinc-500 mt-1">{t('journey.frontpage.createNewSub')}</p>
            </div>

            {/* Body */}
            <div className="flex-1 overflow-y-auto px-7 py-5">
              <label className="text-[10px] font-semibold tracking-[0.12em] uppercase text-zinc-500 block mb-2.5">{t('journey.frontpage.journeyName')}</label>
              <input
                value={newTitle}
                onChange={e => setNewTitle(e.target.value)}
                placeholder={t('journey.frontpage.namePlaceholder')}
                className="w-full px-3.5 py-2.5 border border-zinc-200 dark:border-zinc-700 rounded-lg text-[14px] bg-white dark:bg-zinc-800 text-zinc-900 dark:text-white focus:border-zinc-900 dark:focus:border-zinc-400 focus:outline-none mb-5"
              />

              <label className="text-[10px] font-semibold tracking-[0.12em] uppercase text-zinc-500 block mb-2.5">{t('journey.frontpage.selectTrips')}</label>
              <div className="flex flex-col gap-2 max-h-[320px] overflow-y-auto">
                {availableTrips.map(trip => {
                  const selected = selectedTripIds.has(trip.id)
                  const status = trip.end_date && trip.end_date < new Date().toISOString().split('T')[0]
                    ? 'completed'
                    : trip.start_date && trip.start_date <= new Date().toISOString().split('T')[0]
                      ? 'active'
                      : 'upcoming'
                  const statusColors: Record<string, string> = {
                    completed: 'bg-emerald-100 text-emerald-800 dark:bg-emerald-900/30 dark:text-emerald-400',
                    active: 'bg-blue-100 text-blue-800 dark:bg-blue-900/30 dark:text-blue-400',
                    upcoming: 'bg-amber-100 text-amber-800 dark:bg-amber-900/30 dark:text-amber-400',
                  }

                  return (
                    <div
                      key={trip.id}
                      onClick={() => {
                        setSelectedTripIds(prev => {
                          const next = new Set(prev)
                          if (next.has(trip.id)) next.delete(trip.id)
                          else next.add(trip.id)
                          return next
                        })
                      }}
                      className={`flex items-center gap-3 p-3 rounded-xl border cursor-pointer transition-[border-color,background-color] duration-150 ease-[cubic-bezier(0.23,1,0.32,1)] ${
                        selected
                          ? 'border-zinc-900 dark:border-zinc-400 bg-zinc-50 dark:bg-zinc-800'
                          : 'border-zinc-200 dark:border-zinc-700 hover:border-zinc-400 dark:hover:border-zinc-500'
                      }`}
                    >
                      <div className={`w-5 h-5 rounded-md border-2 flex items-center justify-center flex-shrink-0 ${
                        selected
                          ? 'bg-zinc-900 dark:bg-white border-zinc-900 dark:border-white'
                          : 'border-zinc-300 dark:border-zinc-600'
                      }`}>
                        {selected && <Check size={12} className="text-white dark:text-zinc-900" />}
                      </div>
                      <div className="w-12 h-12 rounded-lg flex-shrink-0 overflow-hidden" style={{ background: pickGradient(trip.id) }}>
                        {trip.cover_image && (
                          <img src={trip.cover_image} className="w-full h-full object-cover" alt="" />
                        )}
                      </div>
                      <div className="flex-1 min-w-0">
                        <div className="text-[14px] font-semibold text-zinc-900 dark:text-white">{trip.title}</div>
                        <div className="text-[12px] text-zinc-500 flex items-center gap-2.5 mt-0.5">
                          <span className="flex items-center gap-1"><Calendar size={11} /> {trip.start_date ? Math.ceil((new Date(trip.end_date || trip.start_date).getTime() - new Date(trip.start_date).getTime()) / 86400000) + 1 : '?'}<span className="hidden md:inline"> {t('journey.stats.days').toLowerCase()}</span></span>
                          <span className="flex items-center gap-1"><MapPin size={11} /> {trip.place_count || 0}<span className="hidden md:inline"> {t("journey.frontpage.places")}</span></span>
                        </div>
                      </div>
                      <span className={`text-[10px] font-medium uppercase tracking-[0.05em] px-2 py-0.5 rounded-full ${statusColors[status]}`}>
                        {t(`journey.status.${status}`)}
                      </span>
                    </div>
                  )
                })}
              </div>
            </div>

            {/* Footer */}
            <div className="px-7 py-4 border-t border-zinc-200 dark:border-zinc-700 bg-zinc-50 dark:bg-zinc-800/50 flex items-center justify-between">
              <div className="text-[12px] text-zinc-500">
                <strong className="text-zinc-900 dark:text-white">{selectedTripIds.size}</strong> <span className="hidden md:inline">{t('journey.frontpage.tripsSelected')}</span><span className="md:hidden">{t('journey.frontpage.trips')}</span>
                {selectedTripIds.size > 0 && <> · <strong className="text-zinc-900 dark:text-white">{totalPlaces}</strong> <span className="hidden md:inline">{t('journey.frontpage.placesImported')}</span><span className="md:hidden">{t('journey.frontpage.places')}</span></>}
              </div>
              <div className="flex items-center gap-2">
                <button
                  onClick={() => setShowCreate(false)}
                  className="px-3.5 py-2 rounded-lg border border-zinc-200 dark:border-zinc-600 text-[13px] font-medium text-zinc-700 dark:text-zinc-300 hover:bg-zinc-100 dark:hover:bg-zinc-700"
                >
                  {t('common.cancel')}
                </button>
                <button
                  onClick={handleCreate}
                  disabled={!newTitle.trim()}
                  className="px-3.5 py-2 rounded-lg bg-zinc-900 dark:bg-white text-white dark:text-zinc-900 text-[13px] font-medium hover:bg-zinc-800 dark:hover:bg-zinc-100 disabled:opacity-40 disabled:cursor-not-allowed"
                >
                  <span className="md:hidden">{t('journey.create')}</span><span className="hidden md:inline">{t('journey.frontpage.createJourney')}</span>
                </button>
              </div>
            </div>
          </div>
        </div>
      )}
    </div>
  )
}

function JourneyCard({ journey, onClick }: { journey: Journey & { entry_count?: number; photo_count?: number; place_count?: number; trip_date_min?: string | null; trip_date_max?: string | null }; onClick: () => void }) {
  const { t } = useTranslation()
  const j = journey
  const entryCount = j.entry_count ?? 0
  const photoCount = j.photo_count ?? 0
  const placeCount = j.place_count ?? 0
  const lifecycle = computeJourneyLifecycle(j.status, j.trip_date_min, j.trip_date_max)

  return (
    <div
      onClick={onClick}
      className="rounded-2xl border border-zinc-200 dark:border-zinc-700 bg-white dark:bg-zinc-900 overflow-hidden cursor-pointer transition-[transform,box-shadow,border-color] duration-250 ease-[cubic-bezier(0.23,1,0.32,1)] hover:border-zinc-400 hover:-translate-y-1 hover:shadow-[0_20px_40px_rgba(0,0,0,0.06)] flex flex-col"
    >
      {/* Cover */}
      <div className="h-[170px] relative overflow-hidden" style={{ background: pickGradient(j.id) }}>
        {j.cover_image && (
          <>
            <img src={`/uploads/${j.cover_image}`} className="absolute inset-0 w-full h-full object-cover" alt="" />
            <div className="absolute inset-0" style={{ background: pickGradient(j.id), opacity: 0.4 }} />
          </>
        )}
        <div className="absolute inset-0" style={{ background: 'linear-gradient(180deg, transparent 50%, rgba(0,0,0,0.4) 100%)' }} />

        {/* Top overlay */}
        <div className="absolute top-3.5 left-3.5 right-3.5 flex items-start justify-between z-[2]">
          <span className="inline-flex items-center gap-1.5 px-2.5 py-1 bg-black/45 backdrop-blur-sm rounded-full text-white text-[10px] font-semibold tracking-wide">
            <Calendar size={10} />
            {new Date(j.created_at).getFullYear()}
          </span>
        </div>

      </div>

      {/* Body */}
      <div className="px-[18px] pt-4 pb-[18px] flex flex-col flex-1">
        <h3 className="text-[16px] font-bold tracking-[-0.01em] text-zinc-900 dark:text-white">{j.title}</h3>
        {j.subtitle && (
          <p className="text-[12px] text-zinc-500 mt-1">{j.subtitle}</p>
        )}
        {lifecycle !== 'live' && (
          <span className={`inline-flex self-start mt-1.5 px-2 py-0.5 rounded-full text-[10px] font-medium uppercase tracking-wide ${
            lifecycle === 'archived' ? 'bg-zinc-100 dark:bg-zinc-800 text-zinc-500' :
            lifecycle === 'upcoming' ? 'bg-amber-100 dark:bg-amber-900/30 text-amber-700 dark:text-amber-400' :
            lifecycle === 'completed' ? 'bg-emerald-100 dark:bg-emerald-900/30 text-emerald-700 dark:text-emerald-400' :
            'bg-zinc-100 dark:bg-zinc-800 text-zinc-500'
          }`}>
            {t(`journey.status.${lifecycle}`)}
          </span>
        )}

        <div className="grid grid-cols-3 gap-2.5 mt-auto pt-3.5 border-t border-zinc-100 dark:border-zinc-800" style={{ marginTop: j.subtitle ? 14 : 'auto' }}>
          {[
            { val: entryCount, label: t('journey.stats.entries') },
            { val: photoCount, label: t('journey.stats.photos') },
            { val: placeCount, label: t('journey.stats.places') },
          ].map(s => (
            <div key={s.label} className="flex flex-col gap-1">
              <span className={`text-[16px] font-bold leading-none tracking-[-0.01em] ${s.val > 0 ? 'text-zinc-900 dark:text-white' : 'text-zinc-300 dark:text-zinc-600'}`}>
                {s.val > 0 ? s.val : '--'}
              </span>
              <span className="text-[9px] uppercase tracking-[0.06em] text-zinc-500 font-medium">{s.label}</span>
            </div>
          ))}
        </div>
      </div>
    </div>
  )
}
