﻿'use client';

import { useState, useMemo, useEffect, useCallback } from 'react';
import { Card, CardContent } from '@/components/ui/card';
import { Badge } from '@/components/ui/badge';
import { Button } from '@/components/ui/button';
import {
  LayoutGrid,
  Heart,
  Download,
  Brush,
  ImagePlus,
  Video,
  Film,
  X,
  Clock,
  Cpu,
  Sparkles,
  Image as ImageIcon,
  MessageSquare,
  Copy,
  Maximize2,
  ArrowLeft,
  Trash2,
  Search,
} from 'lucide-react';
import { copyTextToClipboard, downloadFile } from '@/lib/utils';
import { usePublishedWorks, useCreationHistory, syncPublishedToSupabase, type PublishedWork } from '@/lib/creation-history-store';
import { useAuth } from '@/lib/auth-store';
import { FullscreenPreview } from '@/components/fullscreen-preview';
import { toast } from 'sonner';

const CATEGORIES = [
  { value: 'all', label: '全部', icon: LayoutGrid },
  { value: 'text2img', label: '文生图', icon: Brush },
  { value: 'img2img', label: '图生图', icon: ImagePlus },
  { value: 'text2video', label: '文生视频', icon: Video },
  { value: 'img2video', label: '图生视频', icon: Film },
];

/* ---------- Gallery Work (from API) ---------- */
interface GalleryWork {
  id: string;
  type: string;
  title?: string | null;
  prompt?: string | null;
  negativePrompt?: string | null;
  url: string;
  thumbnailUrl?: string | null;
  width?: number | null;
  height?: number | null;
  duration?: number | null;
  likes: number;
  creditsCost?: number | null;
  params: Record<string, unknown>;
  referenceImage?: string | null;
  referenceImages?: string[];
  publisherId: string;
  publisherNickname: string;
  publisherAvatarUrl?: string | null;
  publishedAt: string;
}

function getCategoryFromWork(work: GalleryWork): string {
  const mode = work.params?.creationMode || work.params?.workType || work.params?.mode;
  if (
    mode === 'text2img' ||
    mode === 'img2img' ||
    mode === 'text2video' ||
    mode === 'img2video'
  ) {
    return mode;
  }
  if (work.type === 'text2video' || work.type === 'img2video') {
    return work.type;
  }
  if (work.type === 'img2img') return work.type;
  const hasReference =
    Boolean(work.referenceImage) ||
    (Array.isArray(work.referenceImages) && work.referenceImages.length > 0) ||
    Boolean(work.params?.referenceImage) ||
    (Array.isArray(work.params?.referenceImages) && work.params.referenceImages.length > 0);
  // Fallback: infer from type + referenceImage
  if (work.type === 'video' || work.duration) {
    return hasReference ? 'img2video' : 'text2video';
  }
  return hasReference ? 'img2img' : 'text2img';
}

function getCategoryLabel(work: GalleryWork): string {
  const cat = CATEGORIES.find(c => c.value === getCategoryFromWork(work));
  return cat?.label ?? work.type;
}

function formatDate(iso: string): string {
  try {
    return new Date(iso).toLocaleDateString('zh-CN', {
      year: 'numeric',
      month: 'short',
      day: 'numeric',
      hour: '2-digit',
      minute: '2-digit',
    });
  } catch {
    return iso;
  }
}

function getAvatarText(nickname: string): string {
  const trimmed = nickname.trim();
  return trimmed ? trimmed.slice(0, 1).toUpperCase() : '匿';
}

function getWorkReferenceImages(work: GalleryWork): string[] {
  const fromArray = Array.isArray(work.referenceImages) ? work.referenceImages : [];
  const fromParams = Array.isArray(work.params?.referenceImages)
    ? (work.params.referenceImages as unknown[]).filter((item): item is string => typeof item === 'string' && item.trim().length > 0)
    : [];
  const single = typeof work.referenceImage === 'string' && work.referenceImage.trim()
    ? [work.referenceImage]
    : typeof work.params?.referenceImage === 'string' && work.params.referenceImage.trim()
      ? [work.params.referenceImage]
      : [];
  return [...new Set([...single, ...fromArray, ...fromParams].filter(url => url && !url.startsWith('data:') && !url.startsWith('[')))];
}

async function copyGalleryText(text: string, successMessage: string) {
  const copied = await copyTextToClipboard(text);
  if (copied) {
    toast.success(successMessage);
  } else {
    toast.error('复制失败，请手动选择文本复制');
  }
}

function getCreateUrlForCategory(category: string): string {
  const type = category === 'img2img' || category === 'text2video' || category === 'img2video'
    ? category
    : 'text2img';
  return `/create?type=${type}`;
}

type MediaSize = { width: number; height: number };

function getEstimatedWorkHeight(work: GalleryWork, measuredSize?: MediaSize): number {
  const width = Number(measuredSize?.width || work.width || 0);
  const height = Number(measuredSize?.height || work.height || 0);
  const imageHeight = width > 0 && height > 0 ? Math.max(120, (height / width) * 320) : 320;
  return imageHeight + 152 + 16;
}

const galleryGlassPanel =
  'liquid-glass';
const galleryGlassCard =
  'liquid-surface';
const galleryGlassBlock =
  'rounded-xl border border-border bg-card/40';
const detailGlassBlock =
  'rounded-xl border border-white/[0.08] bg-[#12161d]/82 shadow-[inset_0_1px_0_rgba(255,255,255,0.045),0_16px_36px_rgba(0,0,0,0.18)] backdrop-blur-xl light:border-amber-900/18 light:bg-white/36 light:text-foreground light:shadow-[inset_0_1px_0_rgba(255,255,255,0.70),0_16px_40px_rgba(83,61,27,0.12)]';
const detailGlassInner =
  'rounded-md border border-white/[0.07] bg-[#0d1219]/80 light:border-amber-900/16 light:bg-white/32';
const galleryMenuItemClass =
  'inline-flex h-10 cursor-pointer items-center gap-2.5 rounded-xl border border-transparent px-5 text-base font-semibold leading-none text-foreground/75 transition-colors hover:bg-white/[0.035]';
const galleryMenuItemActiveClass =
  'border-transparent bg-white/[0.075] text-primary shadow-[inset_0_1px_0_rgba(255,255,255,0.12),0_0_18px_rgba(244,166,36,0.18),0_6px_18px_rgba(0,0,0,0.18)] [&_svg]:text-primary';

export default function GalleryPage() {
  const [apiWorks, setApiWorks] = useState<GalleryWork[]>([]);
  const [loading, setLoading] = useState(true);
  const [syncStatus, setSyncStatus] = useState<'idle' | 'syncing' | 'done'>('idle');
  const [category, setCategory] = useState('all');
  const [likedIds, setLikedIds] = useState<Set<string>>(new Set());
  const [selectedWork, setSelectedWork] = useState<GalleryWork | null>(null);
  const [fullscreenSrc, setFullscreenSrc] = useState<string | null>(null);
  const [sortBy, setSortBy] = useState<'newest' | 'popular'>('newest');
  const [searchQuery, setSearchQuery] = useState('');
  const [masonryColumnCount, setMasonryColumnCount] = useState(4);
  const [measuredMediaSizes, setMeasuredMediaSizes] = useState<Record<string, MediaSize>>({});
  const [selectedGalleryIds, setSelectedGalleryIds] = useState<Set<string>>(new Set());

  useEffect(() => {
    const updateColumnCount = () => {
      const width = window.innerWidth;
      if (width >= 1280) setMasonryColumnCount(4);
      else if (width >= 1024) setMasonryColumnCount(3);
      else if (width >= 640) setMasonryColumnCount(2);
      else setMasonryColumnCount(1);
    };

    updateColumnCount();
    window.addEventListener('resize', updateColumnCount);
    return () => window.removeEventListener('resize', updateColumnCount);
  }, []);

  // ESC to close detail overlay
  useEffect(() => {
    if (!selectedWork) return;
    const handler = (e: KeyboardEvent) => { if (e.key === 'Escape') setSelectedWork(null); };
    window.addEventListener('keydown', handler);
    return () => window.removeEventListener('keydown', handler);
  }, [selectedWork]);

  // Prevent body scroll when detail is open
  useEffect(() => {
    if (selectedWork) {
      document.body.style.overflow = 'hidden';
    } else {
      document.body.style.overflow = '';
    }
    return () => { document.body.style.overflow = ''; };
  }, [selectedWork]);
  const { works: localPublished } = usePublishedWorks();
  const { records: creationHistory } = useCreationHistory();
  const { user, accessToken, isAdmin } = useAuth();

  // Fetch works from API, after syncing localStorage to Supabase
  const fetchWorks = useCallback(async () => {
    setLoading(true);
    try {
      const params = new URLSearchParams({ sort: sortBy, limit: '300' });
      if (searchQuery.trim()) params.set('q', searchQuery.trim());
      const res = await fetch(`/api/gallery?${params.toString()}`);
      if (res.ok) {
        const data = await res.json();
        setApiWorks(data.works || []);
      }
    } catch { /* ignore */ }
    setLoading(false);
  }, [sortBy, searchQuery]);

  // Sync localStorage to Supabase on first mount only
  useEffect(() => {
    setSyncStatus('syncing');
    syncPublishedToSupabase().then(synced => {
      setSyncStatus('done');
      if (synced > 0) {
        // Re-fetch after sync to show newly synced works
        fetchWorks();
      }
    }).catch(() => {
      setSyncStatus('done');
    });
  // eslint-disable-next-line react-hooks/exhaustive-deps
  }, []);

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

  // Merge API works with localStorage published works + published creation history
  // This ensures previously shared works are visible even if not yet in Supabase
  const works = useMemo(() => {
    const apiUrls = new Set(apiWorks.map(w => w.url));

    // From localStorage published gallery
    const localAsGallery: GalleryWork[] = localPublished
      .filter(w => !apiUrls.has(w.url))
      .map(w => ({
        id: w.id,
        type: w.type === 'video' ? (w.referenceImage ? 'img2video' : 'text2video') : (w.referenceImage ? 'img2img' : 'text2img'),
        title: null,
        prompt: w.prompt,
        negativePrompt: w.negativePrompt,
        url: w.url,
        thumbnailUrl: null,
        width: null,
        height: null,
        duration: null,
        likes: w.likes || 0,
        creditsCost: null,
        params: { model: w.model, modelLabel: w.modelLabel, ...w.params },
        referenceImage: w.referenceImage,
        referenceImages: w.referenceImages,
        publisherId: w.publisherId,
        publisherNickname: w.publisherNickname,
        publisherAvatarUrl: null,
        publishedAt: w.publishedAt,
      }));

    // From creation history records marked as published
    const existingUrls = new Set([...apiUrls, ...localAsGallery.map(w => w.url)]);
    const historyPublished: GalleryWork[] = creationHistory
      .filter(r => r.published && r.url && !existingUrls.has(r.url) && !r.url.startsWith('data:') && !r.url.startsWith('['))
      .map(r => ({
        id: r.id,
        type: r.type === 'video' ? (r.referenceImage ? 'img2video' : 'text2video') : (r.referenceImage ? 'img2img' : 'text2img'),
        title: null,
        prompt: r.prompt,
        negativePrompt: r.negativePrompt,
        url: r.url,
        thumbnailUrl: null,
        width: null,
        height: null,
        duration: null,
        likes: 0,
        creditsCost: null,
        params: { model: r.model, modelLabel: r.modelLabel, ...r.params },
        referenceImage: r.referenceImage,
        referenceImages: r.referenceImages,
        publisherId: user?.id || 'anonymous',
        publisherNickname: user?.nickname || user?.email?.split('@')[0] || '匿名用户',
        publisherAvatarUrl: user?.avatarUrl || null,
        publishedAt: r.createdAt,
      }));

    return [...apiWorks, ...localAsGallery, ...historyPublished];
  }, [apiWorks, localPublished, creationHistory, user]);

  const filteredWorks = useMemo(() => {
    const query = searchQuery.trim().toLowerCase();
    return works.filter(work => {
      if (category !== 'all' && getCategoryFromWork(work) !== category) return false;
      if (!query) return true;
      const haystack = [
        work.title,
        work.prompt,
        work.negativePrompt,
        work.publisherNickname,
        work.params?.model,
        work.params?.modelLabel,
        work.type,
      ].map(value => String(value || '').toLowerCase()).join('\n');
      return haystack.includes(query);
    });
  }, [works, category, searchQuery]);

  const apiWorkIds = useMemo(() => new Set(apiWorks.map(work => work.id)), [apiWorks]);

  const handleCardImageLoad = useCallback((workId: string, e: React.SyntheticEvent<HTMLImageElement>) => {
    const img = e.currentTarget;
    if (img.naturalWidth <= 0 || img.naturalHeight <= 0) return;

    setMeasuredMediaSizes(prev => {
      const current = prev[workId];
      if (current?.width === img.naturalWidth && current?.height === img.naturalHeight) {
        return prev;
      }
      return {
        ...prev,
        [workId]: { width: img.naturalWidth, height: img.naturalHeight },
      };
    });
  }, []);

  const masonryColumns = useMemo(() => {
    const columns = Array.from({ length: masonryColumnCount }, () => [] as GalleryWork[]);
    const columnHeights = Array.from({ length: masonryColumnCount }, () => 0);
    filteredWorks.forEach((work) => {
      const targetIndex = columnHeights.indexOf(Math.min(...columnHeights));
      columns[targetIndex].push(work);
      columnHeights[targetIndex] += getEstimatedWorkHeight(work, measuredMediaSizes[work.id]);
    });
    return columns;
  }, [filteredWorks, masonryColumnCount, measuredMediaSizes]);

  const selectedReferenceImages = useMemo(
    () => selectedWork ? getWorkReferenceImages(selectedWork) : [],
    [selectedWork],
  );

  const toggleLike = (id: string, e?: React.MouseEvent) => {
    e?.stopPropagation();
    if (likedIds.has(id)) return;
    setLikedIds(prev => new Set(prev).add(id));
  };

  const handleDownload = async (url: string, filename: string, e?: React.MouseEvent) => {
    e?.stopPropagation();
    const result = await downloadFile(url, filename);
    if (!result.ok) {
      window.open(url, '_blank');
    }
  };

  const toggleSelectGalleryWork = (id: string, e?: React.MouseEvent) => {
    e?.stopPropagation();
    setSelectedGalleryIds(prev => {
      const next = new Set(prev);
      if (next.has(id)) next.delete(id);
      else next.add(id);
      return next;
    });
  };

  const handleDeleteGalleryWorks = async (ids: string[], e?: React.MouseEvent) => {
    e?.stopPropagation();
    const targetIds = ids.filter(id => apiWorkIds.has(id));
    if (targetIds.length === 0) {
      toast.error('没有可删除的服务器画廊作品');
      return;
    }
    const confirmed = window.confirm(targetIds.length === 1 ? '确认从画廊移除这个作品？' : `确认从画廊批量移除 ${targetIds.length} 个作品？`);
    if (!confirmed) return;

    try {
      const res = await fetch('/api/gallery', {
        method: 'DELETE',
        headers: {
          'Content-Type': 'application/json',
          ...(accessToken ? { Authorization: `Bearer ${accessToken}` } : {}),
        },
        body: JSON.stringify({ ids: targetIds }),
      });
      const data = await res.json().catch(() => ({}));
      if (!res.ok) {
        throw new Error(data.error || '删除失败');
      }
      const removedIds = new Set<string>((data.ids || targetIds) as string[]);
      setApiWorks(prev => prev.filter(work => !removedIds.has(work.id)));
      setSelectedGalleryIds(prev => new Set([...prev].filter(id => !removedIds.has(id))));
      if (selectedWork && removedIds.has(selectedWork.id)) {
        setSelectedWork(null);
      }
      toast.success(`已从画廊移除 ${data.removed ?? removedIds.size} 个作品`);
    } catch (err) {
      toast.error(err instanceof Error ? err.message : '删除失败');
    }
  };

  return (
    <div className="min-h-screen bg-background">
      <div className="mx-auto max-w-7xl px-4 sm:px-6 py-8">
        {/* Header */}
        <div className="mb-8">
          <div className="flex items-center gap-3">
            <h1 className="font-serif text-3xl font-bold">作品画廊</h1>
            {syncStatus === 'syncing' && (
              <span className="text-xs text-muted-foreground animate-pulse">同步本地数据...</span>
            )}
          </div>
          <p className="mt-2 text-muted-foreground">探索社区创作，发现灵感之美</p>
        </div>

        <div className={`${galleryGlassPanel} mb-4 flex items-center gap-2.5 rounded-2xl px-4 py-2`}>
          <Search className="h-4 w-4 shrink-0 text-muted-foreground" />
          <input
            value={searchQuery}
            onChange={(event) => setSearchQuery(event.target.value)}
            placeholder="搜索作品、用户、提示词、模型"
            className="h-8 min-w-0 flex-1 bg-transparent text-sm font-medium outline-none placeholder:text-muted-foreground/70"
          />
          {searchQuery && (
            <button
              onClick={() => setSearchQuery('')}
              className="flex h-7 w-7 items-center justify-center rounded-full text-muted-foreground transition-colors hover:bg-white/10 hover:text-foreground"
            >
              <X className="h-3.5 w-3.5" />
            </button>
          )}
        </div>

        {/* Filters */}
        <div className={`${galleryGlassPanel} mb-8 flex min-h-12 flex-col items-start justify-between gap-4 rounded-2xl p-1 sm:flex-row sm:items-center`}>
          <div className="flex flex-wrap gap-2">
            {CATEGORIES.map((cat) => {
              const Icon = cat.icon;
              return (
                <button
                  key={cat.value}
                  className={`${galleryMenuItemClass} ${category === cat.value ? galleryMenuItemActiveClass : ''}`}
                  onClick={() => setCategory(cat.value)}
                >
                  <Icon className="h-3.5 w-3.5" />
                  {cat.label}
                </button>
              );
            })}
          </div>
          <div className="flex flex-wrap gap-2">
            <button
              className={`${galleryMenuItemClass} ${sortBy === 'newest' ? galleryMenuItemActiveClass : ''}`}
              onClick={() => setSortBy('newest')}
            >
              最新发布
            </button>
            <button
              className={`${galleryMenuItemClass} ${sortBy === 'popular' ? galleryMenuItemActiveClass : ''}`}
              onClick={() => setSortBy('popular')}
            >
              最受欢迎
            </button>
            {isAdmin && selectedGalleryIds.size > 0 && (
              <Button
                size="sm"
                variant="destructive"
                className="h-10 rounded-xl px-4 text-sm font-semibold"
                onClick={(e) => handleDeleteGalleryWorks([...selectedGalleryIds], e)}
              >
                <Trash2 className="mr-2 h-4 w-4" />
                批量删除 {selectedGalleryIds.size}
              </Button>
            )}
          </div>
        </div>

        {/* Gallery Grid */}
        {loading ? (
          <div className="flex flex-col items-center justify-center py-24 text-muted-foreground">
            <Sparkles className="h-12 w-12 mb-4 animate-pulse opacity-30" />
            <p className="text-lg font-serif">加载中...</p>
          </div>
        ) : filteredWorks.length === 0 ? (
          <div className="flex flex-col items-center justify-center py-24 text-muted-foreground">
            <LayoutGrid className="h-16 w-16 mb-4 opacity-30" />
            <p className="text-lg font-serif">暂无作品</p>
            <p className="text-sm mt-1">创作并发布你的作品，让大家一起欣赏</p>
            <Button
              className="mt-4"
              variant="outline"
              onClick={() => window.location.href = getCreateUrlForCategory(category)}
            >
              <Sparkles className="h-4 w-4 mr-2" />
              前往创作
            </Button>
          </div>
        ) : (
          <div
            className="grid gap-4"
            style={{ gridTemplateColumns: `repeat(${masonryColumnCount}, minmax(0, 1fr))` }}
          >
            {masonryColumns.map((columnWorks, columnIndex) => (
              <div key={columnIndex} className="flex min-w-0 flex-col gap-4">
                {columnWorks.map((work) => (
              <Card
                key={work.id}
                className={`${galleryGlassCard} group w-full overflow-hidden cursor-pointer !rounded-2xl !py-0 transition-all duration-300 hover:border-primary/25 hover:bg-slate-900/[0.52] hover:shadow-[0_18px_52px_rgba(0,0,0,0.34),inset_0_1px_0_rgba(255,255,255,0.075)]`}
                onClick={() => setSelectedWork(work)}
              >
                <div className="relative overflow-hidden bg-black/25">
                  {(work.thumbnailUrl || (work.url && !work.url.startsWith('data:'))) ? (
                    <img
                      src={work.thumbnailUrl || work.url}
                      alt={(work.prompt || '').slice(0, 30)}
                      className="block h-auto w-full object-contain"
                      loading="lazy"
                      onLoad={(e) => handleCardImageLoad(work.id, e)}
                      onDoubleClick={(e) => { e.stopPropagation(); setFullscreenSrc(work.url); }}
                    />
                  ) : (
                    <div className="flex aspect-square w-full flex-col items-center justify-center bg-gradient-to-br from-muted to-muted/50">
                      <Sparkles className="h-8 w-8 text-muted-foreground/20" />
                    </div>
                  )}
                  {isAdmin && apiWorkIds.has(work.id) && (
                    <button
                      className={`absolute left-2 top-2 z-20 flex h-7 w-7 items-center justify-center rounded-lg border text-xs font-semibold backdrop-blur-md transition-colors ${
                        selectedGalleryIds.has(work.id)
                          ? 'border-primary/60 bg-primary text-primary-foreground'
                          : 'border-white/20 bg-black/45 text-white hover:bg-black/65'
                      }`}
                      onClick={(e) => toggleSelectGalleryWork(work.id, e)}
                      title={selectedGalleryIds.has(work.id) ? '取消选择' : '选择作品'}
                    >
                      {selectedGalleryIds.has(work.id) ? '✓' : ''}
                    </button>
                  )}
                  {(work.type === 'video' || work.type === 'text2video' || work.type === 'img2video') && (
                    <Badge className={`absolute left-2 ${isAdmin && apiWorkIds.has(work.id) ? 'top-11' : 'top-2'}`} variant="secondary">
                      <Film className="h-3 w-3 mr-1" />视频
                    </Badge>
                  )}
                  <Badge className="absolute top-2 right-2" variant="secondary">
                    {getCategoryLabel(work)}
                  </Badge>
                  {/* Hover overlay */}
                  <div className="absolute inset-0 bg-black/0 group-hover:bg-black/50 transition-colors flex flex-col items-center justify-center gap-2 opacity-0 group-hover:opacity-100">
                    <p className="text-white text-sm font-serif line-clamp-2 px-4 text-center">
                      {work.prompt}
                    </p>
                    <div className="flex gap-2">
                      <Button
                        size="sm"
                        variant="secondary"
                        className="h-8 w-8 p-0"
                        onClick={(e) => toggleLike(work.id, e)}
                      >
                        <Heart className={`h-4 w-4 ${likedIds.has(work.id) ? 'fill-rose-500 text-rose-500' : ''}`} />
                      </Button>
                      <Button
                        size="sm"
                        variant="secondary"
                        className="h-8 w-8 p-0"
                        onClick={(e) => handleDownload(work.url, `miaojing-${work.id}.png`, e)}
                      >
                        <Download className="h-4 w-4" />
                      </Button>
                      {isAdmin && apiWorkIds.has(work.id) && (
                        <Button
                          size="sm"
                          variant="destructive"
                          className="h-8 w-8 p-0"
                          onClick={(e) => handleDeleteGalleryWorks([work.id], e)}
                          title="从画廊删除"
                        >
                          <Trash2 className="h-4 w-4" />
                        </Button>
                      )}
                    </div>
                  </div>
                </div>
                <CardContent className="flex h-[152px] flex-col p-3">
                  <div className="flex items-center justify-between">
                    <div className="flex min-w-0 items-center gap-2">
                      <div className="flex h-6 w-6 shrink-0 items-center justify-center overflow-hidden rounded-full bg-primary/15 text-xs font-semibold text-primary ring-1 ring-primary/25">
                        {work.publisherAvatarUrl ? (
                          <img
                            src={work.publisherAvatarUrl}
                            alt={work.publisherNickname}
                            className="h-full w-full object-cover"
                            loading="lazy"
                          />
                        ) : (
                          getAvatarText(work.publisherNickname)
                        )}
                      </div>
                      <span className="truncate text-sm font-medium">
                        {work.publisherNickname}
                      </span>
                    </div>
                    <div className="flex items-center gap-1 text-xs text-muted-foreground">
                      <Heart className={`h-3 w-3 ${likedIds.has(work.id) ? 'fill-rose-500 text-rose-500' : ''}`} />
                      {work.likes + (likedIds.has(work.id) ? 1 : 0)}
                    </div>
                  </div>
                  <p className="mt-2 h-[100px] overflow-hidden whitespace-pre-wrap break-words text-xs leading-5 text-muted-foreground line-clamp-5">
                    {work.prompt}
                  </p>
                </CardContent>
              </Card>
                ))}
              </div>
            ))}
          </div>
        )}
      </div>

      {/* Detail - Fullscreen Overlay */}
      {selectedWork && (
        <div
          className="fixed inset-0 z-50 flex items-center justify-center bg-black/60 backdrop-blur-md animate-in fade-in duration-200 light:bg-white/58 light:backdrop-blur-xl"
          onClick={(e) => { if (e.target === e.currentTarget) setSelectedWork(null); }}
        >
          <div className="relative flex h-[96vh] w-[98vw] overflow-hidden rounded-2xl border border-white/[0.08] bg-[#07090d] shadow-[0_28px_80px_rgba(0,0,0,0.55)] light:border-amber-900/18 light:bg-white/30 light:shadow-[0_28px_80px_rgba(83,61,27,0.16),inset_0_1px_0_rgba(255,255,255,0.70)]">
            {selectedWork.url && !selectedWork.url.startsWith('data:') && (
              <>
                  <img
                    src={selectedWork.thumbnailUrl || selectedWork.url}
                    alt=""
                    aria-hidden="true"
                    className="pointer-events-none absolute inset-0 h-full w-full scale-125 object-cover opacity-48 blur-[5px]"
                  />
                <div className="pointer-events-none absolute inset-0 bg-black/42 light:bg-white/38" />
                <div className="pointer-events-none absolute inset-0 bg-[radial-gradient(circle_at_center,rgba(255,255,255,0.015),rgba(0,0,0,0.62))] light:bg-[radial-gradient(circle_at_center,rgba(255,255,255,0.16),rgba(255,248,235,0.54))]" />
                </>
              )}
            {/* Left: Image/Video */}
            <div className="relative z-10 flex min-w-0 flex-1 items-center justify-center overflow-hidden bg-black/22 light:bg-white/12">
              {selectedWork.type === 'video' || selectedWork.type === 'text2video' || selectedWork.type === 'img2video' ? (
                <video
                  src={selectedWork.url}
                  controls
                  className="relative z-10 h-full w-full object-contain"
                />
              ) : (
                <img
                  src={selectedWork.url}
                  alt={(selectedWork.prompt || '').slice(0, 30)}
                  className="relative z-10 h-full w-full cursor-zoom-in object-contain"
                  onDoubleClick={() => setFullscreenSrc(selectedWork.url)}
                />
              )}
              {/* Fullscreen button overlay */}
              {selectedWork.type !== 'video' && selectedWork.type !== 'text2video' && selectedWork.type !== 'img2video' && (
                <button
                  onClick={() => setFullscreenSrc(selectedWork.url)}
                  className="absolute bottom-4 right-4 z-20 flex h-10 w-10 items-center justify-center rounded-full bg-black/50 text-white shadow-lg backdrop-blur-md transition-colors hover:bg-black/70"
                >
                  <Maximize2 className="h-5 w-5 text-white" />
                </button>
              )}
            </div>

            {/* Right: Info Panel */}
            <div className="relative z-10 flex w-[410px] shrink-0 flex-col overflow-hidden border-l border-white/[0.07] bg-[#0a0d12]/74 backdrop-blur-2xl light:border-amber-900/14 light:bg-white/28">
              <div className="pointer-events-none absolute inset-0 bg-gradient-to-r from-[#0a0d12]/46 via-[#0a0d12]/72 to-[#0a0d12]/86 light:from-white/8 light:via-white/24 light:to-white/42" />
              {/* Close header */}
              <div className={`${detailGlassBlock} relative z-10 m-4 mb-0 flex items-center gap-2 px-4 py-3`}>
                <button
                  onClick={() => setSelectedWork(null)}
                  className="flex h-8 w-8 items-center justify-center rounded-full transition-colors hover:bg-white/[0.07]"
                >
                  <ArrowLeft className="h-4 w-4" />
                </button>
                <h2 className="font-serif text-lg font-semibold">作品详情</h2>
                <button
                  onClick={() => setSelectedWork(null)}
                  className="ml-auto flex h-8 w-8 items-center justify-center rounded-full transition-colors hover:bg-white/[0.07]"
                >
                  <X className="h-4 w-4" />
                </button>
              </div>

              <div className="relative z-10 flex min-h-0 flex-1 flex-col gap-4 overflow-hidden p-4">
                {/* Publisher info */}
                <div className={`${detailGlassBlock} flex shrink-0 items-center gap-3 p-4`}>
                  <div className="flex h-11 w-11 shrink-0 items-center justify-center overflow-hidden rounded-full bg-primary/10 text-sm font-semibold text-primary ring-1 ring-primary/25">
                    {selectedWork.publisherAvatarUrl ? (
                      <img
                        src={selectedWork.publisherAvatarUrl}
                        alt={selectedWork.publisherNickname}
                        className="h-full w-full object-cover"
                      />
                    ) : (
                      getAvatarText(selectedWork.publisherNickname)
                    )}
                  </div>
                  <div className="min-w-0">
                    <p className="truncate text-base font-semibold">{selectedWork.publisherNickname}</p>
                    <p className="flex items-center gap-1 text-xs text-slate-400 light:text-muted-foreground">
                      <Clock className="h-3 w-3" />
                      {formatDate(selectedWork.publishedAt)}
                    </p>
                  </div>
                </div>

                {/* Prompt */}
                {(selectedWork.prompt || selectedWork.negativePrompt) && (
                  <div className={`${detailGlassBlock} flex min-h-0 flex-1 flex-col space-y-4 p-4`}>
                    {selectedWork.prompt && (
                      <div className="flex min-h-0 flex-1 flex-col space-y-2">
                        <div className="flex items-center justify-between">
                          <p className="flex items-center gap-2 text-sm font-medium text-slate-400 light:text-muted-foreground">
                            <MessageSquare className="h-4 w-4 text-primary" />
                            提示词
                          </p>
                          <Button
                            variant="ghost"
                            size="sm"
                            className="h-6 gap-1 px-2 text-xs"
                            onClick={() => copyGalleryText(selectedWork.prompt || '', '提示词已复制')}
                          >
                            <Copy className="h-3 w-3" />复制
                          </Button>
                        </div>
                        <div className={`${detailGlassInner} min-h-0 flex-1 overflow-y-auto p-3`}>
                          <p className="whitespace-pre-wrap break-words text-sm leading-6 text-slate-100 light:text-foreground">{selectedWork.prompt}</p>
                        </div>
                      </div>
                    )}
                    {selectedWork.negativePrompt && (
                      <div className="shrink-0 space-y-2">
                        <div className="flex items-center justify-between gap-2">
                          <p className="flex items-center gap-2 text-sm font-medium text-slate-400 light:text-muted-foreground">
                            <X className="h-4 w-4 text-destructive" />
                            负面提示词
                          </p>
                          <Button
                            variant="ghost"
                            size="sm"
                            className="h-6 gap-1 px-2 text-xs"
                            onClick={() => copyGalleryText(selectedWork.negativePrompt || '', '负面提示词已复制')}
                          >
                            <Copy className="h-3 w-3" />复制
                          </Button>
                        </div>
                        <div className={`${detailGlassInner} max-h-28 overflow-y-auto p-3`}>
                          <p className="whitespace-pre-wrap break-words text-sm leading-6 text-slate-300 light:text-foreground/75">
                            {selectedWork.negativePrompt}
                          </p>
                        </div>
                      </div>
                    )}
                  </div>
                )}

                {/* Reference Image */}
                {selectedReferenceImages.length > 0 && (
                  <div className={`${detailGlassBlock} shrink-0 p-4`}>
                    <div className="mb-2 flex items-center justify-between gap-2">
                      <div className="flex items-center gap-2">
                        <ImageIcon className="h-4 w-4 text-primary" />
                        <p className="text-sm font-medium text-slate-100 light:text-foreground">参考图</p>
                      </div>
                      <span className="text-xs text-slate-400 light:text-muted-foreground">{selectedReferenceImages.length} 张</span>
                    </div>
                    <div className="grid max-h-[240px] grid-cols-2 gap-2 overflow-y-auto pr-1">
                      {selectedReferenceImages.map((url, index) => (
                        <div key={`${url}-${index}`} className={`${detailGlassInner} group relative overflow-hidden`}>
                          <img
                            src={url}
                            alt={`参考图 ${index + 1}`}
                            className="aspect-square w-full cursor-zoom-in object-cover"
                            onDoubleClick={() => setFullscreenSrc(url)}
                          />
                          <div className="absolute inset-x-0 bottom-0 flex justify-end gap-1 bg-black/35 p-1 opacity-0 backdrop-blur-sm transition-opacity group-hover:opacity-100">
                            <button
                              className="flex h-7 w-7 items-center justify-center rounded-full bg-white/90 text-black"
                              onClick={() => setFullscreenSrc(url)}
                            >
                              <Maximize2 className="h-3.5 w-3.5" />
                            </button>
                            <button
                              className="flex h-7 w-7 items-center justify-center rounded-full bg-white/90 text-black"
                              onClick={(event) => handleDownload(url, `miaojing-reference-${selectedWork.id}-${index + 1}.png`, event)}
                            >
                              <Download className="h-3.5 w-3.5" />
                            </button>
                          </div>
                        </div>
                      ))}
                    </div>
                  </div>
                )}

                <div className={`${detailGlassBlock} mt-auto shrink-0 space-y-4 p-4`}>
                  {/* Model & Params */}
                  {selectedWork.params && Object.keys(selectedWork.params).length > 0 && (
                    <div>
                      <div className="mb-3 flex items-center gap-2">
                      <Cpu className="h-4 w-4 text-primary" />
                      <p className="text-sm font-medium text-slate-100 light:text-foreground">模型与参数</p>
                      </div>
                      <div className="grid max-h-36 grid-cols-2 gap-3 overflow-y-auto text-sm">
                      {(!!selectedWork.params.modelLabel || !!selectedWork.params.model) && (
                        <div>
                          <p className="text-xs text-slate-500 light:text-muted-foreground/80">模型</p>
                          <p className="font-medium text-slate-100 light:text-foreground">{String(selectedWork.params.modelLabel || selectedWork.params.model || '')}</p>
                        </div>
                      )}
                      <div>
                        <p className="text-xs text-slate-500 light:text-muted-foreground/80">类型</p>
                        <Badge variant="secondary">{getCategoryLabel(selectedWork)}</Badge>
                      </div>
                      {!!selectedWork.params.size && (
                        <div>
                          <p className="text-xs text-slate-500 light:text-muted-foreground/80">尺寸</p>
                          <p className="text-slate-100 light:text-foreground">{String(selectedWork.params.size)}</p>
                        </div>
                      )}
                      {!!selectedWork.params.steps && (
                        <div>
                          <p className="text-xs text-slate-500 light:text-muted-foreground/80">步数</p>
                          <p className="text-slate-100 light:text-foreground">{String(selectedWork.params.steps)}</p>
                        </div>
                      )}
                      {!!selectedWork.params.cfg_scale && (
                        <div>
                          <p className="text-xs text-slate-500 light:text-muted-foreground/80">引导系数</p>
                          <p className="text-slate-100 light:text-foreground">{String(selectedWork.params.cfg_scale)}</p>
                        </div>
                      )}
                      {!!selectedWork.params.seed && (
                        <div>
                          <p className="text-xs text-slate-500 light:text-muted-foreground/80">种子</p>
                          <p className="text-slate-100 light:text-foreground">{String(selectedWork.params.seed)}</p>
                        </div>
                      )}
                      </div>
                    </div>
                  )}

                  <div className="flex items-center justify-between gap-3 border-t border-white/[0.07] light:border-amber-900/14 pt-4">
                    <Button
                      size="sm"
                      variant={likedIds.has(selectedWork.id) ? 'default' : 'outline'}
                      className="h-9 min-w-[92px] gap-1.5 px-3 text-sm font-semibold"
                      onClick={() => toggleLike(selectedWork.id)}
                    >
                      <Heart className={`h-3.5 w-3.5 ${likedIds.has(selectedWork.id) ? 'fill-current' : ''}`} />
                      {selectedWork.likes + (likedIds.has(selectedWork.id) ? 1 : 0)}
                    </Button>
                    <Button
                      size="sm"
                      className="h-9 min-w-[112px] gap-1.5 px-3 text-sm font-semibold"
                      onClick={() => handleDownload(selectedWork.url, `miaojing-${selectedWork.id}.png`)}
                    >
                      <Download className="h-3.5 w-3.5" />
                      下载图片
                    </Button>
                    {isAdmin && apiWorkIds.has(selectedWork.id) && (
                      <Button
                        size="sm"
                        variant="destructive"
                        className="h-9 min-w-[92px] gap-1.5 px-3 text-sm font-semibold"
                        onClick={(e) => handleDeleteGalleryWorks([selectedWork.id], e)}
                      >
                        <Trash2 className="h-3.5 w-3.5" />
                        删除
                      </Button>
                    )}
                  </div>
                    </div>
              </div>
            </div>
          </div>
        </div>
      )}

      {/* Fullscreen image preview overlay */}
      <FullscreenPreview
        src={fullscreenSrc || ''}
        alt="全屏预览"
        open={!!fullscreenSrc}
        onClose={() => setFullscreenSrc(null)}
      />
    </div>
  );
}


