'use client';

import { useState, useEffect, useCallback, useRef } from 'react';
import {
    ArrowLeft, Plus, Edit2, Trash2, MapPin, Type, Image as ImageIcon,
    Camera, ImagePlus, Loader2, X, ChevronLeft, ChevronRight, MoveUp, MoveDown,
} from 'lucide-react';
import { motion, AnimatePresence, PanInfo } from 'framer-motion';
import dynamic from 'next/dynamic';
import { apiUrl, thumbnailUrl } from '@/lib/api';
import JourneyForm from './JourneyForm';
import ArchivePhotoPicker from './ArchivePhotoPicker';
import Lightbox from './Lightbox';
import { Photo } from '@prisma/client';

const JourneyMap = dynamic(() => import('./JourneyMap'), {
    ssr: false,
    loading: () => (
        <div className="flex items-center justify-center h-[200px] bg-foreground/5 rounded-xl">
            <div className="w-6 h-6 border-2 border-foreground/20 border-t-foreground/60 rounded-full animate-spin" />
        </div>
    ),
});

// ── Types ─────────────────────────────────────────────────

interface GalleryImage {
    url: string;
    caption: string | null;
    photoId: string | null;
    focalX?: number | null;
    focalY?: number | null;
}

interface Block {
    id: string;
    type: 'text' | 'image' | 'gallery' | 'location';
    text: string | null;
    imageUrl: string | null;
    filename: string | null;
    images: string | null; // JSON array for gallery: [{ url, caption, photoId, focalX?, focalY? }]
    photoId: string | null;
    focalX: number | null;
    focalY: number | null;
    latitude: number | null;
    longitude: number | null;
    locationName: string | null;
    order: number;
}

interface JourneyFull {
    id: string;
    title: string;
    description: string | null;
    coverPhotoUrl: string | null;
    startDate: string | null;
    endDate: string | null;
    userId: string;
    createdAt: string;
    user: { id: string; name: string | null };
    blocks: Block[];
}

interface JourneyDetailProps {
    journeyId: string;
    onBack: () => void;
    canEdit: boolean;
}

// ── Block Adder (the + button between blocks) ────────────

function BlockAdder({ onAdd }: { onAdd: (type: 'text' | 'image' | 'location') => void }) {
    const [open, setOpen] = useState(false);

    return (
        <div className="flex items-center justify-center py-1 group relative">
            {/* Line */}
            <div className="absolute inset-x-0 top-1/2 h-px bg-foreground/0 group-hover:bg-foreground/8 transition-colors" />

            <button
                onClick={() => setOpen(!open)}
                className="relative z-10 w-7 h-7 rounded-full border-2 border-foreground/10 bg-paper
                           text-foreground/25 hover:text-foreground/50 hover:border-foreground/25
                           flex items-center justify-center transition-all opacity-0 group-hover:opacity-100
                           focus:opacity-100"
            >
                <Plus className="w-3.5 h-3.5" />
            </button>

            {open && (
                <div className="absolute z-20 top-full mt-1 flex gap-1 bg-paper border border-foreground/10 rounded-lg shadow-lg p-1">
                    <button
                        onClick={() => { onAdd('text'); setOpen(false); }}
                        className="flex items-center gap-1.5 px-3 py-1.5 rounded-md text-xs text-foreground/60 hover:bg-foreground/5 transition-colors"
                    >
                        <Type className="w-3.5 h-3.5" /> Text
                    </button>
                    <button
                        onClick={() => { onAdd('image'); setOpen(false); }}
                        className="flex items-center gap-1.5 px-3 py-1.5 rounded-md text-xs text-foreground/60 hover:bg-foreground/5 transition-colors"
                    >
                        <ImageIcon className="w-3.5 h-3.5" /> Photo
                    </button>
                    <button
                        onClick={() => { onAdd('location'); setOpen(false); }}
                        className="flex items-center gap-1.5 px-3 py-1.5 rounded-md text-xs text-foreground/60 hover:bg-foreground/5 transition-colors"
                    >
                        <MapPin className="w-3.5 h-3.5" /> Location
                    </button>
                </div>
            )}
        </div>
    );
}


// ── Text Block ────────────────────────────────────────────

function TextBlock({ block, editing, onUpdate, onDelete }: {
    block: Block; editing: boolean;
    onUpdate: (text: string) => void; onDelete: () => void;
}) {
    const [value, setValue] = useState(block.text || '');
    const textareaRef = useRef<HTMLTextAreaElement>(null);
    const saveTimeout = useRef<NodeJS.Timeout | null>(null);

    // Auto-resize textarea
    useEffect(() => {
        if (textareaRef.current) {
            textareaRef.current.style.height = 'auto';
            textareaRef.current.style.height = textareaRef.current.scrollHeight + 'px';
        }
    }, [value]);

    const handleChange = (newVal: string) => {
        setValue(newVal);
        // Debounced save
        if (saveTimeout.current) clearTimeout(saveTimeout.current);
        saveTimeout.current = setTimeout(() => onUpdate(newVal), 800);
    };

    if (editing) {
        return (
            <div className="group/block relative">
                <textarea
                    ref={textareaRef}
                    value={value}
                    onChange={e => handleChange(e.target.value)}
                    placeholder="Write something..."
                    className="w-full text-[15px] text-foreground/70 font-serif leading-[1.85] bg-transparent
                               resize-none focus:outline-none placeholder:text-foreground/20
                               border-l-2 border-transparent focus:border-foreground/15 pl-3 -ml-3 transition-colors"
                    rows={1}
                />
                <button onClick={onDelete}
                    className="absolute -right-2 top-0 p-1 rounded-full bg-paper border border-foreground/10
                               text-foreground/20 hover:text-red-500 hover:border-red-200 opacity-0 group-hover/block:opacity-100 transition-all">
                    <X className="w-3 h-3" />
                </button>
            </div>
        );
    }

    if (!block.text) return null;

    return (
        <p className="text-[15px] text-foreground/70 font-serif leading-[1.85]">
            {block.text}
        </p>
    );
}


// ── Image Block ───────────────────────────────────────────

function ImageBlock({ block, editing, isCover, onDelete, onOpenLightbox, onSetCover }: {
    block: Block; editing: boolean; isCover: boolean;
    onDelete: () => void;
    onOpenLightbox: () => void;
    onSetCover: () => void;
}) {
    if (!block.imageUrl) {
        return (
            <div className="-mx-4 sm:-mx-0">
                <div className="aspect-[3/2] bg-foreground/5 sm:rounded-xl flex items-center justify-center relative group/block">
                    <div className="text-center">
                        <ImageIcon className="w-8 h-8 text-foreground/15 mx-auto mb-2" />
                        <p className="text-xs text-foreground/25 font-serif italic">{block.text || block.filename || 'Photo'}</p>
                    </div>
                    {editing && (
                        <button onClick={onDelete}
                            className="absolute top-2 right-2 p-1.5 rounded-full bg-black/50 text-white/70 hover:text-white
                                       opacity-0 group-hover/block:opacity-100 transition-opacity">
                            <X className="w-3.5 h-3.5" />
                        </button>
                    )}
                </div>
            </div>
        );
    }

    return (
        <div className="-mx-4 sm:-mx-0">
            <div className="relative group/block cursor-pointer" onClick={onOpenLightbox}>
                <img
                    src={thumbnailUrl(block.imageUrl, 'lg')}
                    alt={block.text || ''}
                    className="w-full sm:rounded-xl"
                    loading="lazy"
                />
                {editing && (
                    <div className="absolute top-2 right-2 flex gap-1.5 opacity-0 group-hover/block:opacity-100 transition-opacity">
                        {!isCover && (
                            <button
                                onClick={(e) => { e.stopPropagation(); onSetCover(); }}
                                className="px-2 py-1 rounded-full bg-black/50 text-white/70 hover:text-white text-[10px] font-medium">
                                Cover
                            </button>
                        )}
                        <button
                            onClick={(e) => { e.stopPropagation(); onDelete(); }}
                            className="p-1.5 rounded-full bg-black/50 text-white/70 hover:text-white">
                            <X className="w-3.5 h-3.5" />
                        </button>
                    </div>
                )}
                {isCover && (
                    <div className="absolute top-2 left-2 px-2 py-0.5 rounded-full bg-black/50 text-white/80 text-[10px] font-medium">
                        Cover
                    </div>
                )}
            </div>
            {block.text && (
                <p className="text-xs text-foreground/35 italic font-serif text-center mt-2 px-4">
                    {block.text}
                </p>
            )}
        </div>
    );
}


// ── Gallery Block (carousel of multiple photos) ──────────

function GalleryBlock({ block, editing, coverUrl, onDelete, onOpenLightbox, onSetCover }: {
    block: Block; editing: boolean; coverUrl: string | null;
    onDelete: () => void;
    onOpenLightbox: (index: number) => void;
    onSetCover: (url: string) => void;
}) {
    const [currentIndex, setCurrentIndex] = useState(0);
    const [direction, setDirection] = useState(0);

    let images: GalleryImage[] = [];
    try {
        images = block.images ? JSON.parse(block.images) : [];
    } catch { /* invalid json */ }

    if (images.length === 0) return null;

    const hasMultiple = images.length > 1;

    const goTo = (idx: number) => {
        if (idx < 0 || idx >= images.length) return;
        setDirection(idx > currentIndex ? 1 : -1);
        setCurrentIndex(idx);
    };

    const handleDragEnd = (_: MouseEvent | TouchEvent | PointerEvent, info: PanInfo) => {
        if (info.offset.x < -50 || info.velocity.x < -0.5) {
            if (currentIndex < images.length - 1) goTo(currentIndex + 1);
        } else if (info.offset.x > 50 || info.velocity.x > 0.5) {
            if (currentIndex > 0) goTo(currentIndex - 1);
        }
    };

    const slideVariants = {
        enter: (d: number) => ({ x: d > 0 ? '100%' : '-100%', opacity: 0.5 }),
        center: { x: 0, opacity: 1 },
        exit: (d: number) => ({ x: d < 0 ? '100%' : '-100%', opacity: 0.5 }),
    };

    return (
        <div className="-mx-4 sm:-mx-0 group/block relative">
            {/* Carousel */}
            <div
                className="relative aspect-[3/2] bg-foreground/5 overflow-hidden cursor-pointer sm:rounded-xl"
                onClick={() => onOpenLightbox(currentIndex)}
            >
                <AnimatePresence initial={false} custom={direction} mode="popLayout">
                    <motion.img
                        key={images[currentIndex].url}
                        src={thumbnailUrl(images[currentIndex].url, 'lg')}
                        alt={images[currentIndex].caption || ''}
                        className="absolute inset-0 w-full h-full object-cover"
                        custom={direction}
                        variants={slideVariants}
                        initial="enter"
                        animate="center"
                        exit="exit"
                        transition={{ x: { duration: 0.35, ease: [0.25, 1, 0.5, 1] }, opacity: { duration: 0.2 } }}
                        drag={hasMultiple ? 'x' : false}
                        dragConstraints={{ left: 0, right: 0 }}
                        dragElastic={0.2}
                        onDragEnd={handleDragEnd}
                        loading="lazy"
                    />
                </AnimatePresence>

                {/* Arrows */}
                {hasMultiple && currentIndex > 0 && (
                    <button
                        onClick={(e) => { e.stopPropagation(); goTo(currentIndex - 1); }}
                        className="absolute left-2 top-1/2 -translate-y-1/2 w-9 h-9 rounded-full bg-black/30 text-white/80
                                   hover:bg-black/60 items-center justify-center transition-all hidden md:flex">
                        <ChevronLeft className="w-5 h-5" />
                    </button>
                )}
                {hasMultiple && currentIndex < images.length - 1 && (
                    <button
                        onClick={(e) => { e.stopPropagation(); goTo(currentIndex + 1); }}
                        className="absolute right-2 top-1/2 -translate-y-1/2 w-9 h-9 rounded-full bg-black/30 text-white/80
                                   hover:bg-black/60 items-center justify-center transition-all hidden md:flex">
                        <ChevronRight className="w-5 h-5" />
                    </button>
                )}

                {/* Counter */}
                {hasMultiple && (
                    <div className="absolute top-3 right-3 bg-black/60 text-white/90 text-xs font-mono px-2 py-0.5 rounded-full">
                        {currentIndex + 1}/{images.length}
                    </div>
                )}

                {/* Edit controls */}
                {editing && (
                    <div className="absolute top-2 left-2 flex gap-1.5 opacity-0 group-hover/block:opacity-100 transition-opacity">
                        {images[currentIndex]?.url !== coverUrl && (
                            <button
                                onClick={(e) => { e.stopPropagation(); onSetCover(images[currentIndex].url); }}
                                className="px-2 py-1 rounded-full bg-black/50 text-white/70 hover:text-white text-[10px] font-medium">
                                Cover
                            </button>
                        )}
                        <button
                            onClick={(e) => { e.stopPropagation(); onDelete(); }}
                            className="p-1.5 rounded-full bg-black/50 text-white/70 hover:text-white">
                            <X className="w-3.5 h-3.5" />
                        </button>
                    </div>
                )}
                {images[currentIndex]?.url === coverUrl && (
                    <div className="absolute top-2 left-2 px-2 py-0.5 rounded-full bg-black/50 text-white/80 text-[10px] font-medium">
                        Cover
                    </div>
                )}
            </div>

            {/* Dots */}
            {hasMultiple && (
                <div className="flex items-center justify-center gap-1.5 py-2.5">
                    {images.map((_, i) => (
                        <button
                            key={i}
                            onClick={() => goTo(i)}
                            className={`h-1.5 rounded-full transition-all duration-300 ${
                                i === currentIndex ? 'bg-[#8B7355] w-5' : 'bg-foreground/15 w-1.5 hover:bg-foreground/30'
                            }`}
                        />
                    ))}
                </div>
            )}

            {/* Caption */}
            {images[currentIndex].caption && (
                <p className="text-xs text-foreground/35 italic font-serif text-center px-4 pb-1">
                    {images[currentIndex].caption}
                </p>
            )}
        </div>
    );
}


// ── Location Block ────────────────────────────────────────

function LocationBlock({ block }: { block: Block }) {
    if (!block.locationName && block.latitude == null) return null;

    const isUrl = block.text && /^https?:\/\//i.test(block.text);

    return (
        <div className="flex items-center gap-2 py-3">
            <div className="w-7 h-7 rounded-full bg-[#8B7355] text-paper flex items-center justify-center flex-shrink-0">
                <MapPin className="w-3.5 h-3.5" />
            </div>
            <div className="min-w-0">
                <span className="text-sm font-display text-foreground/50">
                    {block.locationName || `${block.latitude?.toFixed(2)}, ${block.longitude?.toFixed(2)}`}
                </span>
                {isUrl && (
                    <a
                        href={block.text!}
                        target="_blank"
                        rel="noopener noreferrer"
                        className="block text-xs text-[#8B7355]/60 hover:text-[#8B7355] font-serif truncate transition-colors"
                    >
                        {block.text!.replace(/^https?:\/\/(www\.)?/, '').split('/')[0]}
                    </a>
                )}
            </div>
        </div>
    );
}


// ── Image Upload Trigger ──────────────────────────────────

function ImageUploadBlock({ journeyId, order, onDone }: {
    journeyId: string; order: number; onDone: () => void;
}) {
    const [uploading, setUploading] = useState(false);
    const [showArchive, setShowArchive] = useState(false);
    const fileRef = useRef<HTMLInputElement>(null);

    const handleUpload = async (file: File) => {
        setUploading(true);
        const formData = new FormData();
        formData.append('file', file);
        formData.append('order', String(order));
        try {
            await fetch(apiUrl(`/api/journeys/${journeyId}/blocks`), { method: 'POST', body: formData });
            onDone();
        } catch (e) {
            console.error('Upload error:', e);
        } finally {
            setUploading(false);
        }
    };

    const handleArchive = async (photoIds: string[]) => {
        setShowArchive(false);
        if (photoIds.length === 1) {
            // Single photo → image block
            await fetch(apiUrl(`/api/journeys/${journeyId}/blocks`), {
                method: 'POST',
                headers: { 'Content-Type': 'application/json' },
                body: JSON.stringify({ type: 'image', photoId: photoIds[0], order }),
            });
        } else if (photoIds.length > 1) {
            // Multiple photos → gallery block
            await fetch(apiUrl(`/api/journeys/${journeyId}/blocks`), {
                method: 'POST',
                headers: { 'Content-Type': 'application/json' },
                body: JSON.stringify({ type: 'gallery', photoIds, order }),
            });
        }
        onDone();
    };

    return (
        <>
            <div className="-mx-4 sm:-mx-0">
                <div className="aspect-[3/2] bg-foreground/3 sm:rounded-xl border-2 border-dashed border-foreground/10
                                flex flex-col items-center justify-center gap-3">
                    {uploading ? (
                        <Loader2 className="w-6 h-6 text-foreground/30 animate-spin" />
                    ) : (
                        <>
                            <div className="flex gap-2">
                                <button onClick={() => fileRef.current?.click()}
                                    className="flex items-center gap-1.5 px-4 py-2 rounded-lg text-sm
                                               bg-foreground/5 text-foreground/50 hover:bg-foreground/10 transition-colors">
                                    <Camera className="w-4 h-4" /> Upload
                                </button>
                                <button onClick={() => setShowArchive(true)}
                                    className="flex items-center gap-1.5 px-4 py-2 rounded-lg text-sm
                                               bg-foreground/5 text-foreground/50 hover:bg-foreground/10 transition-colors">
                                    <ImagePlus className="w-4 h-4" /> Archive
                                </button>
                            </div>
                            <p className="text-xs text-foreground/20 font-serif italic">Add a photo</p>
                        </>
                    )}
                </div>
            </div>
            <input ref={fileRef} type="file" accept="image/*" className="hidden"
                onChange={e => e.target.files?.[0] && handleUpload(e.target.files[0])} />
            {showArchive && (
                <ArchivePhotoPicker onSelect={handleArchive} onClose={() => setShowArchive(false)} />
            )}
        </>
    );
}


// ── Main Component ────────────────────────────────────────

export default function JourneyDetail({ journeyId, onBack, canEdit }: JourneyDetailProps) {
    const [journey, setJourney] = useState<JourneyFull | null>(null);
    const [loading, setLoading] = useState(true);
    const [showEditMeta, setShowEditMeta] = useState(false);

    // Pending image blocks (just added, need upload)
    const [pendingImageAt, setPendingImageAt] = useState<number | null>(null);

    // Lightbox
    const [lightboxPhotos, setLightboxPhotos] = useState<Block[]>([]);
    const [lightboxIndex, setLightboxIndex] = useState(0);
    const [showLightbox, setShowLightbox] = useState(false);

    const fetchJourney = useCallback(async () => {

        try {
            const res = await fetch(apiUrl(`/api/journeys/${journeyId}`));
            if (res.ok) {
                const data = await res.json();
                setJourney(data);
            }
        } catch (error) {
            console.error('Failed to fetch journey:', error);
        } finally {
            setLoading(false);
        }
    }, [journeyId]);

    useEffect(() => { fetchJourney(); }, [fetchJourney]);

    // ── Block CRUD ──

    const addBlock = async (type: 'text' | 'image' | 'location', afterOrder: number) => {

        const order = afterOrder + 1;

        if (type === 'image') {
            setPendingImageAt(order);
            return;
        }

        try {
            await fetch(apiUrl(`/api/journeys/${journeyId}/blocks`), {
                method: 'POST',
                headers: { 'Content-Type': 'application/json' },
                body: JSON.stringify({ type, order }),
            });
            fetchJourney();
        } catch (e) {
            console.error('Add block error:', e);
        }
    };

    const updateBlock = async (blockId: string, text: string) => {

        try {
            await fetch(apiUrl(`/api/journeys/${journeyId}/blocks/${blockId}`), {
                method: 'PUT',
                headers: { 'Content-Type': 'application/json' },
                body: JSON.stringify({ text }),
            });
        } catch (e) {
            console.error('Update block error:', e);
        }
    };

    const deleteBlock = async (blockId: string) => {

        try {
            await fetch(apiUrl(`/api/journeys/${journeyId}/blocks/${blockId}`), { method: 'DELETE' });
            fetchJourney();
        } catch (e) {
            console.error('Delete block error:', e);
        }
    };

    const setCoverPhoto = async (imageUrl: string) => {
        try {
            await fetch(apiUrl(`/api/journeys/${journeyId}`), {
                method: 'PUT',
                headers: { 'Content-Type': 'application/json' },
                body: JSON.stringify({ coverPhotoUrl: imageUrl }),
            });
            fetchJourney();
        } catch (e) {
            console.error('Set cover error:', e);
        }
    };

    const handleDeleteJourney = async () => {
        if (!confirm('Delete this journey?')) return;
        await fetch(apiUrl(`/api/journeys/${journeyId}`), { method: 'DELETE' });
        onBack();
    };

    const openLightbox = (block: Block) => {
        if (!journey) return;
        const imageBlocks = journey.blocks.filter(b => b.type === 'image' && b.imageUrl);
        const idx = imageBlocks.findIndex(b => b.id === block.id);
        if (idx >= 0) {
            setLightboxPhotos(imageBlocks);
            setLightboxIndex(idx);
            setShowLightbox(true);
        }
    };

    const openGalleryLightbox = (block: Block, startIndex: number) => {
        let images: GalleryImage[] = [];
        try { images = block.images ? JSON.parse(block.images) : []; } catch { /* */ }
        if (images.length === 0) return;
        // Convert gallery images to fake blocks for the lightbox
        const fakeBlocks: Block[] = images.map((img, i) => ({
            id: `${block.id}-${i}`,
            type: 'image' as const,
            text: img.caption,
            imageUrl: img.url,
            filename: null,
            images: null,
            photoId: img.photoId,
            latitude: null,
            longitude: null,
            locationName: null,
            order: i,
        }));
        setLightboxPhotos(fakeBlocks);
        setLightboxIndex(startIndex);
        setShowLightbox(true);
    };

    // ── Render ──

    if (loading) {
        return (
            <div className="flex flex-col items-center justify-center py-20 gap-4">
                <div className="w-6 h-6 border-2 border-foreground/20 border-t-foreground/60 rounded-full animate-spin" />
                <p className="text-sm text-foreground/30 italic font-serif">Loading journey...</p>
            </div>
        );
    }

    if (!journey) {
        return (
            <div className="text-center py-20">
                <p className="text-foreground/40 font-display">Journey not found</p>
                <button onClick={onBack} className="mt-4 text-sm text-foreground/50 underline">Go back</button>
            </div>
        );
    }

    const formatDate = (dateStr: string | null) => {
        if (!dateStr) return null;
        return new Date(dateStr).toLocaleDateString('en-US', { month: 'long', day: 'numeric', year: 'numeric' });
    };

    const blocks = journey.blocks;

    return (
        <>
            <div className="space-y-0">
                {/* ── Top bar ── */}
                <div className="flex items-center justify-between mb-6">
                    <button onClick={onBack}
                        className="p-1.5 rounded-lg hover:bg-foreground/5 text-foreground/40 hover:text-foreground transition-colors">
                        <ArrowLeft className="w-5 h-5" />
                    </button>
                    {canEdit && (
                        <div className="flex gap-1">
                            <button onClick={() => setShowEditMeta(true)}
                                className="p-1.5 rounded-lg hover:bg-foreground/5 text-foreground/30 hover:text-foreground">
                                <Edit2 className="w-4 h-4" />
                            </button>
                            <button onClick={handleDeleteJourney}
                                className="p-1.5 rounded-lg hover:bg-red-50 text-foreground/30 hover:text-red-500">
                                <Trash2 className="w-4 h-4" />
                            </button>
                        </div>
                    )}
                </div>

                {/* ── Title ── */}
                <div className="mb-8">
                    <h1 className="font-display text-3xl leading-tight tracking-tight">
                        {journey.title}
                    </h1>
                    <div className="flex items-center gap-3 mt-2 text-sm text-foreground/40">
                        {journey.user.name && <span className="font-serif italic">by {journey.user.name}</span>}
                        {journey.startDate && (
                            <>
                                <span className="text-foreground/15">|</span>
                                <span>
                                    {formatDate(journey.startDate)}
                                    {journey.endDate && ` — ${formatDate(journey.endDate)}`}
                                </span>
                            </>
                        )}
                    </div>
                </div>

                {/* ── Blocks ── */}
                <div className="space-y-5">
                    {blocks.map((block, idx) => (
                        <div key={block.id}>
                            <motion.div
                                initial={{ opacity: 0, y: 12 }}
                                whileInView={{ opacity: 1, y: 0 }}
                                viewport={{ once: true, margin: '-40px' }}
                                transition={{ duration: 0.4, ease: [0.25, 1, 0.5, 1] }}
                            >
                                {block.type === 'text' && (
                                    <TextBlock
                                        block={block}
                                        editing={canEdit}
                                        onUpdate={(text) => updateBlock(block.id, text)}
                                        onDelete={() => deleteBlock(block.id)}
                                    />
                                )}
                                {block.type === 'image' && (
                                    <ImageBlock
                                        block={block}
                                        editing={canEdit}
                                        isCover={block.imageUrl === journey.coverPhotoUrl}
                                        onDelete={() => deleteBlock(block.id)}
                                        onOpenLightbox={() => openLightbox(block)}
                                        onSetCover={() => block.imageUrl && setCoverPhoto(block.imageUrl)}
                                    />
                                )}
                                {block.type === 'gallery' && (
                                    <GalleryBlock
                                        block={block}
                                        editing={canEdit}
                                        coverUrl={journey.coverPhotoUrl}
                                        onDelete={() => deleteBlock(block.id)}
                                        onOpenLightbox={(idx) => openGalleryLightbox(block, idx)}
                                        onSetCover={(url) => setCoverPhoto(url)}
                                    />
                                )}
                                {block.type === 'location' && (
                                    <LocationBlock block={block} />
                                )}
                            </motion.div>

                            {/* Add block between */}
                            {canEdit && (
                                <BlockAdder onAdd={(type) => addBlock(type, block.order)} />
                            )}

                            {/* Pending image upload */}
                            {pendingImageAt === block.order + 1 && (
                                <ImageUploadBlock
                                    journeyId={journeyId}
                                    order={block.order + 1}
                                    onDone={() => { setPendingImageAt(null); fetchJourney(); }}
                                />
                            )}
                        </div>
                    ))}
                </div>

                {/* ── Empty state / first block ── */}
                {blocks.length === 0 && canEdit && (
                    <div className="py-8 space-y-4">
                        <p className="text-center text-sm text-foreground/25 font-serif italic">Start telling your story</p>
                        <div className="flex items-center justify-center gap-2">
                            <button onClick={() => addBlock('text', -1)}
                                className="flex items-center gap-1.5 px-4 py-2.5 rounded-lg text-sm bg-foreground/5 text-foreground/50 hover:bg-foreground/10 transition-colors">
                                <Type className="w-4 h-4" /> Add Text
                            </button>
                            <button onClick={() => addBlock('image', -1)}
                                className="flex items-center gap-1.5 px-4 py-2.5 rounded-lg text-sm bg-foreground/5 text-foreground/50 hover:bg-foreground/10 transition-colors">
                                <ImageIcon className="w-4 h-4" /> Add Photo
                            </button>
                            <button onClick={() => addBlock('location', -1)}
                                className="flex items-center gap-1.5 px-4 py-2.5 rounded-lg text-sm bg-foreground/5 text-foreground/50 hover:bg-foreground/10 transition-colors">
                                <MapPin className="w-4 h-4" /> Add Location
                            </button>
                        </div>
                    </div>
                )}

                {blocks.length === 0 && !canEdit && (
                    <div className="text-center py-12">
                        <p className="text-foreground/25 font-serif italic">This journey has no content yet.</p>
                    </div>
                )}

                {/* Pending image at the end (when adding to empty or appending) */}
                {pendingImageAt !== null && blocks.length === 0 && (
                    <ImageUploadBlock
                        journeyId={journeyId}
                        order={0}
                        onDone={() => { setPendingImageAt(null); fetchJourney(); }}
                    />
                )}

                {/* ── Trailing add button for appending ── */}
                {canEdit && blocks.length > 0 && (
                    <div className="flex items-center justify-center gap-2 pt-6 pb-2">
                        <button onClick={() => addBlock('text', blocks[blocks.length - 1].order)}
                            className="flex items-center gap-1 px-3 py-1.5 rounded-lg text-xs bg-foreground/5 text-foreground/35 hover:bg-foreground/10 transition-colors">
                            <Type className="w-3 h-3" /> Text
                        </button>
                        <button onClick={() => addBlock('image', blocks[blocks.length - 1].order)}
                            className="flex items-center gap-1 px-3 py-1.5 rounded-lg text-xs bg-foreground/5 text-foreground/35 hover:bg-foreground/10 transition-colors">
                            <ImageIcon className="w-3 h-3" /> Photo
                        </button>
                        <button onClick={() => addBlock('location', blocks[blocks.length - 1].order)}
                            className="flex items-center gap-1 px-3 py-1.5 rounded-lg text-xs bg-foreground/5 text-foreground/35 hover:bg-foreground/10 transition-colors">
                            <MapPin className="w-3 h-3" /> Location
                        </button>
                    </div>
                )}

                {/* ── Fin ── */}
                {blocks.length > 0 && (
                    <div className="pt-10 pb-6">
                        <div className="flex items-center justify-center gap-4">
                            <div className="h-px w-12 bg-foreground/10" />
                            <span className="text-xl font-script text-foreground/15">fin</span>
                            <div className="h-px w-12 bg-foreground/10" />
                        </div>
                    </div>
                )}

                {/* ── Map with all locations ── */}
                {(() => {
                    const locationBlocks = blocks.filter(
                        b => b.type === 'location' && (b.latitude != null || b.locationName)
                    );
                    const hasCoords = locationBlocks.some(b => b.latitude != null && b.longitude != null);
                    if (!hasCoords) return null;

                    const mapStops = locationBlocks
                        .filter(b => b.latitude != null && b.longitude != null)
                        .map((b, i) => ({
                            id: b.id,
                            title: b.locationName || `Location ${i + 1}`,
                            locationName: b.locationName,
                            latitude: b.latitude,
                            longitude: b.longitude,
                            order: i,
                        }));

                    return (
                        <div className="pt-2 pb-8">
                            <JourneyMap
                                stops={mapStops}
                                height="280px"
                                className="border border-foreground/10"
                            />
                        </div>
                    );
                })()}
            </div>

            {/* ── Modals ── */}
            {showEditMeta && (
                <JourneyForm
                    journey={journey}
                    onSave={() => { setShowEditMeta(false); fetchJourney(); }}
                    onCancel={() => setShowEditMeta(false)}
                />
            )}

            {showLightbox && lightboxPhotos[lightboxIndex] && (
                <Lightbox
                    photo={{
                        id: lightboxPhotos[lightboxIndex].id,
                        url: lightboxPhotos[lightboxIndex].imageUrl!,
                        filename: lightboxPhotos[lightboxIndex].filename || '',
                        caption: lightboxPhotos[lightboxIndex].text,
                        rollId: '', order: 0, createdAt: new Date(),
                        dateTaken: null, location: null, people: null, circa: false,
                        latitude: lightboxPhotos[lightboxIndex].latitude,
                        longitude: lightboxPhotos[lightboxIndex].longitude,
                    } as Photo}
                    onClose={() => setShowLightbox(false)}
                    onNext={() => setLightboxIndex(i => Math.min(i + 1, lightboxPhotos.length - 1))}
                    onPrev={() => setLightboxIndex(i => Math.max(i - 1, 0))}
                    hasNext={lightboxIndex < lightboxPhotos.length - 1}
                    hasPrev={lightboxIndex > 0}
                />
            )}
        </>
    );
}
