const { useEffect, useRef, useState } = React;

type ToolMode = "pick" | "erase" | "restore";
type StatusTone = "idle" | "busy" | "success" | "error";

interface StatusState {
  tone: StatusTone;
  title: string;
  detail: string;
}

interface UploadMeta {
  name: string;
  type: string;
  size: number;
}

interface BackgroundRemovePayload {
  image_url: string;
  filename: string;
  width: number;
  height: number;
  engine: string;
  source_width: number;
  source_height: number;
  has_transparent_background: boolean;
}

interface RgbaColor {
  r: number;
  g: number;
  b: number;
  a: number;
}

const initialStatus: StatusState = {
  tone: "idle",
  title: "等待上传图片",
  detail: "上传 JPG、PNG 或 WebP 后，系统会自动识别主体并输出透明 PNG。",
};

function clamp(value: number, min: number, max: number): number {
  return Math.min(Math.max(value, min), max);
}

function formatBytes(size: number): string {
  if (!size) {
    return "0 KB";
  }

  if (size < 1024 * 1024) {
    return `${(size / 1024).toFixed(size < 1024 * 10 ? 1 : 0)} KB`;
  }

  return `${(size / (1024 * 1024)).toFixed(2)} MB`;
}

function cloneImageData(imageData: ImageData): ImageData {
  return new ImageData(new Uint8ClampedArray(imageData.data), imageData.width, imageData.height);
}

function createWorkingContext(width: number, height: number): CanvasRenderingContext2D {
  const canvas = document.createElement("canvas");
  canvas.width = width;
  canvas.height = height;
  const context = canvas.getContext("2d", { willReadFrequently: true });
  if (!context) {
    throw new Error("浏览器暂时不支持 2D 画布。");
  }
  return context;
}

function imageDataFromImageSource(source: string): Promise<ImageData> {
  return new Promise((resolve, reject) => {
    const image = new Image();
    image.onload = () => {
      const context = createWorkingContext(image.naturalWidth || image.width, image.naturalHeight || image.height);
      context.drawImage(image, 0, 0);
      resolve(context.getImageData(0, 0, context.canvas.width, context.canvas.height));
    };
    image.onerror = () => {
      reject(new Error("图片载入失败。"));
    };
    image.src = source;
  });
}

function drawImageData(canvas: HTMLCanvasElement | null, imageData: ImageData | null): void {
  if (!canvas) {
    return;
  }

  if (!imageData) {
    const context = canvas.getContext("2d");
    if (context) {
      context.clearRect(0, 0, canvas.width, canvas.height);
    }
    canvas.width = 0;
    canvas.height = 0;
    return;
  }

  canvas.width = imageData.width;
  canvas.height = imageData.height;
  const context = canvas.getContext("2d");
  if (!context) {
    return;
  }

  context.clearRect(0, 0, canvas.width, canvas.height);
  context.putImageData(imageData, 0, 0);
}

function getCanvasPoint(
  canvas: HTMLCanvasElement,
  event: PointerEvent | React.PointerEvent<HTMLCanvasElement>,
  width: number,
  height: number,
): { x: number; y: number } {
  const rect = canvas.getBoundingClientRect();
  const x = clamp(Math.floor(((event.clientX - rect.left) / rect.width) * width), 0, Math.max(width - 1, 0));
  const y = clamp(Math.floor(((event.clientY - rect.top) / rect.height) * height), 0, Math.max(height - 1, 0));
  return { x, y };
}

function sampleColor(imageData: ImageData, x: number, y: number): RgbaColor {
  const index = (y * imageData.width + x) * 4;
  const pixels = imageData.data;
  return {
    r: pixels[index],
    g: pixels[index + 1],
    b: pixels[index + 2],
    a: pixels[index + 3],
  };
}

function applyColorTransparency(imageData: ImageData, selectedColor: RgbaColor, tolerance: number): ImageData {
  const next = cloneImageData(imageData);
  const pixels = next.data;
  const safeTolerance = Math.max(1, tolerance);

  for (let index = 0; index < pixels.length; index += 4) {
    const alpha = pixels[index + 3];
    if (alpha === 0) {
      continue;
    }

    const diff = Math.max(
      Math.abs(pixels[index] - selectedColor.r),
      Math.abs(pixels[index + 1] - selectedColor.g),
      Math.abs(pixels[index + 2] - selectedColor.b),
    );

    if (diff > safeTolerance) {
      continue;
    }

    const ratio = diff / safeTolerance;
    pixels[index + 3] = Math.round(alpha * ratio);
  }

  return next;
}

function defringeImage(imageData: ImageData, mode: "white" | "black"): ImageData {
  const next = cloneImageData(imageData);
  const pixels = next.data;

  for (let index = 0; index < pixels.length; index += 4) {
    const alpha = pixels[index + 3];
    if (alpha <= 0 || alpha >= 255) {
      continue;
    }

    const coverage = alpha / 255;
    const invCoverage = 1 - coverage;

    if (mode === "white") {
      pixels[index] = clamp(Math.round((pixels[index] - 255 * invCoverage) / coverage), 0, 255);
      pixels[index + 1] = clamp(Math.round((pixels[index + 1] - 255 * invCoverage) / coverage), 0, 255);
      pixels[index + 2] = clamp(Math.round((pixels[index + 2] - 255 * invCoverage) / coverage), 0, 255);
    } else {
      pixels[index] = clamp(Math.round(pixels[index] / coverage), 0, 255);
      pixels[index + 1] = clamp(Math.round(pixels[index + 1] / coverage), 0, 255);
      pixels[index + 2] = clamp(Math.round(pixels[index + 2] / coverage), 0, 255);
    }
  }

  return next;
}

function featherImage(imageData: ImageData, radius: number): ImageData {
  if (radius <= 0) {
    return cloneImageData(imageData);
  }

  const width = imageData.width;
  const height = imageData.height;
  const maskContext = createWorkingContext(width, height);
  const blurredContext = createWorkingContext(width, height);
  const mask = maskContext.createImageData(width, height);

  for (let index = 0; index < imageData.data.length; index += 4) {
    const alpha = imageData.data[index + 3];
    mask.data[index] = alpha;
    mask.data[index + 1] = alpha;
    mask.data[index + 2] = alpha;
    mask.data[index + 3] = 255;
  }

  maskContext.putImageData(mask, 0, 0);
  blurredContext.filter = `blur(${radius}px)`;
  blurredContext.drawImage(maskContext.canvas, 0, 0);
  const blurred = blurredContext.getImageData(0, 0, width, height);
  const next = cloneImageData(imageData);

  for (let index = 0; index < next.data.length; index += 4) {
    next.data[index + 3] = Math.min(next.data[index + 3], blurred.data[index]);
  }

  return next;
}

function applyBrush(imageData: ImageData, baseImageData: ImageData | null, x: number, y: number, size: number, toolMode: ToolMode): void {
  const radius = Math.max(2, Math.floor(size / 2));
  const minX = Math.max(0, x - radius);
  const maxX = Math.min(imageData.width - 1, x + radius);
  const minY = Math.max(0, y - radius);
  const maxY = Math.min(imageData.height - 1, y + radius);

  for (let py = minY; py <= maxY; py += 1) {
    for (let px = minX; px <= maxX; px += 1) {
      const dx = px - x;
      const dy = py - y;
      if (dx * dx + dy * dy > radius * radius) {
        continue;
      }

      const index = (py * imageData.width + px) * 4;
      if (toolMode === "erase") {
        imageData.data[index + 3] = 0;
        continue;
      }

      if (toolMode === "restore" && baseImageData) {
        imageData.data[index] = baseImageData.data[index];
        imageData.data[index + 1] = baseImageData.data[index + 1];
        imageData.data[index + 2] = baseImageData.data[index + 2];
        imageData.data[index + 3] = baseImageData.data[index + 3];
      }
    }
  }
}

async function imageDataToBlob(imageData: ImageData): Promise<Blob> {
  const context = createWorkingContext(imageData.width, imageData.height);
  context.putImageData(imageData, 0, 0);
  return new Promise((resolve, reject) => {
    context.canvas.toBlob((blob) => {
      if (!blob) {
        reject(new Error("PNG 导出失败。"));
        return;
      }
      resolve(blob);
    }, "image/png");
  });
}

function TransparentBackgroundStudio(): JSX.Element {
  const fileInputRef = useRef<HTMLInputElement | null>(null);
  const sourceCanvasRef = useRef<HTMLCanvasElement | null>(null);
  const resultCanvasRef = useRef<HTMLCanvasElement | null>(null);
  const sourceObjectUrlRef = useRef<string>("");
  const sourceImageRef = useRef<ImageData | null>(null);
  const baseImageRef = useRef<ImageData | null>(null);
  const workingImageRef = useRef<ImageData | null>(null);
  const strokeImageRef = useRef<ImageData | null>(null);
  const isPaintingRef = useRef<boolean>(false);

  const [sourceVersion, setSourceVersion] = useState(0);
  const [workingVersion, setWorkingVersion] = useState(0);
  const [toolMode, setToolMode] = useState<ToolMode>("pick");
  const [brushSize, setBrushSize] = useState(28);
  const [tolerance, setTolerance] = useState(28);
  const [featherRadius, setFeatherRadius] = useState(2);
  const [status, setStatus] = useState<StatusState>(initialStatus);
  const [uploadMeta, setUploadMeta] = useState<UploadMeta | null>(null);
  const [resultMeta, setResultMeta] = useState<BackgroundRemovePayload | null>(null);
  const [selectedColor, setSelectedColor] = useState<RgbaColor | null>(null);
  const [dragActive, setDragActive] = useState(false);
  const [busy, setBusy] = useState(false);

  const hasSourceImage = sourceImageRef.current !== null;
  const hasWorkingImage = workingImageRef.current !== null;
  const resultFilename = resultMeta?.filename || "transparent-output.png";

  useEffect(() => {
    drawImageData(sourceCanvasRef.current, sourceImageRef.current);
  }, [sourceVersion]);

  useEffect(() => {
    drawImageData(resultCanvasRef.current, workingImageRef.current);
  }, [workingVersion]);

  useEffect(() => {
    const handlePointerUp = () => {
      if (!isPaintingRef.current) {
        return;
      }

      isPaintingRef.current = false;
      if (!strokeImageRef.current) {
        return;
      }

      workingImageRef.current = strokeImageRef.current;
      strokeImageRef.current = null;
      setWorkingVersion((value) => value + 1);
      setStatus({
        tone: "success",
        title: toolMode === "erase" ? "擦除已应用" : "恢复已应用",
        detail: toolMode === "erase" ? "当前画笔把该区域处理为透明。" : "当前画笔把该区域恢复到自动去背景结果。",
      });
    };

    window.addEventListener("pointerup", handlePointerUp);
    window.addEventListener("pointercancel", handlePointerUp);

    return () => {
      window.removeEventListener("pointerup", handlePointerUp);
      window.removeEventListener("pointercancel", handlePointerUp);
    };
  }, [toolMode]);

  useEffect(() => {
    return () => {
      if (sourceObjectUrlRef.current) {
        URL.revokeObjectURL(sourceObjectUrlRef.current);
      }
    };
  }, []);

  async function uploadAndRemoveBackground(file: File): Promise<BackgroundRemovePayload> {
    const formData = new FormData();
    formData.append("image", file);

    const response = await fetch("/api/background/remove", {
      method: "POST",
      body: formData,
    });

    const payload = await response.json().catch(() => ({}));
    if (!response.ok) {
      throw new Error(payload.error || "自动去背景失败，请稍后重试。");
    }

    return payload as BackgroundRemovePayload;
  }

  function commitSourceImage(imageData: ImageData): void {
    sourceImageRef.current = imageData;
    setSourceVersion((value) => value + 1);
  }

  function commitWorkingImage(imageData: ImageData): void {
    workingImageRef.current = imageData;
    setWorkingVersion((value) => value + 1);
  }

  async function handleFile(file: File | null): Promise<void> {
    if (!file) {
      return;
    }

    const allowed = /image\/(png|jpeg|webp)/i.test(file.type) || /\.(png|jpe?g|webp)$/i.test(file.name);
    if (!allowed) {
      setStatus({
        tone: "error",
        title: "文件类型不支持",
        detail: "请上传 JPG、PNG 或 WebP 图片。",
      });
      return;
    }

    if (sourceObjectUrlRef.current) {
      URL.revokeObjectURL(sourceObjectUrlRef.current);
      sourceObjectUrlRef.current = "";
    }

    const objectUrl = URL.createObjectURL(file);
    sourceObjectUrlRef.current = objectUrl;
    setUploadMeta({
      name: file.name,
      type: file.type || "image/*",
      size: file.size,
    });
    setSelectedColor(null);
    setResultMeta(null);
    sourceImageRef.current = null;
    setSourceVersion((value) => value + 1);
    baseImageRef.current = null;
    workingImageRef.current = null;
    setWorkingVersion((value) => value + 1);
    setBusy(true);
    setStatus({
      tone: "busy",
      title: "正在自动去背景",
      detail: "图片已上传，后端正在使用 rembg 识别主体并输出透明 PNG。第一次运行可能会稍慢一点。",
    });

    try {
      const sourceImageData = await imageDataFromImageSource(objectUrl);
      commitSourceImage(sourceImageData);
      const payload = await uploadAndRemoveBackground(file);
      const removedImageData = await imageDataFromImageSource(payload.image_url);
      baseImageRef.current = cloneImageData(removedImageData);
      commitWorkingImage(cloneImageData(removedImageData));
      setResultMeta(payload);
      setToolMode("pick");

      const detail =
        payload.engine === "source-alpha"
          ? "原图本身已经带透明背景，页面已直接载入原始透明 PNG，可继续做颜色透明化与笔刷微调。"
          : "主体已经自动抠出，现在可以继续按背景颜色透明化、去边和用笔刷做最后微调。";

      setStatus({
        tone: "success",
        title: "透明 PNG 已生成",
        detail,
      });
    } catch (error) {
      setStatus({
        tone: "error",
        title: "自动去背景失败",
        detail: error instanceof Error ? error.message : "自动去背景失败，请换一张图或稍后重试。",
      });
    } finally {
      setBusy(false);
    }
  }

  function handleFileInputChange(event: React.ChangeEvent<HTMLInputElement>): void {
    const file = event.target.files?.[0] || null;
    event.target.value = "";
    void handleFile(file);
  }

  function handleDrop(event: React.DragEvent<HTMLLabelElement>): void {
    event.preventDefault();
    setDragActive(false);
    const file = event.dataTransfer.files?.[0] || null;
    void handleFile(file);
  }

  function pickColorFromImage(
    canvas: HTMLCanvasElement | null,
    imageData: ImageData | null,
    event: React.PointerEvent<HTMLCanvasElement>,
  ): void {
    if (!canvas || !imageData) {
      return;
    }

    const { x, y } = getCanvasPoint(canvas, event, imageData.width, imageData.height);
    const color = sampleColor(imageData, x, y);
    setSelectedColor(color);
    setStatus({
      tone: "success",
      title: "背景色已取样",
      detail: `已取到 RGB(${color.r}, ${color.g}, ${color.b})，现在可以配合容差执行背景色透明化。`,
    });
  }

  function handleSourceCanvasPointerDown(event: React.PointerEvent<HTMLCanvasElement>): void {
    if (toolMode !== "pick") {
      return;
    }

    pickColorFromImage(sourceCanvasRef.current, sourceImageRef.current, event);
  }

  function handleResultCanvasPointerDown(event: React.PointerEvent<HTMLCanvasElement>): void {
    if (!workingImageRef.current || !resultCanvasRef.current) {
      return;
    }

    if (toolMode === "pick") {
      pickColorFromImage(resultCanvasRef.current, workingImageRef.current, event);
      return;
    }

    event.preventDefault();
    const next = cloneImageData(workingImageRef.current);
    const { x, y } = getCanvasPoint(resultCanvasRef.current, event, next.width, next.height);
    applyBrush(next, baseImageRef.current, x, y, brushSize, toolMode);
    strokeImageRef.current = next;
    workingImageRef.current = next;
    drawImageData(resultCanvasRef.current, next);
    isPaintingRef.current = true;
  }

  function handleResultCanvasPointerMove(event: React.PointerEvent<HTMLCanvasElement>): void {
    if (!isPaintingRef.current || !strokeImageRef.current || !resultCanvasRef.current) {
      return;
    }

    const { x, y } = getCanvasPoint(
      resultCanvasRef.current,
      event,
      strokeImageRef.current.width,
      strokeImageRef.current.height,
    );
    applyBrush(strokeImageRef.current, baseImageRef.current, x, y, brushSize, toolMode);
    workingImageRef.current = strokeImageRef.current;
    drawImageData(resultCanvasRef.current, strokeImageRef.current);
  }

  function runImageTransform(
    transform: (imageData: ImageData) => ImageData,
    statusTitle: string,
    statusDetail: string,
  ): void {
    if (!workingImageRef.current) {
      return;
    }

    const next = transform(workingImageRef.current);
    commitWorkingImage(next);
    setStatus({
      tone: "success",
      title: statusTitle,
      detail: statusDetail,
    });
  }

  function handleApplyColorTransparency(): void {
    if (!workingImageRef.current || !selectedColor) {
      setStatus({
        tone: "error",
        title: "还没有背景色",
        detail: "先切到取色工具，再点击原图或结果图选择一个背景颜色。",
      });
      return;
    }

    runImageTransform(
      (imageData) => applyColorTransparency(imageData, selectedColor, tolerance),
      "背景色透明化已应用",
      `当前使用 RGB(${selectedColor.r}, ${selectedColor.g}, ${selectedColor.b})，容差为 ${tolerance}。`,
    );
  }

  function handleFeather(): void {
    if (featherRadius <= 0) {
      setStatus({
        tone: "idle",
        title: "羽化半径为 0",
        detail: "把羽化边缘滑杆调高一点，再点一次应用羽化。",
      });
      return;
    }

    runImageTransform(
      (imageData) => featherImage(imageData, featherRadius),
      "羽化已应用",
      `已按 ${featherRadius}px 的半径柔化边缘透明过渡。`,
    );
  }

  function handleReset(): void {
    if (!baseImageRef.current) {
      return;
    }

    commitWorkingImage(cloneImageData(baseImageRef.current));
    setStatus({
      tone: "success",
      title: "已重置到自动去背景结果",
      detail: "所有颜色透明化和笔刷微调都已清空，当前结果回到上传后的初始透明 PNG。",
    });
  }

  async function handleDownload(): Promise<void> {
    if (!workingImageRef.current) {
      return;
    }

    try {
      const blob = await imageDataToBlob(workingImageRef.current);
      const downloadUrl = URL.createObjectURL(blob);
      const link = document.createElement("a");
      link.href = downloadUrl;
      link.download = resultFilename;
      link.click();
      URL.revokeObjectURL(downloadUrl);
      setStatus({
        tone: "success",
        title: "PNG 已开始下载",
        detail: "当前透明背景结果会以 PNG 格式保存到本地。",
      });
    } catch (error) {
      setStatus({
        tone: "error",
        title: "下载失败",
        detail: error instanceof Error ? error.message : "PNG 导出失败。",
      });
    }
  }

  const statusClass = `status-pill is-${status.tone}`;
  const selectedColorStyle = selectedColor
    ? { background: `rgba(${selectedColor.r}, ${selectedColor.g}, ${selectedColor.b}, 1)` }
    : { background: "linear-gradient(135deg, #f4efe6, #d9d5ce)" };

  return (
    <div className="studio-page">
      <div className="studio-ambient studio-ambient-a" aria-hidden="true"></div>
      <div className="studio-ambient studio-ambient-b" aria-hidden="true"></div>

      <div className="studio-shell">
        <header className="studio-hero">
          <div>
            <p className="hero-kicker">Transparent Background Studio</p>
            <h1>上传后自动去背景，并继续做透明微调</h1>
            <p>
              前端使用 React + TypeScript，后端使用开源 <code>rembg</code> 自动识别主体。
              上传图片后会直接输出透明 PNG，再配合取色透明化、羽化、去边和画笔做最后修边。
            </p>
          </div>

          <div className="hero-links">
            <a className="ghost-button" href="/">返回像素工作台</a>
            <button className="primary-button" type="button" onClick={() => fileInputRef.current?.click()}>
              选择图片开始
            </button>
          </div>
        </header>

        <main className="workspace-grid">
          <aside className="sidebar-card glass-card">
            <div className="section-stack">
              <section className="section-card">
                <div className="section-head">
                  <div>
                    <h2>上传并自动去背景</h2>
                    <p>支持 JPG、PNG、WebP。上传后立即进入自动抠图流程。</p>
                  </div>
                  <span className="meta-badge">自动执行</span>
                </div>

                <label
                  className={`dropzone${dragActive ? " is-active" : ""}`}
                  onDragOver={(event) => {
                    event.preventDefault();
                    setDragActive(true);
                  }}
                  onDragLeave={() => setDragActive(false)}
                  onDrop={handleDrop}
                >
                  <input
                    ref={fileInputRef}
                    type="file"
                    accept=".png,.jpg,.jpeg,.webp,image/png,image/jpeg,image/webp"
                    onChange={handleFileInputChange}
                  />
                  <span className="dropzone-kicker">Auto Remove</span>
                  <p className="dropzone-title">点击选择图片，或直接拖拽到这里</p>
                  <p className="dropzone-copy">
                    如果原图本身已经是透明背景，页面会直接保留透明 Alpha，不会再额外加底色。
                  </p>

                  <div className="file-chip-row">
                    <span className="file-chip">{uploadMeta ? uploadMeta.name : "还没有选择图片"}</span>
                    <span className="file-chip">{uploadMeta ? formatBytes(uploadMeta.size) : "支持 32MB 以内图片"}</span>
                  </div>
                </label>
              </section>

              <section className="section-card status-card">
                <span className={statusClass}>{status.title}</span>
                <p className="status-detail">{status.detail}</p>
              </section>

              <section className="section-card">
                <div className="section-head">
                  <div>
                    <h3>按背景颜色透明化</h3>
                    <p>先切到取色工具，再点击左侧原图或右侧结果图取样背景颜色。</p>
                  </div>
                </div>

                <div className="toolbar-grid">
                  <div className="swatch-row">
                    <div className="color-swatch" style={selectedColorStyle}></div>
                    <div>
                      <p className="mini-note">
                        {selectedColor
                          ? `当前颜色：RGB(${selectedColor.r}, ${selectedColor.g}, ${selectedColor.b})`
                          : "当前还没有选中背景色"}
                      </p>
                      <p className="mini-note">建议先取样背景，再根据容差一点点扩大透明范围。</p>
                    </div>
                  </div>

                  <div className="tool-row">
                    <div className="tool-label">
                      <span>容差</span>
                      <span className="tool-value">{tolerance}</span>
                    </div>
                    <input
                      className="range-control"
                      type="range"
                      min="0"
                      max="120"
                      value={tolerance}
                      onChange={(event) => setTolerance(Number(event.target.value))}
                    />
                  </div>

                  <div className="button-row">
                    <button
                      className={`tool-button${toolMode === "pick" ? " is-active" : ""}`}
                      type="button"
                      onClick={() => setToolMode("pick")}
                    >
                      取色工具
                    </button>
                    <button
                      className="secondary-button"
                      type="button"
                      disabled={!hasWorkingImage}
                      onClick={handleApplyColorTransparency}
                    >
                      应用背景色透明化
                    </button>
                  </div>
                </div>
              </section>

              <section className="section-card">
                <div className="section-head">
                  <div>
                    <h3>边缘修正</h3>
                    <p>羽化用于柔化过渡，去白边 / 去黑边适合修掉抠图后残留的描边。</p>
                  </div>
                </div>

                <div className="toolbar-grid">
                  <div className="tool-row">
                    <div className="tool-label">
                      <span>羽化半径</span>
                      <span className="tool-value">{featherRadius}px</span>
                    </div>
                    <input
                      className="range-control"
                      type="range"
                      min="0"
                      max="12"
                      value={featherRadius}
                      onChange={(event) => setFeatherRadius(Number(event.target.value))}
                    />
                  </div>

                  <div className="button-row">
                    <button className="secondary-button" type="button" disabled={!hasWorkingImage} onClick={handleFeather}>
                      应用羽化
                    </button>
                    <button
                      className="ghost-button"
                      type="button"
                      disabled={!hasWorkingImage}
                      onClick={() =>
                        runImageTransform(
                          (imageData) => defringeImage(imageData, "white"),
                          "去白边已完成",
                          "半透明边缘已按白底污染逻辑做了一次修正。",
                        )
                      }
                    >
                      去白边
                    </button>
                    <button
                      className="ghost-button"
                      type="button"
                      disabled={!hasWorkingImage}
                      onClick={() =>
                        runImageTransform(
                          (imageData) => defringeImage(imageData, "black"),
                          "去黑边已完成",
                          "半透明边缘已按黑底污染逻辑做了一次修正。",
                        )
                      }
                    >
                      去黑边
                    </button>
                  </div>
                </div>
              </section>

              <section className="section-card">
                <div className="section-head">
                  <div>
                    <h3>画笔微调</h3>
                    <p>擦除画笔把区域改成透明，恢复画笔会恢复到自动去背景后的初始结果。</p>
                  </div>
                </div>

                <div className="toolbar-grid">
                  <div className="button-row">
                    <button
                      className={`tool-button${toolMode === "erase" ? " is-active" : ""}`}
                      type="button"
                      disabled={!hasWorkingImage}
                      onClick={() => setToolMode("erase")}
                    >
                      擦除画笔
                    </button>
                    <button
                      className={`tool-button${toolMode === "restore" ? " is-active" : ""}`}
                      type="button"
                      disabled={!hasWorkingImage}
                      onClick={() => setToolMode("restore")}
                    >
                      恢复画笔
                    </button>
                  </div>

                  <div className="tool-row">
                    <div className="tool-label">
                      <span>画笔大小</span>
                      <span className="tool-value">{brushSize}px</span>
                    </div>
                    <input
                      className="range-control"
                      type="range"
                      min="6"
                      max="160"
                      value={brushSize}
                      onChange={(event) => setBrushSize(Number(event.target.value))}
                    />
                  </div>
                </div>
              </section>

              <section className="section-card">
                <div className="button-row">
                  <button className="primary-button" type="button" disabled={!hasWorkingImage} onClick={() => void handleDownload()}>
                    下载 PNG
                  </button>
                  <button className="secondary-button" type="button" disabled={!hasWorkingImage} onClick={handleReset}>
                    重置
                  </button>
                </div>
              </section>

              <section className="section-card">
                <div className="section-head">
                  <div>
                    <h3>使用提示</h3>
                  </div>
                </div>
                <ul className="tips-list">
                  <li>自动去背景优先使用后端 rembg，适合人物、物体、产品图等主体抠图。</li>
                  <li>背景比较单一时，可以再叠加“按背景颜色透明化”，把残留底色处理干净。</li>
                  <li>如果边缘发灰、发白或发黑，先用去边，再用羽化和画笔做最后微调。</li>
                </ul>
              </section>
            </div>
          </aside>

          <section className="preview-column">
            <article className="panel-card glass-card">
              <div className="panel-head">
                <div>
                  <h2>原图取色区</h2>
                  <p>取色工具启用时，点击图片即可把背景颜色带入右侧透明化流程。</p>
                </div>
                <span className="meta-badge">{hasSourceImage ? "可取色" : "等待上传"}</span>
              </div>

              <div className="preview-stage">
                <div className="board-frame">
                  <div className="board-scroll">
                    <canvas ref={sourceCanvasRef} onPointerDown={handleSourceCanvasPointerDown}></canvas>
                  </div>
                  {!hasSourceImage ? <div className="preview-placeholder">上传图片后，这里会显示原图，可直接点击取色。</div> : null}
                </div>
              </div>
            </article>

            <article className="panel-card glass-card">
              <div className="panel-head">
                <div>
                  <h2>透明背景预览</h2>
                  <p>棋盘格代表透明区域。点击取色、或用擦除 / 恢复画笔直接在这张结果图上微调。</p>
                </div>
                <span className="meta-badge">{resultMeta?.engine === "source-alpha" ? "已保留原透明" : "自动抠图结果"}</span>
              </div>

              <div className="preview-grid">
                <div className="preview-stage">
                  <div className="board-frame is-checker">
                    <div className={`board-scroll${toolMode !== "pick" ? " is-painting" : ""}`}>
                      <canvas
                        ref={resultCanvasRef}
                        onPointerDown={handleResultCanvasPointerDown}
                        onPointerMove={handleResultCanvasPointerMove}
                      ></canvas>
                    </div>
                    {!hasWorkingImage ? <div className="preview-placeholder">自动去背景完成后，这里会显示透明 PNG 预览。</div> : null}
                    {busy ? (
                      <div className="busy-overlay" aria-live="polite">
                        <div className="busy-spinner" aria-hidden="true"></div>
                        <p>正在生成透明背景结果</p>
                      </div>
                    ) : null}
                  </div>
                </div>

                <div className="preview-stage">
                  <div className="meta-grid">
                    <div className="meta-card">
                      <strong>输出尺寸</strong>
                      <span>{resultMeta ? `${resultMeta.width} × ${resultMeta.height}` : "等待生成"}</span>
                    </div>
                    <div className="meta-card">
                      <strong>引擎</strong>
                      <span>{resultMeta ? resultMeta.engine : "rembg / source alpha"}</span>
                    </div>
                    <div className="meta-card">
                      <strong>原图尺寸</strong>
                      <span>{resultMeta ? `${resultMeta.source_width} × ${resultMeta.source_height}` : "等待上传"}</span>
                    </div>
                    <div className="meta-card">
                      <strong>透明状态</strong>
                      <span>{resultMeta?.has_transparent_background ? "已带透明 Alpha" : "等待生成"}</span>
                    </div>
                  </div>

                  <p className="mini-note">
                    当前工具：
                    {toolMode === "pick" ? "取色工具" : toolMode === "erase" ? "擦除画笔" : "恢复画笔"}
                    。下载时会保存你当前看到的透明结果。
                  </p>
                </div>
              </div>
            </article>
          </section>
        </main>

        <p className="footer-note">
          如果你还想把这个透明 PNG 继续送进像素化、自动切片或材质图集流程，可以再回到首页继续处理。
        </p>
      </div>
    </div>
  );
}

const rootElement = document.getElementById("root");
if (rootElement) {
  ReactDOM.createRoot(rootElement).render(<TransparentBackgroundStudio />);
}
