import type { ToolInput } from "../../core/io/input-types";
import type { ToolResult } from "../../core/io/output-types";
import type { ToolContext } from "../../core/plugins/plugin-types";
import type { ImageRedactorOptions } from "./index";

function loadImage(url: string): Promise<HTMLImageElement> {
  return new Promise((resolve, reject) => {
    const img = new Image();
    img.onload = () => resolve(img);
    img.onerror = () => reject(new Error("Failed to load image."));
    img.src = url;
  });
}

function canvasToBlob(
  canvas: HTMLCanvasElement,
  mimeType: string,
  quality = 0.95
): Promise<Blob> {
  return new Promise((resolve, reject) => {
    canvas.toBlob(
      (blob) => {
        if (blob) {
          resolve(blob);
        } else {
          reject(new Error("Failed to export image from canvas."));
        }
      },
      mimeType,
      quality
    );
  });
}

export async function runImageRedactor(
  input: ToolInput,
  options: ImageRedactorOptions,
  context: ToolContext
): Promise<ToolResult> {
  const files = input.files;
  if (!files || !Array.isArray(files) || files.length === 0) {
    throw new Error("No image file uploaded.");
  }

  const file = files[0];
  const url = URL.createObjectURL(file);

  try {
    context.reportProgress({ percentage: 20, message: "Loading image file..." });
    const img = await loadImage(url);

    context.reportProgress({ percentage: 50, message: "Drawing base canvas..." });
    const canvas = document.createElement("canvas");
    canvas.width = img.naturalWidth;
    canvas.height = img.naturalHeight;

    const ctx = canvas.getContext("2d");
    if (!ctx) {
      throw new Error("Could not acquire 2D canvas context.");
    }

    // Draw original image
    ctx.drawImage(img, 0, 0);

    // Apply redactions
    context.reportProgress({ percentage: 70, message: "Applying redaction blocks..." });
    ctx.fillStyle = options.color || "#000000";
    const rects = options.rects || [];

    for (const rect of rects) {
      const rx = (rect.x / 100) * img.naturalWidth;
      const ry = (rect.y / 100) * img.naturalHeight;
      const rw = (rect.w / 100) * img.naturalWidth;
      const rh = (rect.h / 100) * img.naturalHeight;
      ctx.fillRect(rx, ry, rw, rh);
    }

    context.reportProgress({ percentage: 90, message: "Exporting redacted image..." });
    const mimeType = file.type || "image/png";
    const blob = await canvasToBlob(canvas, mimeType);

    // Generate output file name
    const dotIdx = file.name.lastIndexOf(".");
    const name = dotIdx !== -1
      ? `${file.name.substring(0, dotIdx)}_redacted${file.name.substring(dotIdx)}`
      : `${file.name}_redacted.png`;

    context.reportProgress({ percentage: 100, message: "Completed!" });
    return {
      type: "files",
      files: [
        {
          name: name,
          mimeType: mimeType,
          blob: blob,
          sizeAfter: blob.size,
        },
      ],
    };
  } catch (error) {
    console.error("Image Redaction Error:", error);
    throw error instanceof Error ? error : new Error("Unknown error occurred during image redaction");
  } finally {
    URL.revokeObjectURL(url);
  }
}
