import {
  ArrowLeftOutlined,
  CameraOutlined,
  CheckCircleFilled,
  ClearOutlined,
  ColumnWidthOutlined,
  CustomerServiceOutlined,
  DeleteOutlined,
  DownloadOutlined,
  EditOutlined,
  FileImageOutlined,
  FontSizeOutlined,
  HighlightOutlined,
  LinkOutlined,
  LoadingOutlined,
  MinusOutlined,
  PictureOutlined,
  PlusOutlined,
  InboxOutlined,
  RightOutlined,
  ScissorOutlined,
  SwapOutlined,
  TableOutlined,
} from "@ant-design/icons";
import { useCallback, useEffect, useRef, useState, type DragEvent } from "react";
import "../../styles/pages/more-tools.css";
import "../../styles/pages/image-workbench.css";
import type { WebImageWorkbenchTool, WebViewKey } from "../../types";
import { aiGenerationClient } from "../../api/aiGenerationClient";
import { waitForTask } from "../../api/taskSubscription";
import { saveToolTaskState, loadToolTaskState, clearToolTaskState } from "../workbench/toolKeepalive";
import { addToolResultToAssetLibrary, saveToolResultToLocal } from "../workbench/toolResultActions";
import { useCanvasDrawing } from "./useCanvasDrawing";
import CameraViewport3D from "./CameraViewport3D";

type WorkMode = "single" | "blend";
type OutputSize = "9:16" | "16:9" | "4:3" | "3:4" | "1:1";
type OutputCount = 1 | 2 | 3 | 4;

const OUTPUT_SIZE_OPTIONS: OutputSize[] = ["9:16", "16:9", "4:3", "3:4", "1:1"];

const SIZE_TO_RATIO: Record<OutputSize, string> = {
  "9:16": "9:16",
  "16:9": "16:9",
  "4:3": "4:3",
  "3:4": "3:4",
  "1:1": "1:1",
};

const cameraPresets = [
  { name: "自定义", rotationX: 0, rotationY: 0, rotationZ: 0, shotScale: 5 },
  { name: "正面平视", rotationX: 0, rotationY: 0, rotationZ: 0, shotScale: 5 },
  { name: "正面俯拍", rotationX: -35, rotationY: 0, rotationZ: 0, shotScale: 4 },
  { name: "正面仰拍", rotationX: 28, rotationY: 0, rotationZ: 0, shotScale: 6 },
  { name: "左侧平视", rotationX: 0, rotationY: 90, rotationZ: 0, shotScale: 5 },
  { name: "右侧平视", rotationX: 0, rotationY: -90, rotationZ: 0, shotScale: 5 },
  { name: "正背面", rotationX: 0, rotationY: 180, rotationZ: 0, shotScale: 5 },
  { name: "左肩越肩", rotationX: -5, rotationY: 35, rotationZ: 0, shotScale: 7 },
  { name: "右肩越肩", rotationX: -5, rotationY: -35, rotationZ: 0, shotScale: 7 },
  { name: "背身反打", rotationX: 2, rotationY: 180, rotationZ: 0, shotScale: 6 },
  { name: "俯拍全景", rotationX: -55, rotationY: 20, rotationZ: 0, shotScale: 1 },
  { name: "虫视角", rotationX: 65, rotationY: 0, rotationZ: 0, shotScale: 8 },
  { name: "鸟瞰", rotationX: -85, rotationY: 0, rotationZ: 0, shotScale: 2 },
  { name: "低斜近拍", rotationX: 4, rotationY: 78, rotationZ: 18, shotScale: 6 },
  { name: "鱼眼贴脸", rotationX: 8, rotationY: 42, rotationZ: 0, shotScale: 2 },
  { name: "英雄仰角", rotationX: 40, rotationY: -15, rotationZ: -8, shotScale: 7 },
  { name: "戏剧肩角", rotationX: -50, rotationY: 45, rotationZ: 12, shotScale: 3 },
];

const CAMERA_EFFECT_PRESETS = [
  { key: "dof", label: "浅景深", prompt: "浅景深，背景虚化，主体清晰突出" },
  { key: "wide-angle", label: "广角畸变", prompt: "广角镜头畸变效果，边缘拉伸，空间感强" },
  { key: "telephoto", label: "长焦压缩", prompt: "长焦镜头压缩感，前后景距离感缩小，画面扁平" },
  { key: "motion-blur", label: "运动模糊", prompt: "运动模糊效果，速度感，动态拖影" },
  { key: "handheld", label: "手持抖动", prompt: "手持摄影轻微晃动感，纪实风格，真实感" },
  { key: "fisheye", label: "鱼眼", prompt: "鱼眼镜头效果，180度超广角，强烈桶形畸变" },
  { key: "low-angle", label: "低机位", prompt: "低机位拍摄，从地面向上取景，增强高度感和力量感" },
  { key: "high-angle", label: "高机位", prompt: "高机位俯拍，从上方取景，展示全貌和渺小感" },
  { key: "aerial", label: "航拍感", prompt: "航拍视角，无人机空中俯瞰，大场景纵深感" },
  { key: "cinematic", label: "电影感", prompt: "电影感色调，2.39:1宽银幕构图感觉，戏剧性光影" },
  { key: "vintage", label: "复古胶片", prompt: "复古胶片质感，颗粒感，暖色调，怀旧氛围" },
  { key: "hdr", label: "HDR", prompt: "HDR高动态范围，明暗细节丰富，色彩饱和" },
] as const;

const CAMERA_EFFECT_PROMPT_BY_KEY = new Map<string, string>(
  CAMERA_EFFECT_PRESETS.map((effect) => [effect.key, effect.prompt]),
);

function getCameraEffectsPrompt(effectKeys: Set<string>): string {
  if (effectKeys.size === 0) return "";
  const prompts: string[] = [];
  for (const key of effectKeys) {
    const prompt = CAMERA_EFFECT_PROMPT_BY_KEY.get(key);
    if (prompt) prompts.push(prompt);
  }
  return prompts.join("，");
}

function shotScaleToZoom(shotScale: number): number {
  const map: Record<number, number> = { 1: 24, 2: 28, 3: 32, 4: 35, 5: 40, 6: 50, 7: 60, 8: 75, 9: 85, 10: 100 };
  return map[Math.round(Math.max(1, Math.min(10, shotScale)))] || 40;
}

const cameraDirections = [
  { key: "up", label: "↑" },
  { key: "left", label: "←" },
  { key: "center", label: "⌂" },
  { key: "right", label: "→" },
  { key: "down", label: "↓" },
] as const;

interface ImageWorkbenchPageProps {
  initialTool?: WebImageWorkbenchTool;
  onOpenMore?: () => void;
  onSelectView?: (view: WebViewKey) => void;
}

function ImageWorkbenchPage({ initialTool = "workbench", onOpenMore, onSelectView }: ImageWorkbenchPageProps) {
  const fileInputRef = useRef<HTMLInputElement>(null);
  const inpaintFileInputRef = useRef<HTMLInputElement>(null);
  const cameraFileInputRef = useRef<HTMLInputElement>(null);
  const [activeTool, setActiveTool] = useState<WebImageWorkbenchTool>(initialTool);
  const [mode, setMode] = useState<WorkMode>("single");
  const [imageUrlInput, setImageUrlInput] = useState("");
  const [referenceImages, setReferenceImages] = useState<string[]>([]);
  const [inpaintImage, setInpaintImage] = useState<string | null>(null);
  const [inpaintUrlInput, setInpaintUrlInput] = useState("");
  const [brushSize, setBrushSize] = useState(40);
  const [isMaskEditing, setIsMaskEditing] = useState(false);
  const [inpaintTool, setInpaintTool] = useState<"brush" | "eraser">("brush");
  const [inpaintZoom, setInpaintZoom] = useState(1);
  const [canvasInitCounter, setCanvasInitCounter] = useState(0);
  const inpaintCanvasRef = useRef<HTMLCanvasElement>(null);
  const [cameraImage, setCameraImage] = useState<string | null>(null);
  const [cameraUrlInput, setCameraUrlInput] = useState("");
  const [cameraPreset, setCameraPreset] = useState("自定义");
  const [cameraDirection, setCameraDirection] = useState("center");
  const [cameraHorizontal, setCameraHorizontal] = useState(0);
  const [cameraVertical, setCameraVertical] = useState(0);
  const [cameraRoll, setCameraRoll] = useState(0);
  const [cameraZoom, setCameraZoom] = useState(40);
  const [cameraPromptEnabled, setCameraPromptEnabled] = useState(true);
  const [cameraPrompt, setCameraPrompt] = useState("");
  const [cameraEffects, setCameraEffects] = useState<Set<string>>(new Set());
  const [prompt, setPrompt] = useState("");
  const [outputSize, setOutputSize] = useState<OutputSize>("1:1");
  const [outputCount, setOutputCount] = useState<OutputCount>(1);
  const [status, setStatus] = useState("上传参考图并输入提示词后开始");
  const [generating, setGenerating] = useState(false);
  const [generationProgress, setGenerationProgress] = useState(0);
  const [resultImages, setResultImages] = useState<string[]>([]);
  const [inpaintResultImages, setInpaintResultImages] = useState<string[]>([]);
  const [cameraResultImages, setCameraResultImages] = useState<string[]>([]);
  const [downloadingResultUrl, setDownloadingResultUrl] = useState<string | null>(null);
  const [savingAssetResultUrl, setSavingAssetResultUrl] = useState<string | null>(null);
  const [generationError, setGenerationError] = useState<string | null>(null);
  const [isDragging, setIsDragging] = useState(false);
  const [isCameraDragging, setIsCameraDragging] = useState(false);
  const abortRef = useRef(false);
  const taskIdRef = useRef<string | null>(null);
  const keepaliveRestoredRef = useRef(false);

  // Keep-alive: restore saved task on mount
  useEffect(() => {
    if (keepaliveRestoredRef.current) return;
    keepaliveRestoredRef.current = true;
    const saved = loadToolTaskState("imagewb");
    if (!saved || saved.resultUrl) return;
    setGenerating(true);
    abortRef.current = false;
    taskIdRef.current = saved.taskId;
    void waitForTask(saved.taskId, {
      kind: "image",
      onProgress: (e) => {
        setStatus(`${e.status} / ${e.progress}%`);
        if (e.status === "completed" && e.resultUrl) {
          setResultImages([e.resultUrl]);
          clearToolTaskState("imagewb");
          setGenerating(false);
          setStatus("恢复任务完成");
        }
        if (e.status === "failed") {
          clearToolTaskState("imagewb");
          setGenerating(false);
          setStatus("恢复任务失败");
        }
      },
    });
  }, []);

  useEffect(() => {
    return () => {
      abortRef.current = true;
    };
  }, []);

  const handleCancel = useCallback(() => {
    abortRef.current = true;
    if (taskIdRef.current) {
      aiGenerationClient.cancelTask(taskIdRef.current).catch(() => {});
      taskIdRef.current = null;
    }
    clearToolTaskState("imagewb");
    setGenerating(false);
    setGenerationProgress(0);
    setStatus("已取消");
  }, []);
  const referenceImage = referenceImages[0] ?? null;

  const {
    imageSize: inpaintCanvasSize,
    hasMask,
    initCanvas: initInpaintCanvas,
    startDrawing: maskStartDrawing,
    draw: maskDraw,
    stopDrawing: maskStopDrawing,
    handleTouchStart: maskTouchStart,
    handleTouchMove: maskTouchMove,
    handleTouchEnd: maskTouchEnd,
    clearMask,
    exportMaskDataUrl,
  } = useCanvasDrawing({ baseImage: inpaintImage, brushSize, activeTool: inpaintTool });

  useEffect(() => {
    if (!inpaintImage) return;
    const timer = window.setTimeout(() => initInpaintCanvas(inpaintCanvasRef.current), 0);
    return () => window.clearTimeout(timer);
  }, [inpaintImage, initInpaintCanvas, canvasInitCounter]);

  useEffect(() => {
    setActiveTool(initialTool);
  }, [initialTool]);

  const handleFileChange = (event: React.ChangeEvent<HTMLInputElement>) => {
    const files = Array.from(event.target.files ?? []);
    if (!files.length) return;

    const selectedFiles = mode === "blend" ? files : files.slice(0, 1);
    selectedFiles.forEach((file) => {
      const reader = new FileReader();
      reader.onload = () => {
        if (typeof reader.result !== "string") return;
        setReferenceImages((current) => (mode === "blend" ? [...current, reader.result as string] : [reader.result as string]));
        setStatus(mode === "blend" ? `已追加 ${file.name}` : `已导入 ${file.name}`);
      };
      reader.readAsDataURL(file);
    });
    event.target.value = "";
  };


  const handleDragOver = (event: DragEvent) => {
    event.preventDefault();
    event.stopPropagation();
    setIsDragging(true);
  };

  const handleDragLeave = (event: DragEvent) => {
    event.preventDefault();
    event.stopPropagation();
    setIsDragging(false);
  };

  const handleDrop = (event: DragEvent) => {
    event.preventDefault();
    event.stopPropagation();
    setIsDragging(false);
    const files = Array.from(event.dataTransfer.files).filter((f) => f.type.startsWith('image/'));
    if (!files.length) return;
    const selectedFiles = mode === 'blend' ? files : files.slice(0, 1);
    selectedFiles.forEach((file) => {
      const reader = new FileReader();
      reader.onload = () => {
        if (typeof reader.result !== 'string') return;
        setReferenceImages((current) => (mode === 'blend' ? [...current, reader.result as string] : [reader.result as string]));
        setStatus(mode === 'blend' ? `已追加 ${file.name}` : `已导入 ${file.name}`);
      };
      reader.readAsDataURL(file);
    });
  };

  const handleAddUrl = () => {
    const nextUrl = imageUrlInput.trim();
    if (!nextUrl) return;
    setReferenceImages((current) => (mode === "blend" ? [...current, nextUrl] : [nextUrl]));
    setImageUrlInput("");
    setStatus("已添加 URL 参考图");
  };

  const handleRemoveReferenceImage = (index = 0) => {
    setReferenceImages((current) => current.filter((_, imageIndex) => imageIndex !== index));
    if (fileInputRef.current) {
      fileInputRef.current.value = "";
    }
    setStatus("已删除参考图");
  };

  const handleInpaintFileChange = (event: React.ChangeEvent<HTMLInputElement>) => {
    const file = event.target.files?.[0];
    if (!file) return;

    const reader = new FileReader();
    reader.onload = () => {
      if (typeof reader.result !== "string") return;
      setInpaintImage(reader.result);
      setInpaintResultImages([]);
      setIsMaskEditing(false);
      setStatus(`已导入局部重绘素材 ${file.name}`);
    };
    reader.readAsDataURL(file);
    event.target.value = "";
  };

  const [isInpaintDragging, setIsInpaintDragging] = useState(false);

  const handleInpaintDragOver = (e: DragEvent<HTMLElement>) => { e.preventDefault(); e.stopPropagation(); if (e.dataTransfer.types.includes("Files")) setIsInpaintDragging(true); };
  const handleInpaintDragLeave = (e: DragEvent<HTMLElement>) => { e.preventDefault(); e.stopPropagation(); if (e.currentTarget === e.target || !e.currentTarget.contains(e.relatedTarget as Node)) setIsInpaintDragging(false); };
  const handleInpaintDrop = (e: DragEvent<HTMLElement>) => {
    e.preventDefault();
    e.stopPropagation();
    setIsInpaintDragging(false);
    const file = Array.from(e.dataTransfer.files).find((f) => f.type.startsWith("image/"));
    if (!file) return;
    const reader = new FileReader();
    reader.onload = () => {
      if (typeof reader.result !== "string") return;
      setInpaintImage(reader.result);
      setInpaintResultImages([]);
      setIsMaskEditing(false);
      setStatus(`已导入局部重绘素材 ${file.name}`);
    };
    reader.readAsDataURL(file);
  };

  const handleAddInpaintUrl = () => {
    const nextUrl = inpaintUrlInput.trim();
    if (!nextUrl) return;
    setInpaintImage(nextUrl);
    setInpaintResultImages([]);
    setIsMaskEditing(false);
    setInpaintUrlInput("");
    setStatus("已添加局部重绘素材 URL");
  };

  const handleRemoveInpaintImage = () => {
    setInpaintImage(null);
    setIsMaskEditing(false);
    clearMask(inpaintCanvasRef.current);
    if (inpaintFileInputRef.current) {
      inpaintFileInputRef.current.value = "";
    }
    setStatus("已删除局部重绘素材");
  };

  const handleStartInpaint = async () => {
    if (!inpaintImage) {
      setStatus("请先上传原图再开始局部重绘");
      return;
    }
    if (!hasMask) {
      setStatus("请先编辑页面，涂抹需要重绘的区域");
      return;
    }
    if (generating) return;

    if (isMaskEditing) setIsMaskEditing(false);

    abortRef.current = false;
    setGenerating(true);
    setGenerationProgress(0);
    setGenerationError(null);
    setResultImages([]);
    setInpaintResultImages([]);
    setCameraResultImages([]);
    setStatus("正在上传素材...");
    try {
      const maskDataUrl = exportMaskDataUrl();
      const imagesToUpload = maskDataUrl ? [inpaintImage, maskDataUrl] : [inpaintImage];
      const refUrls = await uploadReferenceImages(imagesToUpload);
      const ratio = SIZE_TO_RATIO[outputSize];
      const model = "wan2.7-image";

      setStatus("正在生成局部重绘...");
      const { taskId } = await aiGenerationClient.createImageTask({
        model,
        prompt: prompt || "图1是原图，图2的绿色标记是需要重绘的区域，在图1的标记区域内生成与周围画面风格一致的新内容，光影融合自然，无拼接痕迹",
        ratio,
        referenceUrls: refUrls,
      });
      taskIdRef.current = taskId;
      saveToolTaskState("imagewb", { taskId, status: "running", progress: 0 });

      const tempUrl = await pollTaskUntilDone(taskId);
      if (tempUrl) {
        const durableUrl = await persistResultUrl(tempUrl);
        setInpaintResultImages([durableUrl || tempUrl]);
      }
      setStatus(tempUrl ? "局部重绘完成" : "已取消");
    } catch (err) {
      const msg = err instanceof Error ? err.message : "生成失败";
      setGenerationError(msg);
      setStatus(`局部重绘失败: ${msg}`);
    } finally {
      setGenerating(false);
      setGenerationProgress(0);
    }
  };

  const handleCameraFileChange = (event: React.ChangeEvent<HTMLInputElement>) => {
    const file = event.target.files?.[0];
    if (!file) return;

    const reader = new FileReader();
    reader.onload = () => {
      if (typeof reader.result !== "string") return;
      setCameraImage(reader.result);
      setStatus(`已导入镜头参考图 ${file.name}`);
    };
    reader.readAsDataURL(file);
    event.target.value = "";
  };

  const handleCameraDragOver = (event: DragEvent) => {
    event.preventDefault();
    event.stopPropagation();
    setIsCameraDragging(true);
  };

  const handleCameraDragLeave = (event: DragEvent) => {
    event.preventDefault();
    event.stopPropagation();
    setIsCameraDragging(false);
  };

  const handleCameraDrop = (event: DragEvent) => {
    event.preventDefault();
    event.stopPropagation();
    setIsCameraDragging(false);
    const file = Array.from(event.dataTransfer.files).find((f) => f.type.startsWith('image/'));
    if (!file) return;
    const reader = new FileReader();
    reader.onload = () => {
      if (typeof reader.result !== 'string') return;
      setCameraImage(reader.result);
      setStatus(`已导入镜头参考图 ${file.name}`);
    };
    reader.readAsDataURL(file);
  };

  const handleAddCameraUrl = () => {
    const nextUrl = cameraUrlInput.trim();
    if (!nextUrl) return;
    setCameraImage(nextUrl);
    setCameraUrlInput("");
    setStatus("已添加镜头参考图 URL");
  };

  const handleRemoveCameraImage = () => {
    setCameraImage(null);
    if (cameraFileInputRef.current) {
      cameraFileInputRef.current.value = "";
    }
    setStatus("已删除镜头参考图");
  };

  const handleStartCamera = async () => {
    if (!cameraImage) {
      setStatus("请先导入参考图再构建镜头");
      return;
    }
    if (generating) return;

    abortRef.current = false;
    setGenerating(true);
    setGenerationProgress(0);
    setGenerationError(null);
    setCameraResultImages([]);
    setStatus("正在上传镜头参考图...");

    try {
      const refUrls = await uploadReferenceImages([cameraImage]);
      const model = "wan2.7-image-pro";
      const cameraDesc = `镜头预设: ${cameraPreset}, 方向: ${cameraDirection}, 水平: ${cameraHorizontal}°, 垂直: ${cameraVertical}°, 倾斜: ${cameraRoll}°, 焦距: ${cameraZoom}mm`;
      const effectsDesc = getCameraEffectsPrompt(cameraEffects);
      const fullPrompt = cameraPromptEnabled && cameraPrompt.trim()
        ? `${cameraDesc}${effectsDesc ? `。视觉效果: ${effectsDesc}` : ""}。${cameraPrompt}`
        : `${cameraDesc}${effectsDesc ? `。视觉效果: ${effectsDesc}` : ""}。保持人物和场景一致，按照镜头参数重新构图。`;

      setStatus("正在生成镜头画面...");
      const { taskId } = await aiGenerationClient.createImageTask({
        model,
        prompt: fullPrompt,
        ratio: "16:9",
        referenceUrls: refUrls,
      });
      taskIdRef.current = taskId;
      saveToolTaskState("imagewb", { taskId, status: "running", progress: 0 });

      const tempUrl = await pollTaskUntilDone(taskId);
      if (tempUrl) {
        const durableUrl = await persistResultUrl(tempUrl);
        setCameraResultImages([durableUrl || tempUrl]);
      }
      setStatus(tempUrl ? `镜头生成完成 · ${cameraPreset} · ${cameraZoom}mm` : "已取消");
    } catch (err) {
      const msg = err instanceof Error ? err.message : "生成失败";
      setGenerationError(msg);
      setStatus(`镜头生成失败: ${msg}`);
    } finally {
      setGenerating(false);
      setGenerationProgress(0);
    }
  };

  const uploadReferenceImages = useCallback(async (images: string[]): Promise<string[]> => {
    const urls: string[] = [];
    for (const img of images) {
      if (img.startsWith("data:")) {
        const result = await aiGenerationClient.uploadAsset({ dataUrl: img, scope: "workbench-ref" });
        urls.push(result.url);
      } else {
        urls.push(img);
      }
    }
    return urls;
  }, []);

  const pollTaskUntilDone = useCallback(async (taskId: string): Promise<string | null> => {
    return waitForTask(taskId, {
      kind: "image",
      abortRef,
      onProgress: (e) => setGenerationProgress(e.progress || 0),
    });
  }, []);

  const persistResultUrl = useCallback(async (tempUrl: string | null): Promise<string | null> => {
    if (!tempUrl) return null;
    try {
      const uploaded = await aiGenerationClient.uploadAssetByUrl({
        sourceUrl: tempUrl,
        name: `workbench-result-${Date.now()}`,
        mimeType: "image/png",
        scope: "workbench-result",
      });
      return uploaded.url || tempUrl;
    } catch {
      return tempUrl;
    }
  }, []);

  const getResultBaseName = (index = 0) => {
    const toolName = activeTool === "camera" ? "camera" : activeTool === "inpaint" ? "inpaint" : "image-workbench";
    return `${toolName}-result-${index + 1}-${Date.now()}`;
  };

  const getResultTags = () => {
    const toolName = activeTool === "camera" ? "镜头实验室" : activeTool === "inpaint" ? "局部重绘" : "图片工作台";
    return ["工具盒", toolName, "生成图片"];
  };

  const handleDownloadResult = async (url: string, index = 0) => {
    if (downloadingResultUrl) return;
    setDownloadingResultUrl(url);
    try {
      const status = await saveToolResultToLocal({
        url,
        name: getResultBaseName(index),
        type: "image",
        isVideo: false,
      });
      setStatus(status === "saved" ? "已保存到本地" : "已开始保存到本地");
    } catch (error) {
      setStatus(error instanceof Error ? error.message : "保存本地失败");
    } finally {
      setDownloadingResultUrl(null);
    }
  };

  const handleAddResultToAssets = async (url: string, index = 0) => {
    if (savingAssetResultUrl) return;
    setSavingAssetResultUrl(url);
    try {
      const status = await addToolResultToAssetLibrary({
        url,
        name: getResultBaseName(index),
        type: "image",
        isVideo: false,
        description: "从工具盒图片生成结果加入的素材。",
        tags: getResultTags(),
      });
      setStatus(status === "server" ? "已加入资产库" : "已加入本地资产库");
    } catch (error) {
      setStatus(error instanceof Error ? error.message : "加入资产库失败");
    } finally {
      setSavingAssetResultUrl(null);
    }
  };

  const renderResultActions = (url: string, index = 0) => (
    <div className="image-workbench-result-actions">
      <button type="button" onClick={() => void handleDownloadResult(url, index)} disabled={downloadingResultUrl === url}>
        <DownloadOutlined />
        {downloadingResultUrl === url ? "保存中" : "保存本地"}
      </button>
      <button type="button" onClick={() => void handleAddResultToAssets(url, index)} disabled={savingAssetResultUrl === url}>
        <InboxOutlined />
        {savingAssetResultUrl === url ? "加入中" : "加入资产库"}
      </button>
    </div>
  );

  const handleGenerate = async () => {
    if (!referenceImages.length && !prompt.trim()) {
      setStatus("请先上传参考图或输入提示词");
      return;
    }
    if (generating) return;

    abortRef.current = false;
    setGenerating(true);
    setGenerationProgress(0);
    setGenerationError(null);
    setResultImages([]);
    setStatus("正在上传参考图...");

    try {
      const refUrls = referenceImages.length ? await uploadReferenceImages(referenceImages) : undefined;
      const ratio = SIZE_TO_RATIO[outputSize];
      const model = "wan2.7-image";
      const results: string[] = [];

      for (let i = 0; i < outputCount; i++) {
        if (abortRef.current) break;
        setStatus(`正在生成第 ${i + 1}/${outputCount} 张...`);
        setGenerationProgress(0);

        const { taskId } = await aiGenerationClient.createImageTask({
          model,
          prompt: prompt || "按照参考图风格生成",
          ratio,
          referenceUrls: refUrls,
        });
        taskIdRef.current = taskId;
        saveToolTaskState("imagewb", { taskId, status: "running", progress: 0 });

        const tempUrl = await pollTaskUntilDone(taskId);
        if (tempUrl) {
          results.push(tempUrl);
          setResultImages([...results]);
          persistResultUrl(tempUrl).then((durableUrl) => {
            if (durableUrl && durableUrl !== tempUrl) {
              setResultImages((prev) => prev.map((u) => u === tempUrl ? durableUrl : u));
            }
          });
        }
      }

      setResultImages(results);
      clearToolTaskState("imagewb");
      if (results.length) {
        saveToolTaskState("imagewb", { taskId: taskIdRef.current || "", resultUrl: results[0], status: "完成", progress: 100 });
      }
      setStatus(results.length ? `生成完成，共 ${results.length} 张` : "生成已取消");
    } catch (err) {
      const msg = err instanceof Error ? err.message : "生成失败";
      setGenerationError(msg);
      setStatus(`生成失败: ${msg}`);
    } finally {
      setGenerating(false);
      setGenerationProgress(0);
    }
  };

  const handleClear = () => {
    handleCancel();
    setReferenceImages([]);
    setPrompt("");
    setImageUrlInput("");
    setOutputSize("1:1");
    setOutputCount(1);
    setMode("single");
    setGenerating(false);
    setGenerationProgress(0);
    setResultImages([]);
    setInpaintResultImages([]);
    setCameraResultImages([]);
    setGenerationError(null);
    setStatus("上传参考图并输入提示词后开始");
  };
  const activeToolTitle = activeTool === "inpaint" ? "局部重绘" : activeTool === "camera" ? "镜头实验室" : "图片工作台";

  return (
    <section className="image-workbench-page image-workbench-page--image-tool">
      <header className="image-workbench-topbar">
        <button type="button" className="image-workbench-back-to-more" onClick={onOpenMore}>
          工具盒
        </button>
        <div className="image-workbench-tool-strip" aria-label="图片工具">
          <button type="button" className={activeTool === "workbench" ? "is-active" : ""} onClick={() => setActiveTool("workbench")}>
            <EditOutlined />
            图片工作台
          </button>
          <button type="button" className={activeTool === "inpaint" ? "is-active" : ""} onClick={() => setActiveTool("inpaint")}>
            <ScissorOutlined />
            局部重绘
          </button>
          <button type="button" className={activeTool === "camera" ? "is-active" : ""} onClick={() => setActiveTool("camera")}>
            <CameraOutlined />
            镜头实验室
          </button>
          <button type="button" onClick={() => onSelectView?.("digitalHuman")}>
            <CustomerServiceOutlined />
            数字人
          </button>
          <button type="button" onClick={() => onSelectView?.("characterMix")}>
            <SwapOutlined />
            角色迁移
          </button>
          <button type="button" onClick={() => onSelectView?.("resolutionUpscale")}>
            <ColumnWidthOutlined />
            分辨率提升
          </button>
          <button type="button" onClick={() => onSelectView?.("watermarkRemoval")}>
            <DeleteOutlined />
            去水印
          </button>
          <button type="button" onClick={() => onSelectView?.("subtitleRemoval")}>
            <FontSizeOutlined />
            字幕去除
          </button>
        </div>
      </header>

      <div className="image-workbench-subbar">
        <div className="image-workbench-subbar__heading">
          <button type="button" className="image-workbench-icon-btn" aria-label="返回工具盒" onClick={onOpenMore}>
            <ArrowLeftOutlined />
          </button>
          <strong className="image-workbench-subbar__title">{activeToolTitle}</strong>
        </div>
        {activeTool === "workbench" ? (
          <div className="image-workbench-mode-tabs" role="tablist" aria-label="图片工作模式">
            <button type="button" className={mode === "single" ? "is-active" : ""} onClick={() => setMode("single")}>
              <PictureOutlined />
              单图编辑
            </button>
            <button type="button" className={mode === "blend" ? "is-active" : ""} onClick={() => setMode("blend")}>
              <TableOutlined />
              多图融合
            </button>
          </div>
        ) : activeTool === "camera" ? (
          <div className="image-workbench-camera-summary" aria-label="镜头参数">
            <strong>{cameraPreset === "自定义" ? "中景 / 正面" : cameraPreset}</strong>
            <span>{cameraZoom}mm</span>
          </div>
        ) : null}
        <button
          type="button"
          className={`image-workbench-icon-btn image-workbench-subbar__next${activeTool === "inpaint" ? " image-workbench-subbar__next--solo" : ""}`}
          aria-label="下一项"
        >
          <RightOutlined />
        </button>
      </div>

      {activeTool === "inpaint" ? (
        <main className="image-workbench-layout image-workbench-layout--inpaint">
          <aside className="image-workbench-panel image-workbench-panel--left">
            <section className="image-workbench-control-card">
              <div className="image-workbench-section-title">
                <h3>素材</h3>
                <span>{inpaintImage ? "待编辑" : "待上传"}</span>
              </div>
              <input
                ref={inpaintFileInputRef}
                type="file"
                accept="image/png,image/jpeg,image/webp"
                onChange={handleInpaintFileChange}
              />
              <div
                className={`image-workbench-upload-shell${isInpaintDragging ? " is-dragging" : ""}`}
                onDragOver={handleInpaintDragOver}
                onDragLeave={handleInpaintDragLeave}
                onDrop={handleInpaintDrop}
              >
                {isInpaintDragging ? <div className="image-workbench-upload-drop-overlay"><span>释放文件以上传</span></div> : null}
                <button type="button" className="image-workbench-upload" onClick={() => inpaintFileInputRef.current?.click()}>
                  {inpaintImage ? <img src={inpaintImage} alt="" /> : <FileImageOutlined />}
                  <strong>{inpaintImage ? "更换原图" : "选择图片"}</strong>
                  <span>PNG / JPG / WebP</span>
                </button>
                {inpaintImage ? (
                  <button
                    type="button"
                    className="image-workbench-upload-remove"
                    aria-label="删除局部重绘素材"
                    onClick={handleRemoveInpaintImage}
                  >
                    ×
                  </button>
                ) : null}
              </div>
              <div className="image-workbench-url-row">
                <label>
                  <LinkOutlined />
                  <input
                    value={inpaintUrlInput}
                    placeholder="粘贴图片 URL"
                    onChange={(event) => setInpaintUrlInput(event.target.value)}
                  />
                </label>
                <button type="button" onClick={handleAddInpaintUrl}>添加</button>
              </div>
            </section>

            <section className="image-workbench-control-card image-workbench-brush-card">
              <h3>笔刷</h3>
              <label className="image-workbench-range">
                <span>大小</span>
                <input
                  type="range"
                  min="8"
                  max="96"
                  step="2"
                  value={brushSize}
                  onChange={(event) => setBrushSize(Number(event.target.value))}
                />
                <em>{brushSize}px</em>
              </label>
            </section>

            <section className="image-workbench-control-card">
              <h3>参数</h3>
              <span className="image-workbench-field-label">输出分辨率</span>
              <div className="image-workbench-segmented">
                {OUTPUT_SIZE_OPTIONS.map((s) => (
                  <button key={s} type="button" className={outputSize === s ? "is-active" : ""} onClick={() => setOutputSize(s)}>
                    {s}
                  </button>
                ))}
              </div>
            </section>

            <section className="image-workbench-control-card">
              <h3>提示词</h3>
              <textarea
                className="image-workbench-prompt"
                placeholder="描述需要重绘的内容，例如：将背景替换为森林"
                value={prompt}
                onChange={(e) => setPrompt(e.target.value)}
                rows={3}
              />
            </section>

            <div className="image-workbench-actions">
              <button type="button" className="image-workbench-primary" onClick={handleStartInpaint} disabled={generating}>
                {generating && activeTool === "inpaint" ? <LoadingOutlined /> : <ScissorOutlined />}
                {generating && activeTool === "inpaint" ? "重绘中..." : "开始重绘"}
              </button>
            </div>
          </aside>

          <section className="image-workbench-canvas image-workbench-canvas--inpaint" aria-label="局部重绘画布">
            {generating && activeTool === "inpaint" ? (
              <div className="image-workbench-generating">
                <LoadingOutlined style={{ fontSize: 32 }} />
                <strong>重绘中...</strong>
                <div className="image-workbench-progress-bar">
                  <div className="image-workbench-progress-fill" style={{ width: `${generationProgress}%` }} />
                </div>
                <span>{generationProgress}%</span>
                <button type="button" className="image-workbench-cancel" onClick={handleCancel}>取消</button>
              </div>
            ) : inpaintResultImages.length && activeTool === "inpaint" ? (
              <div className="image-workbench-inpaint-stage">
                <img src={inpaintResultImages[0]} alt="重绘结果" style={{ maxWidth: "95%", maxHeight: "95%", borderRadius: 8, objectFit: "contain" }} />
                <div className="image-workbench-inpaint-bottom-bar">
                  <button type="button" className="image-workbench-inpaint-edit-btn" onClick={() => { setInpaintResultImages([]); setIsMaskEditing(true); setInpaintTool("brush"); setCanvasInitCounter((c) => c + 1); }}>
                    <HighlightOutlined /> 重新编辑页面
                  </button>
                  {renderResultActions(inpaintResultImages[0], 0)}
                  {inpaintResultImages.length > 1 && (
                    <span className="image-workbench-inpaint-zoom-controls">
                      {inpaintResultImages.map((url, i) => (
                        <a key={url} href={url} target="_blank" rel="noopener noreferrer" style={{ fontSize: 12, color: "var(--accent)" }}>
                          结果{i + 1}
                        </a>
                      ))}
                    </span>
                  )}
                </div>
              </div>
            ) : inpaintImage ? (
              <div
                className="image-workbench-inpaint-stage"
                onWheel={(e) => {
                  setInpaintZoom((z) => Math.min(3, Math.max(0.5, z + (e.deltaY < 0 ? 0.1 : -0.1))));
                }}
              >
                {isMaskEditing && (
                  <div className="image-workbench-inpaint-toolbar">
                    <button type="button" className={`image-workbench-inpaint-tool${inpaintTool === "brush" ? " is-active" : ""}`} onClick={() => setInpaintTool("brush")}>
                      <HighlightOutlined /> 画笔
                    </button>
                    <button type="button" className={`image-workbench-inpaint-tool${inpaintTool === "eraser" ? " is-active" : ""}`} onClick={() => setInpaintTool("eraser")}>
                      <EditOutlined /> 橡皮
                    </button>
                    <button type="button" className="image-workbench-inpaint-tool" onClick={() => clearMask(inpaintCanvasRef.current)}>
                      <ClearOutlined /> 清除
                    </button>
                    <button type="button" className="image-workbench-inpaint-tool image-workbench-inpaint-tool--done" onClick={() => setIsMaskEditing(false)}>
                      <CheckCircleFilled /> 完成
                    </button>
                  </div>
                )}
                <canvas
                  ref={inpaintCanvasRef}
                  className="image-workbench-inpaint-canvas"
                  style={{
                    width: (inpaintCanvasSize.width || 400) * inpaintZoom,
                    height: (inpaintCanvasSize.height || 300) * inpaintZoom,
                    cursor: isMaskEditing ? (inpaintTool === "eraser" ? "cell" : "crosshair") : "default",
                  }}
                  onMouseDown={isMaskEditing ? maskStartDrawing : undefined}
                  onMouseMove={isMaskEditing ? maskDraw : undefined}
                  onMouseUp={isMaskEditing ? maskStopDrawing : undefined}
                  onMouseLeave={isMaskEditing ? maskStopDrawing : undefined}
                  onTouchStart={isMaskEditing ? maskTouchStart : undefined}
                  onTouchMove={isMaskEditing ? maskTouchMove : undefined}
                  onTouchEnd={isMaskEditing ? maskTouchEnd : undefined}
                />
                <div className="image-workbench-inpaint-bottom-bar">
                  {!isMaskEditing && (
                    <button type="button" className="image-workbench-inpaint-edit-btn" onClick={() => { setInpaintTool("brush"); setIsMaskEditing(true); }}>
                      <HighlightOutlined /> {hasMask ? "重新编辑页面" : "编辑页面"}
                    </button>
                  )}
                  <span className="image-workbench-inpaint-zoom-controls">
                    <button type="button" onClick={() => setInpaintZoom((z) => Math.max(0.5, z - 0.2))}><MinusOutlined /></button>
                    <span>{Math.round(inpaintZoom * 100)}%</span>
                    <button type="button" onClick={() => setInpaintZoom((z) => Math.min(3, z + 0.2))}><PlusOutlined /></button>
                  </span>
                </div>
              </div>
            ) : (
              <div
                className={`studio-canvas-ghost${isInpaintDragging ? " is-dragging" : ""}`}
                onClick={() => inpaintFileInputRef.current?.click()}
                onDragOver={handleInpaintDragOver}
                onDragLeave={handleInpaintDragLeave}
                onDrop={handleInpaintDrop}
                role="button"
                tabIndex={0}
                onKeyDown={(e) => { if (e.key === "Enter" || e.key === " ") inpaintFileInputRef.current?.click(); }}
              >
                <div className="studio-canvas-ghost__icon">
                  <FileImageOutlined />
                </div>
                <div className="studio-canvas-ghost__title">点击或拖拽上传图片</div>
                <div className="studio-canvas-ghost__hint">支持 PNG / JPG / WebP，上传后使用画笔标注需要重绘的区域</div>
              </div>
            )}
          </section>

        </main>
      ) : activeTool === "camera" ? (
        <main className="image-workbench-layout image-workbench-layout--camera">
          <aside className="image-workbench-panel image-workbench-panel--left">
            <section className="image-workbench-control-card">
              <div className="image-workbench-section-title">
                <h3>素材</h3>
                <span>{cameraImage ? "已导入" : "待上传"}</span>
              </div>
              <input
                ref={cameraFileInputRef}
                type="file"
                accept="image/png,image/jpeg,image/webp"
                onChange={handleCameraFileChange}
              />
              <div
                className={`image-workbench-upload-shell${isCameraDragging ? " is-dragging" : ""}`}
                onDragOver={handleCameraDragOver}
                onDragLeave={handleCameraDragLeave}
                onDrop={handleCameraDrop}
              >
                {isCameraDragging && <div className="image-workbench-upload-overlay">释放文件以上传</div>}
                <button type="button" className="image-workbench-upload" onClick={() => cameraFileInputRef.current?.click()}>
                  {cameraImage ? <img src={cameraImage} alt="" /> : <FileImageOutlined />}
                  <strong>{cameraImage ? "更换参考图" : "导入参考图"}</strong>
                  <span>PNG / JPG / WebP</span>
                </button>
                {cameraImage ? (
                  <button
                    type="button"
                    className="image-workbench-upload-remove"
                    aria-label="删除镜头参考图"
                    onClick={handleRemoveCameraImage}
                  >
                    ×
                  </button>
                ) : null}
              </div>
              <div className="image-workbench-url-row">
                <label>
                  <LinkOutlined />
                  <input
                    value={cameraUrlInput}
                    placeholder="粘贴图片 URL"
                    onChange={(event) => setCameraUrlInput(event.target.value)}
                  />
                </label>
                <button type="button" onClick={handleAddCameraUrl}>导入</button>
              </div>
            </section>

            <section className="image-workbench-control-card image-workbench-camera-presets">
              <h3>预设</h3>
              <div className="image-workbench-chip-grid">
                {cameraPresets.map((preset) => (
                  <button
                    key={preset.name}
                    type="button"
                    className={cameraPreset === preset.name ? "is-active" : ""}
                    onClick={() => {
                      setCameraPreset(preset.name);
                      if (preset.name !== "自定义") {
                        setCameraVertical(preset.rotationX);
                        setCameraHorizontal(preset.rotationY);
                        setCameraRoll(preset.rotationZ);
                        setCameraZoom(shotScaleToZoom(preset.shotScale));
                      }
                    }}
                  >
                    {preset.name}
                  </button>
                ))}
              </div>
            </section>

            <section className="image-workbench-control-card image-workbench-camera-direction">
              <h3>方向</h3>
              <div className="image-workbench-direction-pad">
                {cameraDirections.map((direction) => (
                  <button
                    key={direction.key}
                    type="button"
                    className={cameraDirection === direction.key ? "is-active" : ""}
                    onClick={() => {
                      setCameraDirection(direction.key);
                      setCameraPreset("自定义");
                      const step = 15;
                      if (direction.key === "up") setCameraVertical((v) => Math.min(45, v + step));
                      else if (direction.key === "down") setCameraVertical((v) => Math.max(-45, v - step));
                      else if (direction.key === "left") setCameraHorizontal((v) => Math.min(180, v + step));
                      else if (direction.key === "right") setCameraHorizontal((v) => Math.max(-180, v - step));
                      else { setCameraVertical(0); setCameraHorizontal(0); setCameraRoll(0); setCameraZoom(40); }
                    }}
                  >
                    {direction.label}
                  </button>
                ))}
              </div>
            </section>

            <section className="image-workbench-control-card image-workbench-camera-fine">
              <h3>微调</h3>
              <label className="image-workbench-range">
                <span>水平环绕</span>
                <input
                  type="range"
                  min="-180"
                  max="180"
                  value={cameraHorizontal}
                  onChange={(event) => { setCameraHorizontal(Number(event.target.value)); setCameraPreset("自定义"); }}
                />
                <em>{cameraHorizontal}°</em>
              </label>
              <label className="image-workbench-range">
                <span>垂直俯仰</span>
                <input
                  type="range"
                  min="-85"
                  max="65"
                  value={cameraVertical}
                  onChange={(event) => { setCameraVertical(Number(event.target.value)); setCameraPreset("自定义"); }}
                />
                <em>{cameraVertical}°</em>
              </label>
              <label className="image-workbench-range">
                <span>画面倾斜</span>
                <input
                  type="range"
                  min="-30"
                  max="30"
                  value={cameraRoll}
                  onChange={(event) => { setCameraRoll(Number(event.target.value)); setCameraPreset("自定义"); }}
                />
                <em>{cameraRoll}°</em>
              </label>
              <label className="image-workbench-range">
                <span>景别缩放</span>
                <input
                  type="range"
                  min="24"
                  max="100"
                  value={cameraZoom}
                  onChange={(event) => { setCameraZoom(Number(event.target.value)); setCameraPreset("自定义"); }}
                />
                <em>{cameraZoom < 40 ? "广角" : cameraZoom > 70 ? "长焦" : "中景"}</em>
              </label>
            </section>

            <section className="image-workbench-control-card image-workbench-camera-effects">
              <div className="image-workbench-section-title">
                <h3>视觉效果</h3>
                <span style={{ fontSize: 11, color: "var(--fg-muted, #888)" }}>可多选</span>
              </div>
              <div style={{ display: "flex", flexWrap: "wrap", gap: 4 }}>
                {CAMERA_EFFECT_PRESETS.map((effect) => {
                  const isActive = cameraEffects.has(effect.key);
                  return (
                    <button
                      key={effect.key}
                      type="button"
                      className={`image-workbench-chip${isActive ? " is-active" : ""}`}
                      style={{
                        padding: "3px 8px",
                        borderRadius: 999,
                        fontSize: 11,
                        border: `1px solid ${isActive ? "var(--accent, #2dd4bf)" : "var(--border-subtle, #333)"}`,
                        background: isActive ? "rgba(45, 212, 191, 0.12)" : "transparent",
                        color: isActive ? "var(--accent, #2dd4bf)" : "var(--fg-body, #eee)",
                        cursor: "pointer",
                        transition: "all 0.15s",
                      }}
                      onClick={() => {
                        setCameraEffects((prev) => {
                          const next = new Set(prev);
                          if (next.has(effect.key)) next.delete(effect.key);
                          else next.add(effect.key);
                          return next;
                        });
                        setCameraPreset("自定义");
                      }}
                    >
                      {effect.label}
                    </button>
                  );
                })}
              </div>
            </section>

            <section className="image-workbench-control-card image-workbench-camera-prompt">
              <div className="image-workbench-section-title">
                <h3>提示词</h3>
                <button
                  type="button"
                  className={`image-workbench-toggle${cameraPromptEnabled ? " is-active" : ""}`}
                  aria-label="启用提示词"
                  onClick={() => setCameraPromptEnabled((current) => !current)}
                />
              </div>
              <textarea
                value={cameraPrompt}
                disabled={!cameraPromptEnabled}
                placeholder="可选：补充额外的镜头要求，如光线、氛围、运动感等"
                onChange={(event) => setCameraPrompt(event.target.value)}
              />
            </section>

            <div className="image-workbench-actions">
              <button type="button" className="image-workbench-primary" onClick={handleStartCamera} disabled={generating}>
                {generating && activeTool === "camera" ? <LoadingOutlined /> : <CameraOutlined />}
                {generating && activeTool === "camera" ? "生成中..." : "生成"}
              </button>
            </div>
          </aside>

          <section className="image-workbench-canvas image-workbench-canvas--camera" aria-label="镜头实验室画布">
            {generating && activeTool === "camera" ? (
              <div className="image-workbench-generating">
                <LoadingOutlined style={{ fontSize: 32 }} />
                <strong>镜头生成中...</strong>
                <div className="image-workbench-progress-bar">
                  <div className="image-workbench-progress-fill" style={{ width: `${generationProgress}%` }} />
                </div>
                <span>{generationProgress}%</span>
                <button type="button" className="image-workbench-cancel" onClick={handleCancel}>取消</button>
              </div>
            ) : cameraResultImages.length && activeTool === "camera" ? (
              <div className="image-workbench-camera-stage">
                <img src={cameraResultImages[0]} alt="镜头结果" />
                <span>{cameraPreset} · {cameraZoom}mm</span>
                {renderResultActions(cameraResultImages[0], 0)}
              </div>
            ) : (
              <CameraViewport3D
                horizontal={cameraHorizontal}
                vertical={cameraVertical}
                roll={cameraRoll}
                zoom={cameraZoom}
                onOrbit={(h, v) => { setCameraHorizontal(h); setCameraVertical(v); setCameraPreset("自定义"); }}
                onZoom={(z) => { setCameraZoom(z); setCameraPreset("自定义"); }}
                onReset={() => { setCameraHorizontal(0); setCameraVertical(0); setCameraRoll(0); setCameraZoom(40); setCameraPreset("正面平视"); }}
                referenceImage={cameraImage}
              />
            )}
          </section>
        </main>
      ) : (
      <main className="image-workbench-layout">
        <aside className="image-workbench-panel image-workbench-panel--left">
          <section className="image-workbench-control-card image-workbench-mode-card">
            <h3>模式</h3>
            <div className="image-workbench-segmented">
              <button type="button" className={mode === "single" ? "is-active" : ""} onClick={() => setMode("single")}>
                <PictureOutlined />
                单图
              </button>
              <button type="button" className={mode === "blend" ? "is-active" : ""} onClick={() => setMode("blend")}>
                <TableOutlined />
                融合
              </button>
            </div>
          </section>

          <section className="image-workbench-control-card">
            <div className="image-workbench-section-title">
              <h3>参考图</h3>
              <span>{mode === "blend" ? `${referenceImages.length || 0} 张` : referenceImage ? "已导入" : "需1张"}</span>
            </div>
            <input
              ref={fileInputRef}
              type="file"
              accept="image/png,image/jpeg,image/webp"
              multiple={mode === "blend"}
              onChange={handleFileChange}
            />
            {mode === "blend" ? (
              <div className="image-workbench-reference-grid">
                {referenceImages.map((image, index) => (
                  <div className="image-workbench-reference-thumb" key={`${image}-${index}`}>
                    <img src={image} alt={`参考图 ${index + 1}`} />
                    <button
                      type="button"
                      className="image-workbench-upload-remove"
                      aria-label={`删除参考图 ${index + 1}`}
                      onClick={() => handleRemoveReferenceImage(index)}
                    >
                      ×
                    </button>
                  </div>
                ))}
                <button
                  type="button"
                  className="image-workbench-upload image-workbench-upload--tile"
                  onClick={() => fileInputRef.current?.click()}
                >
                  <FileImageOutlined />
                  <strong>{referenceImages.length ? "继续上传" : "导入参考图"}</strong>
                  <span>PNG / JPG / WebP</span>
                </button>
              </div>
            ) : (
              <div
                className={`image-workbench-upload-shell${isDragging ? " is-dragging" : ""}`}
                onDragOver={handleDragOver}
                onDragLeave={handleDragLeave}
                onDrop={handleDrop}
              >
                {isDragging && <div className="image-workbench-upload-overlay">释放文件以上传</div>}
                <button type="button" className="image-workbench-upload" onClick={() => fileInputRef.current?.click()}>
                  {referenceImage ? <img src={referenceImage} alt="" /> : <FileImageOutlined />}
                  <strong>{referenceImage ? "更换参考图" : "导入参考图"}</strong>
                  <span>PNG / JPG / WebP</span>
                </button>
                {referenceImage ? (
                  <button
                    type="button"
                    className="image-workbench-upload-remove"
                    aria-label="删除参考图"
                    onClick={() => handleRemoveReferenceImage(0)}
                  >
                    ×
                  </button>
                ) : null}
              </div>
            )}
            <div className="image-workbench-url-row">
              <label>
                <LinkOutlined />
                <input
                  value={imageUrlInput}
                  placeholder="粘贴图片 URL"
                  onChange={(event) => setImageUrlInput(event.target.value)}
                />
              </label>
              <button type="button" onClick={handleAddUrl}>添加</button>
            </div>
          </section>

          <section className="image-workbench-control-card">
            <h3>输出</h3>
            <span className="image-workbench-field-label">尺寸</span>
            <div className="image-workbench-segmented">
              {(["9:16", "16:9", "4:3", "3:4", "1:1"] as OutputSize[]).map((s) => (
                <button key={s} type="button" className={outputSize === s ? "is-active" : ""} onClick={() => setOutputSize(s)}>
                  {s}
                </button>
              ))}
            </div>
            <div className="image-workbench-count">
              <span>数量</span>
              <div>
                {([1, 2, 3, 4] as OutputCount[]).map((count) => (
                  <button
                    key={count}
                    type="button"
                    className={outputCount === count ? "is-active" : ""}
                    onClick={() => setOutputCount(count)}
                  >
                    {count} 张
                  </button>
                ))}
              </div>
            </div>
          </section>

          <section className="image-workbench-control-card image-workbench-prompt">
            <h3>提示词</h3>
            <textarea
              value={prompt}
              placeholder="例如：改成米白色大衣，保留构图与人物特征。"
              onChange={(event) => setPrompt(event.target.value)}
            />
          </section>

          <div className="image-workbench-actions">
            <button type="button" className="image-workbench-primary" onClick={handleGenerate} disabled={generating}>
              {generating ? <LoadingOutlined /> : <ScissorOutlined />}
              {generating ? "生成中..." : "开始生成"}
            </button>
            <button type="button" onClick={handleClear}>
              <ClearOutlined />
              清空工作区
            </button>
          </div>
        </aside>

        <section className="image-workbench-canvas" aria-label="图片预览区">
          {generating ? (
            <div className="image-workbench-generating">
              <LoadingOutlined style={{ fontSize: 32 }} />
              <strong>生成中...</strong>
              <div className="image-workbench-progress-bar">
                <div className="image-workbench-progress-fill" style={{ width: `${generationProgress}%` }} />
              </div>
              <span>{generationProgress}%</span>
              <button type="button" className="image-workbench-cancel" onClick={handleCancel}>
                取消
              </button>
            </div>
          ) : resultImages.length ? (
            <div className="image-workbench-result-grid">
              {resultImages.map((url, i) => (
                <div key={url} className="image-workbench-result-card">
                  <a href={url} target="_blank" rel="noopener noreferrer" className="image-workbench-result-item">
                    <img src={url} alt={`生成结果 ${i + 1}`} />
                  </a>
                  {renderResultActions(url, i)}
                </div>
              ))}
            </div>
          ) : generationError ? (
            <div className="image-workbench-empty image-workbench-empty--error">
              <PictureOutlined />
              <strong>生成失败</strong>
              <span>{generationError}</span>
            </div>
          ) : mode === "blend" && referenceImages.length ? (
            <div className="image-workbench-canvas-grid">
              {referenceImages.map((image, index) => (
                <img src={image} alt={`参考图预览 ${index + 1}`} key={`${image}-preview-${index}`} />
              ))}
            </div>
          ) : referenceImage ? (
            <div className="studio-canvas-image">
              <img src={referenceImage} alt="参考图预览" />
            </div>
          ) : (
            <div
              className={`studio-canvas-ghost${isDragging ? " is-dragging" : ""}`}
              onClick={() => fileInputRef.current?.click()}
              onDragOver={handleDragOver}
              onDragLeave={handleDragLeave}
              onDrop={handleDrop}
              role="button"
              tabIndex={0}
              onKeyDown={(e) => { if (e.key === "Enter" || e.key === " ") fileInputRef.current?.click(); }}
            >
              <div className="studio-canvas-ghost__icon">
                <PictureOutlined />
              </div>
              <div className="studio-canvas-ghost__title">上传参考图后在此预览</div>
              <div className="studio-canvas-ghost__hint">点击或拖拽上传 (PNG / JPG / WebP)，生成结果也会显示在这里</div>
            </div>
          )}
        </section>

      </main>
      )}

      <footer className="image-workbench-status">
        <span>就绪</span>
        <p>{status}</p>
        <em>
          <ColumnWidthOutlined />
          {activeTool === "inpaint"
            ? "局部重绘"
            : activeTool === "camera"
              ? `AZ ${cameraHorizontal} PT ${cameraVertical} ${cameraZoom}mm${cameraEffects.size ? ` + ${cameraEffects.size} 效果` : ""}`
              : `${mode === "single" ? "单图" : "融合"} · ${outputSize}`}
        </em>
      </footer>
    </section>
  );
}

export default ImageWorkbenchPage;
