'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 {
  ASPECT_RATIOS,
  IMAGE_OUTPUT_FORMAT_OPTIONS,
  IMAGE_QUALITY_OPTIONS,
  RESOLUTION_OPTIONS,
  STYLE_PRESETS,
  isCustomModel,
  isSystemModel,
  getCustomKeyId,
  getSystemApiId,
  buildCustomModelId,
  buildSystemModelId,
  calcImageCredits,
  inferImageParamsFromPrompt,
  resolveImageSize,
  resolveCustomApiImageSize,
  type ImageOutputFormat,
  type ImageQuality,
} from '@/lib/model-config';
import { getCustomApiModelLabel, getSystemApiModelLabel } from '@/lib/model-display';
import { Sparkles, Loader2, Download, Wand2, Image as ImageIcon, History, ChevronDown, ChevronUp, Plus, 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 { 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 { 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 { TEXT_TO_IMAGE_DRAFT_EVENT, TEXT_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()
    || '上游接口不支持流式生图请求。是否重新发起同步生图请求？';
}

export function TextToImagePanel() {
  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 [count, setCount] = useState('auto');
  const [outputFormat, setOutputFormat] = useState<ImageOutputFormat>('png');
  const [imageQuality, setImageQuality] = useState<ImageQuality>('auto');
  const [selectedStyleLabel, setSelectedStyleLabel] = useState('');
  const [guidanceScale, setGuidanceScale] = useState(7);

  // 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 activeSubmissionSignaturesRef = useRef(new Set<string>());
  const syncConfirmationResolversRef = useRef(new Map<string, (confirmed: boolean) => void>());
  const generating = activeTasks.length > 0;

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

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

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

  const applyPromptDraft = 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.guidanceScale === 'number' && Number.isFinite(data.guidanceScale)) {
      setGuidanceScale(Math.min(20, Math.max(1, data.guidanceScale)));
    }
  }, []);

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

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

  // 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;

  // Default to first available: system > custom; prefer custom if available
  const [selectedModel, setSelectedModel] = useState('');
  useEffect(() => {
    if (modelOptions.length > 0 && !modelOptions.find(o => o.id === selectedModel)) {
      // Prefer custom model as default
      const customOpt = modelOptions.find(o => o.group === '自定义模型');
      setSelectedModel(customOpt ? customOpt.id : modelOptions[0].id);
    }
  }, [modelOptions, selectedModel]);

  // Text model options for prompt optimization — memoized
  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('未配置多模态模型，请先在API设置中添加多模态模型'); 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 inferredImageParams = useMemo(() => inferImageParamsFromPrompt(prompt), [prompt]);
  const selectedStylePreset = useMemo(
    () => stylePresets.find(preset => preset.label === selectedStyleLabel),
    [stylePresets, selectedStyleLabel],
  );
  const creditCount = count === 'auto' ? (inferredImageParams.count ?? 1) : (Number(count) || 1);
  const creditResolution = resolution === 'auto' ? inferredImageParams.resolution : resolution;
  const creditAspectRatio = aspectRatio === 'auto' ? inferredImageParams.aspectRatio : aspectRatio;
  const credits = calcImageCredits(selectedModel, creditResolution, creditAspectRatio, 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; }

    setGenerationError(null);
    let submissionSignature: string | null = null;
    try {
      const resolvedParams = resolveGenerationParams();
      if (!resolvedParams) return;
      const taskCount = resolvedParams.count;

      // Keep custom/system API size aligned with the selected resolution.
      const useCustomApiSize = isCustomModel(selectedModel) || isSystemModel(selectedModel);
      const resolvedSize = useCustomApiSize
        ? resolveCustomApiImageSize(resolvedParams.aspectRatio, resolvedParams.resolution)
        : resolveImageSize(resolvedParams.aspectRatio, resolvedParams.resolution);

      let requestBodyBase: Record<string, unknown> = {
        prompt: prompt.trim(),
        negativePrompt: negativePrompt.trim() || undefined,
        model: selectedModel,
        aspectRatio: resolvedParams.aspectRatio,
        resolution: resolvedParams.resolution,
        size: resolvedSize,
        count: 1,
        outputFormat,
        imageQuality,
        styleLabel: selectedStylePreset?.label,
        stylePrompt: selectedStylePreset?.prompt,
        guidanceScale,
      };

      if (isCustomModel(selectedModel)) {
        const key = imageKeys.find(k => k.id === getCustomKeyId(selectedModel));
        if (key) {
          requestBodyBase = { ...requestBodyBase, 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) {
          requestBodyBase = { ...requestBodyBase, model: api.modelName, customApiConfig: { systemApiId: api.id, modelName: api.modelName } };
        }
      }

      submissionSignature = JSON.stringify({
        prompt: prompt.trim(),
        negativePrompt: negativePrompt.trim(),
        model: selectedModel,
        aspectRatio: resolvedParams.aspectRatio,
        resolution: resolvedParams.resolution,
        count: taskCount,
        outputFormat,
        imageQuality,
        styleLabel: selectedStylePreset?.label || '',
        guidanceScale,
      });
      if (activeSubmissionSignaturesRef.current.has(submissionSignature)) {
        toast.info('相同任务正在生成中，请勿重复提交');
        return;
      }
      activeSubmissionSignaturesRef.current.add(submissionSignature);

      const batchId = `text2img-${Date.now()}-${Math.random().toString(36).slice(2, 7)}`;
      const taskIds = Array.from({ length: taskCount }, (_, index) => `${batchId}-${index + 1}`);
      setActiveTasks(prev => [
        ...prev,
        ...taskIds.map(taskId => ({
          id: taskId,
          title: '正在生成图片',
          startedAt: Date.now(),
          estimateSeconds: 90,
          jobStatus: null,
          finalCountdownSeconds: null,
        })),
      ]);

      const runSingleTask = async (taskId: string, index: number) => {
        try {
          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({ ...requestBodyBase, count: 1, clientRequestId: `${batchId}-${index + 1}`, 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({
              ...requestBodyBase,
              count: 1,
              clientRequestId: `${batchId}-${index + 1}-sync-${Date.now()}`,
              stream: false,
            });
          }
          await runGenerationFinalCountdown((seconds) => updateActiveTask(taskId, { finalCountdownSeconds: seconds }), 3);
          if (!data.images || data.images.length === 0) {
            throw new Error(data.error || '图片生成失败');
          }
          return data.images;
        } finally {
          syncConfirmationResolversRef.current.delete(taskId);
          removeActiveTask(taskId);
        }
      };

      const settled = await Promise.allSettled(taskIds.map((taskId, index) => runSingleTask(taskId, index)));
      const generatedImages = settled.flatMap(result => result.status === 'fulfilled' ? result.value : []);
      const failedResults = settled.filter((result): result is PromiseRejectedResult => result.status === 'rejected');

      if (generatedImages.length > 0) {
        setResults(prev => [...generatedImages, ...prev]);
        setGenerationError(null);
        for (const url of generatedImages) {
          addRecord({
            type: 'image', url, prompt: prompt.trim(),
            negativePrompt: negativePrompt.trim() || undefined,
            model: selectedModel,
            modelLabel: getCurrentModelLabel(),
            isCustomModel: isCustomModel(selectedModel) || isSystemModel(selectedModel),
            params: {
              creationMode: 'text2img',
              aspectRatio: resolvedParams.aspectRatio,
              resolution: resolvedParams.resolution,
              count: 1,
              batchCount: taskCount,
              outputFormat,
              imageQuality,
              styleLabel: selectedStylePreset?.label,
              guidanceScale,
            },
          });
        }
        toast.success(`生成 ${generatedImages.length} 张图片`);

        const chargedCredits = calcImageCredits(selectedModel, resolvedParams.resolution, resolvedParams.aspectRatio, generatedImages.length);
        if (membershipEnabled && chargedCredits > 0 && user) {
          const currentCredits = typeof user.creditsBalance === 'number' ? user.creditsBalance : 0;
          addCreditRecord({
            type: 'consume',
            amount: -chargedCredits,
            balanceAfter: Math.max(0, currentCredits - chargedCredits),
            description: `文生图 - ${getCurrentModelLabel()}`,
          });
        }
      }

      if (failedResults.length > 0) {
        const stillRunning = failedResults.some(result => result.reason instanceof GenerationJobStillRunningError);
        if (generatedImages.length === 0) {
          const firstError = failedResults[0]?.reason;
          setGenerationError(createGenerationError(firstError instanceof Error ? firstError.message : '图片生成失败'));
        } else {
          toast.error(`${failedResults.length} 个生成任务失败`);
        }
        if (stillRunning) toast.info('部分生成任务仍在执行，可稍后在创作历史中查看');
      }
    } catch (err: unknown) {
      if (err instanceof GenerationJobStillRunningError) {
        setGenerationError(null);
        toast.info('生成任务仍在执行，可稍后在创作历史中查看');
      } else if (err instanceof DOMException && err.name === 'AbortError') {
        setGenerationError(createGenerationError('请求超时，请尝试减少生成数量或降低分辨率'));
      } else {
        setGenerationError(createGenerationError(err instanceof Error ? err.message : '网络错误，请重试'));
      }
    }
    finally {
      if (submissionSignature) activeSubmissionSignaturesRef.current.delete(submissionSignature);
    }
  }, [prompt, negativePrompt, selectedModel, outputFormat, imageQuality, selectedStylePreset, guidanceScale, user, imageKeys, systemImageApis, getCurrentModelLabel, addRecord, membershipEnabled, resolveGenerationParams, removeActiveTask, updateActiveTask, requestSyncConfirmation]);

  // Download
  const handleDownload = useCallback(async (url: string, index: number) => {
    const result = await downloadFile(url, `miaojing-${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: 'text2img',
        styleLabel: selectedStylePreset?.label,
      },
    });
    toast.success('已分享到画廊');
  }, [prompt, selectedModel, selectedStylePreset, getCurrentModelLabel]);

  return (
    <>
    <InspirationGalleryDialog mode="text2img" 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 (scrollable) */}
      <div className="min-w-0 space-y-5 pb-8 pr-2">
        {/* 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 flex-wrap items-center justify-between gap-2">
            <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={4}
            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>
                {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>

        {/* Guidance Scale */}
        <div className="space-y-2">
          <div className="flex flex-wrap items-center justify-between gap-2">
            <Label>引导系数</Label>
            <span className="text-xs text-muted-foreground">{guidanceScale}</span>
          </div>
          <Slider value={[guidanceScale]} onValueChange={([v]) => setGuidanceScale(v)} min={1} max={20} step={1} />
          <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 */}
        <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 (flex-1, takes remaining space) */}
      <div className="min-w-0 space-y-4">
        {/* Results area */}
        {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>
        )}

        {/* History */}
        {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)} />

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