'use client';

import { useState, useCallback, useRef, useMemo, useEffect } from 'react';
import { Button } from '@/components/ui/button';
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';
import { Label } from '@/components/ui/label';
import { Slider } from '@/components/ui/slider';
import { useAuth } from '@/lib/auth-store';
import { useCustomApiKeys } from '@/lib/custom-api-store';
import { useManagedSystemApis } from '@/lib/managed-model-store';
import {
  IMG2IMG_ASPECT_RATIOS,
  IMAGE_OUTPUT_FORMAT_OPTIONS,
  IMAGE_QUALITY_OPTIONS,
  RESOLUTION_OPTIONS,
  IMG2IMG_STYLE_PRESETS,
  isCustomModel,
  isSystemModel,
  getCustomKeyId,
  getSystemApiId,
  buildCustomModelId,
  buildSystemModelId,
  calcImageCredits,
  inferImageParamsFromPrompt,
  resolveImageSize,
  resolveCustomApiImageSize,
  resolveImageSizeFromDimensions,
  type ImageOutputFormat,
  type ImageQuality,
} from '@/lib/model-config';
import { getCustomApiModelLabel, getSystemApiModelLabel } from '@/lib/model-display';
import { Sparkles, Loader2, Download, Upload, Wand2, Image as ImageIcon, History, ChevronDown, ChevronUp, Plus, X, KeyRound, Share2 } from 'lucide-react';
import { useCreationHistory, getCreationMode, isPlaceholder, shareToGallery, isUrlPublished, type CreationRecord } from '@/lib/creation-history-store';
import { addCreditRecord } from '@/lib/credit-records-store';
import { downloadFile } from '@/lib/utils';
import { GenerationJobStillRunningError, runGenerationFinalCountdown, runGenerationJob, type GenerationJobStatus } from '@/lib/generation-job-client';
import { useSiteConfig } from '@/lib/site-config';
import { toast } from 'sonner';
import Link from 'next/link';
import { BareImagePreview, ImageLightbox } from '@/components/lightbox';
import { CreationDetailDialog } from '@/components/creation-detail-dialog';
import { GenerationErrorPanel, createGenerationError, type GenerationErrorState } from '@/components/create/generation-error-panel';
import { ExpandablePromptTextarea } from '@/components/create/expandable-prompt-textarea';
import { compressImageFileForUpload } from '@/lib/browser-image-compression';
import { ImageCountCombobox } from '@/components/create/image-count-combobox';
import { StylePresetSelector } from '@/components/create/style-preset-selector';
import { useImageStylePresets } from '@/lib/style-presets-client';
import { GenerationTaskList, type ActiveGenerationTask } from '@/components/create/generation-task-list';
import { CachedPreviewImage } from '@/components/create/cached-preview-image';
import { InspirationGalleryDialog } from '@/components/create/inspiration-gallery-dialog';
import { IMAGE_TO_IMAGE_DRAFT_EVENT, IMAGE_TO_IMAGE_DRAFT_KEY, type ImageCreationReuseDraft } from '@/lib/creation-reuse';

const STREAM_UNSUPPORTED_SYNC_CONFIRM_PREFIX = 'MIAOJING_STREAM_UNSUPPORTED_SYNC_CONFIRM:';

function parseStreamUnsupportedSyncMessage(error: unknown): string | null {
  const message = error instanceof Error ? error.message : String(error || '');
  if (!message.includes(STREAM_UNSUPPORTED_SYNC_CONFIRM_PREFIX)) return null;
  return message.split(STREAM_UNSUPPORTED_SYNC_CONFIRM_PREFIX).pop()?.trim()
    || '上游接口不支持流式生图请求。是否重新发起同步生图请求？';
}

interface RefImage {
  id: string;
  dataUrl: string;
  name: string;
  width?: number;
  height?: number;
}

export function ImageToImagePanel() {
  const { user, accessToken } = useAuth();
  const { config: siteConfig } = useSiteConfig();
  const membershipEnabled = siteConfig.membershipEnabled !== false;
  const { imageKeys, textKeys } = useCustomApiKeys();
  const managedSystemApis = useManagedSystemApis();

  // Form state
  const [prompt, setPrompt] = useState('');
  const [negativePrompt, setNegativePrompt] = useState('');
  const [aspectRatio, setAspectRatio] = useState('auto');
  const [resolution, setResolution] = useState('auto');
  const [strength, setStrength] = useState(0.5);
  const [count, setCount] = useState('auto');
  const [outputFormat, setOutputFormat] = useState<ImageOutputFormat>('png');
  const [imageQuality, setImageQuality] = useState<ImageQuality>('auto');
  const [selectedStyleLabel, setSelectedStyleLabel] = useState('');
  const [refImages, setRefImages] = useState<RefImage[]>([]);

  // Generation state
  const [activeTasks, setActiveTasks] = useState<ActiveGenerationTask[]>([]);
  const [results, setResults] = useState<string[]>([]);
  const [generationError, setGenerationError] = useState<GenerationErrorState | null>(null);
  const [optimizing, setOptimizing] = useState(false);
  const [inspirationOpen, setInspirationOpen] = useState(false);
  const syncConfirmationResolversRef = useRef(new Map<string, (confirmed: boolean) => void>());
  const generating = activeTasks.length > 0;

  // History
  const { records, add: addRecord, remove: removeRecord } = useCreationHistory();
  const [showHistory, setShowHistory] = useState(false);
  const imageHistory = records.filter(r => getCreationMode(r) === 'img2img');

  // Lightbox state
  const [lightboxSrc, setLightboxSrc] = useState<string | null>(null);
  const [referencePreviewSrc, setReferencePreviewSrc] = useState<string | null>(null);

  // History detail dialog
  const [selectedHistoryRecord, setSelectedHistoryRecord] = useState<CreationRecord | null>(null);
  const stylePresets = useImageStylePresets(IMG2IMG_STYLE_PRESETS);

  const fileInputRef = useRef<HTMLInputElement>(null);

  const applyImageToImageDraft = useCallback((draft: unknown) => {
    if (!draft || typeof draft !== 'object') return;
    const data = draft as ImageCreationReuseDraft;

    if (typeof data.prompt === 'string') setPrompt(data.prompt);
    if (typeof data.negativePrompt === 'string') setNegativePrompt(data.negativePrompt);
    if (typeof data.model === 'string' && data.model.trim()) setSelectedModel(data.model.trim());
    if (typeof data.aspectRatio === 'string' && data.aspectRatio.trim()) setAspectRatio(data.aspectRatio.trim());
    if (typeof data.resolution === 'string' && data.resolution.trim()) setResolution(data.resolution.trim());
    if (typeof data.count === 'string' && data.count.trim()) setCount(data.count.trim());
    if (data.outputFormat) setOutputFormat(data.outputFormat);
    if (data.imageQuality) setImageQuality(data.imageQuality);
    if (typeof data.styleLabel === 'string') setSelectedStyleLabel(data.styleLabel);
    if (typeof data.strength === 'number' && Number.isFinite(data.strength)) {
      setStrength(Math.min(1, Math.max(0, data.strength)));
    }

    const rawReferences = Array.isArray(data.referenceImages)
      ? data.referenceImages
      : typeof data.referenceImage === 'string'
        ? [data.referenceImage]
        : [];
    const references = rawReferences.filter((item): item is string => (
      typeof item === 'string' && (
        item.startsWith('data:image/') ||
        /^https?:\/\/\S+/i.test(item) ||
        item.startsWith('/api/local-storage/')
      )
    ));

    if (references.length > 0) {
      setRefImages(references.map((dataUrl, index) => ({
        id: `draft-${Date.now()}-${index}-${Math.random().toString(36).slice(2, 6)}`,
        dataUrl,
        name: index === 0 ? '复用参考图' : `复用参考图 ${index + 1}`,
      })));
    }
  }, []);

  useEffect(() => {
    try {
      const raw = window.localStorage.getItem(IMAGE_TO_IMAGE_DRAFT_KEY);
      if (raw) applyImageToImageDraft(JSON.parse(raw));
    } catch {
      // Ignore malformed local draft data.
    }

    const handleDraft = (event: Event) => {
      applyImageToImageDraft((event as CustomEvent).detail);
    };
    window.addEventListener(IMAGE_TO_IMAGE_DRAFT_EVENT, handleDraft);
    return () => window.removeEventListener(IMAGE_TO_IMAGE_DRAFT_EVENT, handleDraft);
  }, [applyImageToImageDraft]);

  // System APIs
  const systemImageApis = managedSystemApis.filter(api => api.type === 'image' && api.isActive);
  const systemTextApis = managedSystemApis.filter(api => api.type === 'text' && api.isActive);

  // Model options — only system + custom (no builtin)
  const modelOptions = useMemo(() => [
    ...systemImageApis.map(api => ({ id: buildSystemModelId(api.id), label: getSystemApiModelLabel(api), group: '系统模型' })),
    ...imageKeys.map(k => ({ id: buildCustomModelId(k.id), label: getCustomApiModelLabel(k), group: '自定义模型' })),
  ], [systemImageApis, imageKeys]);

  const hasModels = modelOptions.length > 0;

  const [selectedModel, setSelectedModel] = useState('');
  useEffect(() => {
    if (modelOptions.length > 0 && !modelOptions.find(o => o.id === selectedModel)) {
      const customOpt = modelOptions.find(o => o.group === '自定义模型');
      setSelectedModel(customOpt ? customOpt.id : modelOptions[0].id);
    }
  }, [modelOptions, selectedModel]);

  // Text model options
  const textModelOptions = useMemo(() => [
    ...textKeys.map(k => ({ id: buildCustomModelId(k.id), label: getCustomApiModelLabel(k), config: { customApiKeyId: k.id, modelName: k.modelName } })),
    ...systemTextApis.map(api => ({ id: buildSystemModelId(api.id), label: getSystemApiModelLabel(api), config: { systemApiId: api.id, modelName: api.modelName } })),
  ], [textKeys, systemTextApis]);

  const getCurrentModelLabel = useCallback(() => {
    if (isCustomModel(selectedModel)) {
      const key = imageKeys.find(k => k.id === getCustomKeyId(selectedModel));
      return getCustomApiModelLabel(key);
    }
    if (isSystemModel(selectedModel)) {
      const api = systemImageApis.find(a => a.id === getSystemApiId(selectedModel));
      return getSystemApiModelLabel(api);
    }
    return 'AI模型';
  }, [selectedModel, imageKeys, systemImageApis]);

  // Prompt optimization
  const handleOptimizePrompt = useCallback(async () => {
    if (!prompt.trim()) { toast.error('请先输入创作描述'); return; }
    if (!user || !accessToken) { toast.error('请先登录后再优化提示词'); return; }
    if (textModelOptions.length === 0) { toast.error('未配置文本模型'); return; }

    setOptimizing(true);
    try {
      const textModel = textModelOptions[0];
      const modelLabel = getCurrentModelLabel();
      const res = await fetch('/api/generate/suggest-prompt', {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
          ...(accessToken ? { Authorization: `Bearer ${accessToken}` } : {}),
        },
        body: JSON.stringify({
          prompt: prompt.trim(),
          modelName: textModel.config.modelName,
          customApiConfig: textModel.config,
          systemPrefix: `针对${modelLabel}图片生成优化提示词`,
        }),
      });
      const data = await res.json().catch(() => ({}));
      if (res.ok) {
        if (data.prompt) {
          setPrompt(data.prompt);
          if (typeof data.negativePrompt === 'string' && data.negativePrompt.trim()) {
            setNegativePrompt(data.negativePrompt.trim());
          }
          toast.success('提示词已优化');
        }
        else toast.error(data.error || '优化失败');
      } else toast.error(data.error || '提示词优化请求失败');
    } catch (err: unknown) {
      if (err instanceof DOMException && err.name === 'AbortError') {
        toast.error('请求超时，请尝试减少生成数量或降低分辨率');
      } else {
        toast.error(err instanceof Error ? err.message : '网络错误，请重试');
      }
    }
    finally { setOptimizing(false); }
  }, [prompt, user, accessToken, textModelOptions, getCurrentModelLabel]);

  const addRefImageFiles = useCallback((files: File[]) => {
    const imageFiles = files.filter(file => file.type.startsWith('image/'));
    if (imageFiles.length === 0) {
      toast.error('请上传图片文件');
      return;
    }
    void (async () => {
      const refs: RefImage[] = [];

      for (const file of imageFiles) {
        try {
          const result = await compressImageFileForUpload(file);
          refs.push({
            id: `ref-${Date.now()}-${Math.random().toString(36).slice(2, 6)}`,
            dataUrl: result.dataUrl,
            name: result.name,
            width: result.width,
            height: result.height,
          });
        } catch (err) {
          toast.error(err instanceof Error ? err.message : '图片读取失败');
        }
      }

      if (refs.length > 0) {
        setRefImages(prev => [...prev, ...refs]);
      }
    })();
  }, []);

  const addRefImageUrl = useCallback((value: string) => {
    const url = value.trim();
    if (!/^https?:\/\/\S+/i.test(url)) {
      toast.error('请粘贴有效的图片 URL');
      return false;
    }
    setRefImages(prev => [...prev, { id: `ref-${Date.now()}-${Math.random().toString(36).slice(2, 6)}`, dataUrl: url, name: '图片 URL' }]);
    toast.success('已添加图片 URL');
    return true;
  }, []);

  // Multi-image upload handler
  const handleFileChange = useCallback((e: React.ChangeEvent<HTMLInputElement>) => {
    const files = e.target.files;
    if (!files || files.length === 0) return;
    addRefImageFiles(Array.from(files));
    // Reset input so same file can be re-selected
    e.target.value = '';
  }, [addRefImageFiles]);

  const handleUploadDrop = useCallback((event: React.DragEvent<HTMLDivElement>) => {
    event.preventDefault();
    const files = Array.from(event.dataTransfer.files);
    if (files.length > 0) {
      addRefImageFiles(files);
      return;
    }
    const url = event.dataTransfer.getData('text/uri-list') || event.dataTransfer.getData('text/plain');
    if (url) addRefImageUrl(url);
  }, [addRefImageFiles, addRefImageUrl]);

  const handleUploadPaste = useCallback((event: React.ClipboardEvent<HTMLDivElement>) => {
    const files = Array.from(event.clipboardData.files);
    if (files.length > 0) {
      event.preventDefault();
      addRefImageFiles(files);
      return;
    }
    const text = event.clipboardData.getData('text/plain');
    if (/^https?:\/\/\S+/i.test(text.trim())) {
      event.preventDefault();
      addRefImageUrl(text);
    }
  }, [addRefImageFiles, addRefImageUrl]);

  const removeRefImage = useCallback((id: string) => {
    setRefImages(prev => prev.filter(img => img.id !== id));
  }, []);

  const inferredImageParams = useMemo(
    () => inferImageParamsFromPrompt(prompt, { allowOriginalAspectRatio: true }),
    [prompt],
  );
  const selectedStylePreset = useMemo(
    () => stylePresets.find(preset => preset.label === selectedStyleLabel),
    [stylePresets, selectedStyleLabel],
  );
  const creditCount = count === 'auto' ? (inferredImageParams.count ?? 1) : (Number(count) || 1);
  const credits = calcImageCredits(selectedModel, resolution, aspectRatio, creditCount);

  const resolveGenerationParams = useCallback((): { aspectRatio: string; resolution: string; count: number } | null => {
    const resolvedAspectRatio = aspectRatio === 'auto' ? inferredImageParams.aspectRatio : aspectRatio;
    const resolvedResolution = resolution === 'auto' ? inferredImageParams.resolution : resolution;
    const parsedCount = count === 'auto' ? inferredImageParams.count : Number(count);
    const resolvedCount = Number.isFinite(parsedCount) ? Math.min(10, Math.max(1, Math.floor(Number(parsedCount)))) : undefined;
    const missing: string[] = [];
    if (!resolvedAspectRatio) missing.push('画面比例');
    if (!resolvedResolution) missing.push('分辨率');
    if (!resolvedCount) missing.push('生成数量');
    if (missing.length > 0) {
      toast.error(`请在提示词中写明${missing.join('、')}，或手动设置后再生成`);
      return null;
    }
    if (!resolvedAspectRatio || !resolvedResolution || !resolvedCount) return null;
    return { aspectRatio: resolvedAspectRatio, resolution: resolvedResolution, count: resolvedCount };
  }, [aspectRatio, resolution, count, inferredImageParams]);

  const updateActiveTask = useCallback((taskId: string, update: Partial<ActiveGenerationTask>) => {
    setActiveTasks(prev => prev.map(task => task.id === taskId ? { ...task, ...update } : task));
  }, []);

  const removeActiveTask = useCallback((taskId: string) => {
    setActiveTasks(prev => prev.filter(task => task.id !== taskId));
  }, []);

  const requestSyncConfirmation = useCallback((taskId: string, message: string) => new Promise<boolean>((resolve) => {
    syncConfirmationResolversRef.current.set(taskId, resolve);
    updateActiveTask(taskId, {
      syncConfirmation: {
        message,
      },
      jobStatus: null,
      finalCountdownSeconds: null,
    });
  }), [updateActiveTask]);

  const handleConfirmSync = useCallback((taskId: string) => {
    updateActiveTask(taskId, {
      syncConfirmation: {
        message: '已确认同步生图，正在重新提交请求。',
        confirming: true,
      },
    });
    const resolve = syncConfirmationResolversRef.current.get(taskId);
    syncConfirmationResolversRef.current.delete(taskId);
    resolve?.(true);
  }, [updateActiveTask]);

  const handleCancelSync = useCallback((taskId: string) => {
    const resolve = syncConfirmationResolversRef.current.get(taskId);
    syncConfirmationResolversRef.current.delete(taskId);
    resolve?.(false);
    removeActiveTask(taskId);
  }, [removeActiveTask]);

  // Generate
  const handleGenerate = useCallback(async () => {
    if (!prompt.trim()) { toast.error('请输入创作描述'); return; }
    if (!user) { toast.error('请先登录'); return; }
    if (refImages.length === 0) { toast.error('请至少上传一张参考图片'); return; }

    setGenerationError(null);
    const taskId = `img2img-${Date.now()}-${Math.random().toString(36).slice(2, 7)}`;
    try {
      const resolvedParams = resolveGenerationParams();
      if (!resolvedParams) return;
      setActiveTasks(prev => [
        ...prev,
        {
          id: taskId,
          title: '正在生成图片',
          startedAt: Date.now(),
          estimateSeconds: 90,
          jobStatus: null,
          finalCountdownSeconds: null,
        },
      ]);
      // Send first reference image as primary, others as additional context
      const primaryImage = refImages[0].dataUrl;
      // Keep the outgoing API size aligned with the selected resolution.
      const useCustomApiSize = isCustomModel(selectedModel) || isSystemModel(selectedModel);
      const resolvedSize = resolvedParams.aspectRatio === 'original'
        ? resolveImageSizeFromDimensions(refImages[0].width, refImages[0].height, resolvedParams.resolution)
        : useCustomApiSize
          ? resolveCustomApiImageSize(resolvedParams.aspectRatio, resolvedParams.resolution)
          : resolveImageSize(resolvedParams.aspectRatio, resolvedParams.resolution);

      let requestBody: Record<string, unknown> = {
        prompt: prompt.trim(),
        negativePrompt: negativePrompt.trim() || undefined,
        model: selectedModel,
        aspectRatio: resolvedParams.aspectRatio,
        resolution: resolvedParams.resolution,
        size: resolvedSize,
        count: resolvedParams.count,
        outputFormat,
        imageQuality,
        styleLabel: selectedStylePreset?.label,
        stylePrompt: selectedStylePreset?.prompt,
        strength,
        image: primaryImage,
        // Additional reference images
        extraImages: refImages.length > 1 ? refImages.slice(1).map(img => img.dataUrl) : undefined,
      };

      if (isCustomModel(selectedModel)) {
        const key = imageKeys.find(k => k.id === getCustomKeyId(selectedModel));
        if (key) {
          requestBody = { ...requestBody, model: key.modelName, customApiConfig: { customApiKeyId: key.id, modelName: key.modelName } };
        }
      } else if (isSystemModel(selectedModel)) {
        const api = systemImageApis.find(a => a.id === getSystemApiId(selectedModel));
        if (api) {
          requestBody = { ...requestBody, model: api.modelName, customApiConfig: { systemApiId: api.id, modelName: api.modelName } };
        }
      }
      const runJob = (payload: Record<string, unknown>) => runGenerationJob<{ images?: string[]; error?: string }>(
        'image',
        payload,
        { timeoutMs: 900_000, onStatus: (status: GenerationJobStatus) => updateActiveTask(taskId, { jobStatus: status }) },
      );
      let data: { images?: string[]; error?: string };
      try {
        data = await runJob({ ...requestBody, stream: true });
      } catch (error) {
        const confirmationMessage = parseStreamUnsupportedSyncMessage(error);
        if (!confirmationMessage) throw error;
        const confirmed = await requestSyncConfirmation(taskId, confirmationMessage);
        if (!confirmed) return;
        updateActiveTask(taskId, {
          title: '正在同步生成图片',
          startedAt: Date.now(),
          jobStatus: null,
          finalCountdownSeconds: null,
          syncConfirmation: undefined,
        });
        data = await runJob({
          ...requestBody,
          clientRequestId: `img2img-sync-${Date.now()}-${Math.random().toString(36).slice(2, 7)}`,
          stream: false,
        });
      }
      await runGenerationFinalCountdown((seconds) => updateActiveTask(taskId, { finalCountdownSeconds: seconds }), 3);
      if (data.images && data.images.length > 0) {
        setResults(prev => [...data.images!, ...prev]);
        setGenerationError(null);
        for (const url of data.images) {
          addRecord({
            type: 'image', url, prompt: prompt.trim(),
            negativePrompt: negativePrompt.trim() || undefined,
            model: selectedModel,
            modelLabel: getCurrentModelLabel(),
            isCustomModel: isCustomModel(selectedModel) || isSystemModel(selectedModel),
            referenceImage: primaryImage,
            referenceImages: refImages.map(img => img.dataUrl),
            params: {
              creationMode: 'img2img',
              aspectRatio: resolvedParams.aspectRatio,
              resolution: resolvedParams.resolution,
              count: resolvedParams.count,
              outputFormat,
              imageQuality,
              styleLabel: selectedStylePreset?.label,
              strength,
              refImageCount: refImages.length,
            },
          });
        }
        toast.success(`生成 ${data.images.length} 张图片`);
        if (membershipEnabled && credits > 0 && user) {
          const currentCredits = typeof user.creditsBalance === 'number' ? user.creditsBalance : 0;
          addCreditRecord({
            type: 'consume',
            amount: -credits,
            balanceAfter: Math.max(0, currentCredits - credits),
            description: `图生图 - ${getCurrentModelLabel()}`,
          });
        }
      } else {
        setGenerationError(createGenerationError(data.error || '图片生成失败'));
      }
    } catch (err: unknown) {
      if (err instanceof GenerationJobStillRunningError) {
        setGenerationError(null);
        removeActiveTask(taskId);
        toast.info('生成任务仍在执行，可稍后在创作历史中查看');
      } else if (err instanceof DOMException && err.name === 'AbortError') {
        setGenerationError(createGenerationError('请求超时，请尝试减少生成数量或降低分辨率'));
      } else {
        setGenerationError(createGenerationError(err instanceof Error ? err.message : '网络错误，请重试'));
      }
    }
    finally {
      syncConfirmationResolversRef.current.delete(taskId);
      removeActiveTask(taskId);
    }
  }, [prompt, negativePrompt, selectedModel, outputFormat, imageQuality, selectedStylePreset, strength, refImages, user, imageKeys, systemImageApis, getCurrentModelLabel, addRecord, credits, membershipEnabled, resolveGenerationParams, removeActiveTask, updateActiveTask, requestSyncConfirmation]);

  const handleDownload = useCallback(async (url: string, index: number) => {
    const result = await downloadFile(url, `miaojing-img2img-${Date.now()}-${index}.png`);
    if (!result.ok) toast.error(result.error || '下载失败');
  }, []);

  const handleShareToGallery = useCallback((url: string) => {
    if (isUrlPublished(url)) {
      toast.info('该作品已分享到画廊');
      return;
    }
    shareToGallery({
      type: 'image',
      url,
      prompt: prompt.trim(),
      model: selectedModel,
      modelLabel: getCurrentModelLabel(),
      params: {
        creationMode: 'img2img',
        styleLabel: selectedStylePreset?.label,
      },
    });
    toast.success('已分享到画廊');
  }, [prompt, selectedModel, selectedStylePreset, getCurrentModelLabel]);

  return (
    <>
    <InspirationGalleryDialog mode="img2img" open={inspirationOpen} onOpenChange={setInspirationOpen} />
    <div className="grid min-h-[600px] grid-cols-1 gap-6 xl:grid-cols-[minmax(0,4fr)_minmax(0,6fr)]">
      {/* Left: Settings */}
      <div className="min-w-0 space-y-5 pb-8 pr-2">
        {/* Reference Images Upload (Multi) */}
        <div className="space-y-2">
          <Label>参考图片 <span className="text-destructive">*</span> <span className="text-muted-foreground text-xs">至少1张，可上传多张</span></Label>
          <input type="file" ref={fileInputRef} className="hidden" accept="image/*" multiple onChange={handleFileChange} />
          <div
            tabIndex={0}
            className="flex min-h-[224px] items-center justify-center rounded-2xl border border-dashed border-border/80 bg-background/50 p-5 transition-colors hover:border-primary/60 focus:outline-none focus:ring-2 focus:ring-primary/40"
            onDragOver={(event) => event.preventDefault()}
            onDrop={handleUploadDrop}
            onPaste={handleUploadPaste}
          >
            {refImages.length > 0 ? (
              <div className="grid w-full grid-cols-3 gap-3">
                {refImages.map(img => (
                  <div
                    key={img.id}
                    className="liquid-glass-soft relative group aspect-square cursor-zoom-in overflow-hidden rounded-2xl"
                    onClick={() => setReferencePreviewSrc(img.dataUrl)}
                  >
                    {/* eslint-disable-next-line @next/next/no-img-element */}
                    <img src={img.dataUrl} alt={img.name} className="w-full h-full object-cover" />
                    <button
                      className="absolute top-0.5 right-0.5 w-5 h-5 rounded-full bg-black/60 text-white flex items-center justify-center opacity-0 group-hover:opacity-100 transition-opacity"
                      onClick={(event) => {
                        event.stopPropagation();
                        removeRefImage(img.id);
                      }}
                    >
                      <X className="h-3 w-3" />
                    </button>
                  </div>
                ))}
                <button
                  className="flex aspect-square flex-col items-center justify-center gap-2 rounded-2xl border border-dashed border-border text-muted-foreground transition-colors hover:border-primary/60 hover:text-primary"
                  type="button"
                  onClick={() => fileInputRef.current?.click()}
                >
                  <Plus className="h-6 w-6" />
                  <span className="text-xs">添加</span>
                </button>
              </div>
            ) : (
              <button
                className="flex min-h-[189px] w-full flex-col items-center justify-center gap-2 text-center text-muted-foreground"
                type="button"
                onClick={() => fileInputRef.current?.click()}
              >
                <Upload className="h-14 w-14 opacity-30" />
                <span className="text-base font-semibold text-foreground">上传参考图片</span>
                <span className="text-sm">点击上传、拖入图片、Ctrl+V 粘贴图片或图片 URL</span>
              </button>
            )}
          </div>
        </div>

        {/* Model Selection */}
        <div className="space-y-2">
          <Label>生成模型</Label>
          {hasModels ? (
            <Select value={selectedModel} onValueChange={setSelectedModel}>
              <SelectTrigger><SelectValue placeholder="选择模型" /></SelectTrigger>
              <SelectContent>
                {modelOptions.map(opt => (
                  <SelectItem key={opt.id} value={opt.id}>{opt.label}</SelectItem>
                ))}
              </SelectContent>
            </Select>
          ) : (
            <div className="liquid-glass-soft rounded-2xl border-dashed p-4 text-center space-y-2">
              <KeyRound className="h-8 w-8 mx-auto text-muted-foreground/50" />
              <p className="text-sm text-muted-foreground">暂无可用模型</p>
              <Link href="/profile" className="text-sm text-primary hover:underline">
                前往 我的 → API 中添加API密钥
              </Link>
            </div>
          )}
        </div>

        {/* Prompt */}
        <div className="space-y-2">
          <div className="flex items-center justify-between">
            <Label>创作描述</Label>
            <div className="flex items-center gap-1.5">
              <Button variant="ghost" size="sm" className="h-7 gap-1.5 text-xs text-primary hover:text-primary" onClick={() => setInspirationOpen(true)}>
                <Sparkles className="h-3 w-3" />
                获取灵感
              </Button>
              {textModelOptions.length > 0 && (
                <Button variant="ghost" size="sm" className="h-7 gap-1.5 text-xs text-primary hover:text-primary" onClick={handleOptimizePrompt} disabled={optimizing || !prompt.trim()}>
                  {optimizing ? <Loader2 className="h-3 w-3 animate-spin" /> : <Wand2 className="h-3 w-3" />}
                  {optimizing ? '优化中...' : '优化提示词'}
                </Button>
              )}
            </div>
          </div>
          <ExpandablePromptTextarea
            title="创作描述"
            placeholder="描述你想要的图片变化..."
            rows={3}
            className="h-32 resize-none overflow-y-auto"
            value={prompt}
            onValueChange={setPrompt}
          />
          <StylePresetSelector
            presets={stylePresets}
            selectedLabel={selectedStyleLabel}
            onSelect={setSelectedStyleLabel}
          />
        </div>

        {/* Negative Prompt */}
        <div className="space-y-2">
          <Label>负面提示词 <span className="text-muted-foreground text-xs">(可选)</span></Label>
          <ExpandablePromptTextarea
            title="负面提示词"
            placeholder="不希望出现的元素..."
            rows={2}
            className="h-24 resize-none overflow-y-auto"
            value={negativePrompt}
            onValueChange={setNegativePrompt}
          />
        </div>

        {/* Image Params */}
        <div className="grid grid-cols-2 gap-x-3 gap-y-3 lg:grid-cols-[minmax(7.75rem,1.2fr)_minmax(5.75rem,0.9fr)_minmax(5.75rem,0.9fr)_minmax(5.75rem,0.9fr)]">
          <div className="min-w-0 space-y-2">
            <Label>画面比例</Label>
            <Select value={aspectRatio} onValueChange={setAspectRatio}>
              <SelectTrigger className="w-full min-w-0 gap-1.5 px-3 [&_svg]:size-4"><SelectValue /></SelectTrigger>
              <SelectContent>
                {IMG2IMG_ASPECT_RATIOS.map(ar => (
                  <SelectItem key={ar.value} value={ar.value}>{ar.label}</SelectItem>
                ))}
              </SelectContent>
            </Select>
          </div>
          <div className="min-w-0 space-y-2">
            <Label>分辨率</Label>
            <Select value={resolution} onValueChange={setResolution}>
              <SelectTrigger className="w-full min-w-0 gap-1.5 px-3 [&_svg]:size-4"><SelectValue /></SelectTrigger>
              <SelectContent>
                {RESOLUTION_OPTIONS.map(r => (
                  <SelectItem key={r.value} value={r.value}>{r.label}</SelectItem>
                ))}
              </SelectContent>
            </Select>
          </div>
          <div className="min-w-0 space-y-2">
            <Label>图片格式</Label>
            <Select value={outputFormat} onValueChange={v => setOutputFormat(v as ImageOutputFormat)}>
              <SelectTrigger className="w-full min-w-0 gap-1.5 px-3 [&_svg]:size-4"><SelectValue /></SelectTrigger>
              <SelectContent>
                {IMAGE_OUTPUT_FORMAT_OPTIONS.map(format => (
                  <SelectItem key={format.value} value={format.value}>{format.label}</SelectItem>
                ))}
              </SelectContent>
            </Select>
          </div>
          <div className="min-w-0 space-y-2">
            <Label>质量</Label>
            <Select value={imageQuality} onValueChange={v => setImageQuality(v as ImageQuality)}>
              <SelectTrigger className="w-full min-w-0 gap-1.5 px-3 [&_svg]:size-4"><SelectValue /></SelectTrigger>
              <SelectContent>
                {IMAGE_QUALITY_OPTIONS.map(option => (
                  <SelectItem key={option.value} value={option.value}>{option.label}</SelectItem>
                ))}
              </SelectContent>
            </Select>
          </div>
        </div>

        {/* Strength */}
        <div className="space-y-2">
          <div className="flex items-center justify-between">
            <Label>重绘幅度</Label>
            <span className="text-xs text-muted-foreground">{strength.toFixed(2)}</span>
          </div>
          <Slider value={[strength]} onValueChange={([v]) => setStrength(v)} min={0} max={1} step={0.05} />
          <p className="text-xs text-muted-foreground">低=保留原图特征，高=更贴近提示词</p>
        </div>

        {/* Count */}
        <div className="space-y-2">
          <Label>生成数量</Label>
          <ImageCountCombobox value={count} onChange={setCount} />
        </div>

        {/* Generate */}
        <Button className="w-full gap-2" size="lg" onClick={handleGenerate} disabled={!hasModels}>
          {generating ? (<><Plus className="h-4 w-4" />继续提交任务</>) : (<><Sparkles className="h-4 w-4" />生成图片 {membershipEnabled && credits > 0 && `(${credits} 积分)`}</>)}
        </Button>
      </div>

      {/* Right: Results + History */}
      <div className="min-w-0 space-y-4">
        {generating ? (
          <GenerationTaskList tasks={activeTasks} onConfirmSync={handleConfirmSync} onCancelSync={handleCancelSync} />
        ) : generationError ? (
          <GenerationErrorPanel error={generationError} />
        ) : results.length > 0 ? (
          <div className="space-y-3">
            <div className="flex items-center gap-2 text-sm font-medium"><ImageIcon className="h-4 w-4" />生成结果</div>
            <div className="grid grid-cols-2 gap-3">
              {results.map((url, i) => (
                <div key={i} className="liquid-glass-soft group relative overflow-hidden rounded-2xl">
                  <CachedPreviewImage
                    src={url}
                    alt={`生成结果 ${i + 1}`}
                    className="w-full aspect-square object-cover cursor-zoom-in"
                    onClick={() => setLightboxSrc(url)}
                  />
                  <div className="absolute inset-0 bg-black/0 group-hover:bg-black/30 transition-colors flex items-center justify-center gap-2 opacity-0 group-hover:opacity-100">
                    <Button size="sm" variant="secondary" className="gap-1" onClick={() => setLightboxSrc(url)}><ImageIcon className="h-3.5 w-3.5" />预览</Button>
                    <Button size="sm" variant="secondary" className="gap-1" onClick={() => handleShareToGallery(url)}><Share2 className="h-3.5 w-3.5" />分享</Button>
                    <Button size="sm" variant="secondary" className="gap-1" onClick={() => handleDownload(url, i)}><Download className="h-3.5 w-3.5" />下载</Button>
                  </div>
                </div>
              ))}
            </div>
          </div>
        ) : (
          <div className="liquid-glass flex min-h-[300px] flex-col items-center justify-center rounded-2xl border-dashed py-24 text-muted-foreground">
            <ImageIcon className="h-14 w-14 mb-3 opacity-20" />
            <p className="text-sm">生成结果将显示在这里</p>
          </div>
        )}

        {imageHistory.length > 0 && (
          <div className="space-y-2">
            <button className="flex items-center gap-2 text-sm font-medium text-muted-foreground hover:text-foreground transition-colors" onClick={() => setShowHistory(!showHistory)}>
              <History className="h-4 w-4" />历史创作 ({imageHistory.length})
              {showHistory ? <ChevronUp className="h-3.5 w-3.5" /> : <ChevronDown className="h-3.5 w-3.5" />}
            </button>
            {showHistory && (
              <div className="grid grid-cols-3 gap-2 max-h-[400px] overflow-y-auto">
                {imageHistory.map(record => (
                  <div
                    key={record.id}
                    className="liquid-glass-soft group relative cursor-pointer overflow-hidden rounded-xl"
                    onClick={() => setSelectedHistoryRecord(record)}
                  >
                    {isPlaceholder(record.url) ? (
                      <div className="w-full aspect-square flex items-center justify-center"><ImageIcon className="h-6 w-6 text-muted-foreground/30" /></div>
                    ) : (
                      <CachedPreviewImage
                        src={record.url}
                        alt={record.prompt?.slice(0, 20) || '历史记录'}
                        className="w-full aspect-square object-cover"
                        badgeClassName="absolute right-1.5 top-1.5 z-10 scale-75 origin-top-right"
                      />
                    )}
                    <div className="absolute inset-0 bg-black/0 group-hover:bg-black/40 transition-colors flex items-end p-1.5 opacity-0 group-hover:opacity-100">
                      <p className="text-xs text-white line-clamp-2">{record.prompt}</p>
                    </div>
                  </div>
                ))}
              </div>
            )}
          </div>
        )}
      </div>

      {/* Lightbox */}
      <ImageLightbox src={lightboxSrc || ''} open={!!lightboxSrc} onClose={() => setLightboxSrc(null)} />
      <BareImagePreview src={referencePreviewSrc || ''} open={!!referencePreviewSrc} onClose={() => setReferencePreviewSrc(null)} />

      {/* History Detail Dialog */}
      <CreationDetailDialog
        record={selectedHistoryRecord}
        open={!!selectedHistoryRecord}
        onClose={() => setSelectedHistoryRecord(null)}
        onDelete={async (deletedRecord) => {
          await removeRecord(deletedRecord.id);
          setSelectedHistoryRecord(null);
        }}
      />
    </div>
    </>
  );
}
