import { readFileSync } from "node:fs";
import { join } from "node:path";
import { expect, test } from "@playwright/test";
import { apiToolPath } from "@snapotter/shared";

// ─── AI Tools ───────────────────────────────────────────────────────
// Tests for: remove-background, upscale, ocr, blur-faces, smart-crop,
// enhance-faces, colorize, noise-removal, red-eye-removal, restore-photo,
// passport-photo, erase-object
//
// These tools require the AI sidecar (Python bridge). Each test detects
// whether the required feature bundle is installed:
//   - 200 = tool works, verify output
//   - 501 FEATURE_NOT_INSTALLED = skip gracefully (expected when bundle missing)
//   - Other errors = genuine failures

const FIXTURES = join(process.cwd(), "tests", "fixtures");
const CONTENT = join(FIXTURES, "content");

let token: string;

test.beforeAll(async ({ request }) => {
  const res = await request.post("/api/auth/login", {
    data: { username: "admin", password: "admin" },
  });
  const body = await res.json();
  token = body.token;
});

function fixture(name: string): Buffer {
  return readFileSync(join(FIXTURES, name));
}

function contentFixture(name: string): Buffer {
  return readFileSync(join(CONTENT, name));
}

const JPG_100x100 = fixture("test-100x100.jpg");
const BLANK_PNG = fixture("test-blank.png");
const HEIC_PORTRAIT = fixture("test-portrait.heic");

/** Minimal valid 1x1 PNG for quick feature-detection probes. */
const TINY_PNG = fixture("test-1x1.png");

/**
 * Determine whether a given AI tool's feature bundle is installed by
 * querying the features API and checking the status of the bundle that
 * enables the tool.
 */
async function isFeatureInstalled(
  request: import("@playwright/test").APIRequestContext,
  toolId: string,
): Promise<boolean> {
  const res = await request.get("/api/v1/features", {
    headers: { Authorization: `Bearer ${token}` },
  });
  if (!res.ok()) return false;
  const data = await res.json();

  // Map tool IDs to their bundle IDs
  const toolBundleMap: Record<string, string> = {
    "remove-background": "background-removal",
    "passport-photo": "background-removal",
    "blur-faces": "face-detection",
    "red-eye-removal": "face-detection",
    "smart-crop": "face-detection",
    "erase-object": "object-eraser-colorize",
    colorize: "object-eraser-colorize",
    "ai-canvas-expand": "object-eraser-colorize",
    upscale: "upscale-enhance",
    "enhance-faces": "upscale-enhance",
    "noise-removal": "upscale-enhance",
    "restore-photo": "photo-restoration",
    ocr: "ocr",
  };

  const bundleId = toolBundleMap[toolId];
  if (!bundleId) return false;

  const bundle = data.bundles?.find((b: { id: string }) => b.id === bundleId);
  return bundle?.status === "installed";
}

/**
 * Post a file to an AI tool and return the response.
 * Handles the 501 FEATURE_NOT_INSTALLED case gracefully.
 */
async function callAiTool(
  request: import("@playwright/test").APIRequestContext,
  toolId: string,
  imageBuffer: Buffer,
  settings: Record<string, unknown> = {},
  filename = "test.png",
  mimeType = "image/png",
): Promise<{ installed: boolean; ok: boolean; status: number; body: Record<string, unknown> }> {
  const res = await request.post(apiToolPath(toolId), {
    headers: { Authorization: `Bearer ${token}` },
    multipart: {
      file: { name: filename, mimeType, buffer: imageBuffer },
      settings: JSON.stringify(settings),
    },
  });

  const status = res.status();
  const body = await res.json();

  if (status === 501 && body.code === "FEATURE_NOT_INSTALLED") {
    return { installed: false, ok: false, status, body };
  }

  return { installed: true, ok: res.ok(), status, body };
}

// ─── Remove Background ──────────────────────────────────────────────

test.describe("Remove Background", () => {
  test("remove background returns download URL or 501", async ({ request }) => {
    const result = await callAiTool(request, "remove-background", JPG_100x100, {});
    if (!result.installed) {
      expect(result.body.feature).toBe("background-removal");
      expect(result.body.featureName).toBeTruthy();
      test.skip();
      return;
    }
    expect(result.ok).toBe(true);
    expect(result.body.downloadUrl).toBeTruthy();
    expect(result.body.processedSize).toBeGreaterThan(0);
  });

  test("remove background with specific model", async ({ request }) => {
    const result = await callAiTool(request, "remove-background", JPG_100x100, {
      model: "u2net",
    });
    if (!result.installed) {
      test.skip();
      return;
    }
    expect(result.ok).toBe(true);
    expect(result.body.downloadUrl).toBeTruthy();
  });

  test("remove background on HEIC image", async ({ request }) => {
    const result = await callAiTool(
      request,
      "remove-background",
      HEIC_PORTRAIT,
      {},
      "portrait.heic",
      "image/heic",
    );
    if (!result.installed) {
      test.skip();
      return;
    }
    expect(result.ok).toBe(true);
    expect(result.body.downloadUrl).toBeTruthy();
  });
});

// ─── Upscale ────────────────────────────────────────────────────────

test.describe("Upscale", () => {
  test("upscale 2x returns larger image or 501", async ({ request }) => {
    const result = await callAiTool(request, "upscale", JPG_100x100, {
      scale: 2,
      model: "auto",
    });
    if (!result.installed) {
      expect(result.body.feature).toBe("upscale-enhance");
      test.skip();
      return;
    }
    expect(result.ok).toBe(true);
    expect(result.body.downloadUrl).toBeTruthy();
    expect(result.body.processedSize).toBeGreaterThan(0);
  });

  test("upscale 4x", async ({ request }) => {
    const result = await callAiTool(request, "upscale", TINY_PNG, {
      scale: 4,
      model: "auto",
    });
    if (!result.installed) {
      test.skip();
      return;
    }
    // 4x upscale on a tiny image may fail with processing error — accept both
    if (result.ok) {
      expect(result.body.downloadUrl).toBeTruthy();
    } else {
      expect(result.body.error).toBeDefined();
    }
  });

  test("upscale with lanczos (CPU fallback)", async ({ request }) => {
    const result = await callAiTool(request, "upscale", JPG_100x100, {
      scale: 2,
      model: "lanczos",
    });
    if (!result.installed) {
      test.skip();
      return;
    }
    expect(result.ok).toBe(true);
    expect(result.body.downloadUrl).toBeTruthy();
  });

  test("upscale with realesrgan model", async ({ request }) => {
    const result = await callAiTool(request, "upscale", TINY_PNG, {
      scale: 2,
      model: "realesrgan",
    });
    if (!result.installed) {
      test.skip();
      return;
    }
    // RealESRGAN may fail on very small images — accept both success and error
    if (result.ok) {
      expect(result.body.downloadUrl).toBeTruthy();
    } else {
      expect(result.body.error).toBeDefined();
    }
  });
});

// ─── OCR ────────────────────────────────────────────────────────────

test.describe("OCR", () => {
  test("OCR processes image or returns 501", async ({ request }) => {
    const result = await callAiTool(request, "ocr", JPG_100x100, {});
    if (!result.installed) {
      expect(result.body.feature).toBe("ocr");
      test.skip();
      return;
    }
    expect(result.ok).toBe(true);
    // OCR response may have text, blocks, or engine field
    expect(result.body.text !== undefined || result.body.blocks !== undefined).toBe(true);
  });

  test("OCR with tesseract engine", async ({ request }) => {
    const result = await callAiTool(request, "ocr", JPG_100x100, { engine: "tesseract" });
    if (!result.installed) {
      test.skip();
      return;
    }
    expect(result.ok).toBe(true);
  });

  test("OCR with paddleocr engine", async ({ request }) => {
    const result = await callAiTool(request, "ocr", JPG_100x100, { engine: "paddleocr" });
    if (!result.installed) {
      test.skip();
      return;
    }
    expect(result.ok).toBe(true);
  });

  test("OCR on Japanese text image", async ({ request }) => {
    const ocrJapanese = contentFixture("ocr-japanese.png");
    const result = await callAiTool(
      request,
      "ocr",
      ocrJapanese,
      {},
      "ocr-japanese.png",
      "image/png",
    );
    if (!result.installed) {
      test.skip();
      return;
    }
    expect(result.ok).toBe(true);
  });

  test("OCR on chat screenshot", async ({ request }) => {
    const ocrChat = contentFixture("ocr-chat.jpeg");
    const result = await callAiTool(request, "ocr", ocrChat, {}, "ocr-chat.jpeg", "image/jpeg");
    if (!result.installed) {
      test.skip();
      return;
    }
    expect(result.ok).toBe(true);
    // Chat screenshot should contain some readable text
    if (result.body.text) {
      expect((result.body.text as string).length).toBeGreaterThan(0);
    }
  });
});

// ─── Blur Faces ─────────────────────────────────────────────────────

test.describe("Blur Faces", () => {
  test("blur faces processes image or returns 501", async ({ request }) => {
    const portrait = contentFixture("portrait-color.jpg");
    const result = await callAiTool(
      request,
      "blur-faces",
      portrait,
      { blurRadius: 30, sensitivity: 0.5 },
      "portrait.jpg",
      "image/jpeg",
    );
    if (!result.installed) {
      expect(result.body.feature).toBe("face-detection");
      test.skip();
      return;
    }
    expect(result.ok).toBe(true);
    expect(result.body.downloadUrl).toBeTruthy();
  });

  test("blur faces on HEIC portrait", async ({ request }) => {
    const result = await callAiTool(
      request,
      "blur-faces",
      HEIC_PORTRAIT,
      { blurRadius: 30 },
      "portrait.heic",
      "image/heic",
    );
    if (!result.installed) {
      test.skip();
      return;
    }
    expect(result.ok).toBe(true);
    expect(result.body.downloadUrl).toBeTruthy();
  });

  test("blur faces on image with no faces returns warning", async ({ request }) => {
    const result = await callAiTool(request, "blur-faces", BLANK_PNG, { blurRadius: 30 });
    if (!result.installed) {
      test.skip();
      return;
    }
    // Should succeed but indicate no faces were found
    expect(result.ok).toBe(true);
    // facesDetected should be 0 or a warning should be present
    if (result.body.facesDetected !== undefined) {
      expect(result.body.facesDetected).toBe(0);
    }
  });

  test("blur faces on multi-face image", async ({ request }) => {
    const multiFace = contentFixture("multi-face.webp");
    const result = await callAiTool(
      request,
      "blur-faces",
      multiFace,
      { blurRadius: 20 },
      "multi-face.webp",
      "image/webp",
    );
    if (!result.installed) {
      test.skip();
      return;
    }
    expect(result.ok).toBe(true);
    expect(result.body.downloadUrl).toBeTruthy();
  });
});

// ─── Smart Crop ─────────────────────────────────────────────────────

test.describe("Smart Crop", () => {
  test("smart crop to portrait dimensions or returns 501", async ({ request }) => {
    const portrait = contentFixture("portrait-color.jpg");
    const result = await callAiTool(
      request,
      "smart-crop",
      portrait,
      { width: 400, height: 400 },
      "portrait.jpg",
      "image/jpeg",
    );
    if (!result.installed) {
      expect(result.body.feature).toBe("face-detection");
      test.skip();
      return;
    }
    expect(result.ok).toBe(true);
    expect(result.body.downloadUrl).toBeTruthy();
  });

  test("smart crop with landscape aspect ratio", async ({ request }) => {
    const portrait = contentFixture("portrait-color.jpg");
    const result = await callAiTool(
      request,
      "smart-crop",
      portrait,
      { width: 800, height: 400 },
      "portrait.jpg",
      "image/jpeg",
    );
    if (!result.installed) {
      test.skip();
      return;
    }
    expect(result.ok).toBe(true);
    expect(result.body.downloadUrl).toBeTruthy();
  });
});

// ─── Enhance Faces ──────────────────────────────────────────────────

test.describe("Enhance Faces", () => {
  test("enhance faces with auto model or returns 501", async ({ request }) => {
    const portrait = contentFixture("portrait-color.jpg");
    const result = await callAiTool(
      request,
      "enhance-faces",
      portrait,
      { model: "auto" },
      "portrait.jpg",
      "image/jpeg",
    );
    if (!result.installed) {
      expect(result.body.feature).toBe("upscale-enhance");
      test.skip();
      return;
    }
    expect(result.ok).toBe(true);
    expect(result.body.downloadUrl).toBeTruthy();
  });

  test("enhance faces with gfpgan model", async ({ request }) => {
    const portrait = contentFixture("portrait-color.jpg");
    const result = await callAiTool(
      request,
      "enhance-faces",
      portrait,
      { model: "gfpgan" },
      "portrait.jpg",
      "image/jpeg",
    );
    if (!result.installed) {
      test.skip();
      return;
    }
    expect(result.ok).toBe(true);
    expect(result.body.downloadUrl).toBeTruthy();
  });

  test("enhance faces with codeformer model", async ({ request }) => {
    const portrait = contentFixture("portrait-color.jpg");
    const result = await callAiTool(
      request,
      "enhance-faces",
      portrait,
      { model: "codeformer" },
      "portrait.jpg",
      "image/jpeg",
    );
    if (!result.installed) {
      test.skip();
      return;
    }
    expect(result.ok).toBe(true);
    expect(result.body.downloadUrl).toBeTruthy();
  });
});

// ─── Colorize ───────────────────────────────────────────────────────

test.describe("Colorize", () => {
  test("colorize B&W image or returns 501", async ({ request }) => {
    const bwPortrait = contentFixture("portrait-bw.jpeg");
    const result = await callAiTool(
      request,
      "colorize",
      bwPortrait,
      { model: "auto" },
      "portrait-bw.jpeg",
      "image/jpeg",
    );
    if (!result.installed) {
      expect(result.body.feature).toBe("object-eraser-colorize");
      test.skip();
      return;
    }
    expect(result.ok).toBe(true);
    expect(result.body.downloadUrl).toBeTruthy();
  });

  test("colorize with ddcolor model", async ({ request }) => {
    const bwPortrait = contentFixture("portrait-bw.jpeg");
    const result = await callAiTool(
      request,
      "colorize",
      bwPortrait,
      { model: "ddcolor" },
      "portrait-bw.jpeg",
      "image/jpeg",
    );
    if (!result.installed) {
      test.skip();
      return;
    }
    expect(result.ok).toBe(true);
    expect(result.body.downloadUrl).toBeTruthy();
  });
});

// ─── Noise Removal ──────────────────────────────────────────────────

test.describe("Noise Removal", () => {
  test("noise removal with quick tier or returns 501", async ({ request }) => {
    const result = await callAiTool(request, "noise-removal", JPG_100x100, {
      tier: "quick",
    });
    if (!result.installed) {
      expect(result.body.feature).toBe("upscale-enhance");
      test.skip();
      return;
    }
    expect(result.ok).toBe(true);
    expect(result.body.downloadUrl).toBeTruthy();
  });

  test("noise removal with balanced tier", async ({ request }) => {
    const result = await callAiTool(request, "noise-removal", JPG_100x100, {
      tier: "balanced",
    });
    if (!result.installed) {
      test.skip();
      return;
    }
    expect(result.ok).toBe(true);
    expect(result.body.downloadUrl).toBeTruthy();
  });

  test("noise removal with quality tier (SCUNet)", async ({ request }) => {
    const result = await callAiTool(request, "noise-removal", JPG_100x100, {
      tier: "quality",
    });
    if (!result.installed) {
      test.skip();
      return;
    }
    expect(result.ok).toBe(true);
    expect(result.body.downloadUrl).toBeTruthy();
  });

  test("noise removal with maximum tier (NAFNet)", async ({ request }) => {
    const result = await callAiTool(request, "noise-removal", TINY_PNG, {
      tier: "maximum",
    });
    if (!result.installed) {
      test.skip();
      return;
    }
    // NAFNet may fail on very small images — accept both success and error
    if (result.ok) {
      expect(result.body.downloadUrl).toBeTruthy();
    } else {
      expect(result.body.error).toBeDefined();
    }
  });
});

// ─── Red-Eye Removal ────────────────────────────────────────────────

test.describe("Red-Eye Removal", () => {
  test("red-eye removal processes image or returns 501", async ({ request }) => {
    const redEye = contentFixture("red-eye.jpg");
    const result = await callAiTool(
      request,
      "red-eye-removal",
      redEye,
      {},
      "red-eye.jpg",
      "image/jpeg",
    );
    if (!result.installed) {
      expect(result.body.feature).toBe("face-detection");
      test.skip();
      return;
    }
    expect(result.ok).toBe(true);
    expect(result.body.downloadUrl).toBeTruthy();
  });

  test("red-eye removal on image without red eyes succeeds gracefully", async ({ request }) => {
    const portrait = contentFixture("portrait-color.jpg");
    const result = await callAiTool(
      request,
      "red-eye-removal",
      portrait,
      {},
      "portrait.jpg",
      "image/jpeg",
    );
    if (!result.installed) {
      test.skip();
      return;
    }
    // Should succeed even if no red eyes found
    expect(result.ok).toBe(true);
    expect(result.body.downloadUrl).toBeTruthy();
  });
});

// ─── Restore Photo ──────────────────────────────────────────────────

test.describe("Restore Photo", () => {
  test("restore photo processes image or returns 501", async ({ request }) => {
    const bwPortrait = contentFixture("portrait-bw.jpeg");
    const result = await callAiTool(
      request,
      "restore-photo",
      bwPortrait,
      {},
      "old-photo.jpeg",
      "image/jpeg",
    );
    if (!result.installed) {
      expect(result.body.feature).toBe("photo-restoration");
      test.skip();
      return;
    }
    expect(result.ok).toBe(true);
    expect(result.body.downloadUrl).toBeTruthy();
    expect(result.body.processedSize).toBeGreaterThan(0);
  });
});

// ─── Passport Photo ─────────────────────────────────────────────────

test.describe("Passport Photo", () => {
  test("passport photo processes portrait or returns 501", async ({ request }) => {
    const portrait = contentFixture("portrait-color.jpg");
    const result = await callAiTool(
      request,
      "passport-photo",
      portrait,
      {},
      "portrait.jpg",
      "image/jpeg",
    );
    if (!result.installed) {
      expect(result.body.feature).toBe("background-removal");
      test.skip();
      return;
    }
    // Passport photo may succeed or fail with "no face detected"
    if (result.ok) {
      expect(result.body.downloadUrl).toBeTruthy();
    } else {
      // Acceptable failure if face detection didn't find a face
      expect(result.body.error).toBeDefined();
      expect(typeof result.body.error).toBe("string");
      expect(result.body.error).not.toContain("[object Object]");
    }
  });

  test("passport photo error is readable for non-face image", async ({ request }) => {
    const result = await callAiTool(request, "passport-photo", BLANK_PNG, {});
    if (!result.installed) {
      test.skip();
      return;
    }
    // Should fail gracefully with a readable error, not [object Object]
    if (!result.ok) {
      expect(typeof result.body.error).toBe("string");
      expect(result.body.error).not.toContain("[object Object]");
      if (result.body.details) {
        expect(typeof result.body.details).toBe("string");
      }
    }
  });

  test("passport photo on headshot portrait", async ({ request }) => {
    const headshot = contentFixture("portrait-headshot.heic");
    const result = await callAiTool(
      request,
      "passport-photo",
      headshot,
      {},
      "headshot.heic",
      "image/heic",
    );
    if (!result.installed) {
      test.skip();
      return;
    }
    if (result.ok) {
      expect(result.body.downloadUrl).toBeTruthy();
    }
  });
});

// ─── Erase Object ───────────────────────────────────────────────────

test.describe("Erase Object", () => {
  test("erase object returns 501 when feature not installed", async ({ request }) => {
    const result = await callAiTool(request, "erase-object", JPG_100x100, {});
    if (!result.installed) {
      expect(result.body.feature).toBe("object-eraser-colorize");
      expect(result.body.code).toBe("FEATURE_NOT_INSTALLED");
      // This is the expected state — erase-object needs a mask and LaMa model
      return;
    }
    // If installed, it may fail because no mask was provided
    // That's still a valid test — we're checking the tool doesn't crash
    expect(typeof result.body.error === "string" || result.body.downloadUrl).toBeTruthy();
  });
});

// ─── AI Canvas Expand ──────────────────────────────────────────────

test.describe("AI Canvas Expand", () => {
  test("expand canvas or returns 501", async ({ request }) => {
    const result = await callAiTool(request, "ai-canvas-expand", JPG_100x100, {
      extendTop: 50,
      extendRight: 50,
      extendBottom: 50,
      extendLeft: 50,
      tier: "fast",
    });
    if (!result.installed) {
      expect(result.body.feature).toBe("object-eraser-colorize");
      expect(result.body.code).toBe("FEATURE_NOT_INSTALLED");
      test.skip();
      return;
    }
    // AI canvas expand is async (returns 202 with jobId)
    if (result.status === 202) {
      expect(result.body.jobId).toBeTruthy();
      expect(result.body.async).toBe(true);
    } else {
      expect(result.ok).toBe(true);
      expect(result.body.downloadUrl).toBeTruthy();
      expect(result.body.processedSize).toBeGreaterThan(0);
    }
  });

  test("expand canvas with zero extend returns same-size image or error", async ({ request }) => {
    const result = await callAiTool(request, "ai-canvas-expand", TINY_PNG, {
      extendTop: 0,
      extendRight: 0,
      extendBottom: 0,
      extendLeft: 0,
      tier: "fast",
    });
    if (!result.installed) {
      test.skip();
      return;
    }
    // Zero expansion may succeed with unchanged image or may return validation error
    if (result.ok || result.status === 202) {
      expect(result.body.downloadUrl || result.body.jobId).toBeTruthy();
    } else {
      expect(result.body.error).toBeDefined();
    }
  });

  test("expand canvas with HEIC input", async ({ request }) => {
    const result = await callAiTool(
      request,
      "ai-canvas-expand",
      HEIC_PORTRAIT,
      { extendRight: 100, tier: "fast" },
      "portrait.heic",
      "image/heic",
    );
    if (!result.installed) {
      test.skip();
      return;
    }
    if (result.status === 202) {
      expect(result.body.jobId).toBeTruthy();
    } else if (result.ok) {
      expect(result.body.downloadUrl).toBeTruthy();
    } else {
      // May fail on edge cases -- acceptable
      expect(result.body.error).toBeDefined();
    }
  });
});

// ─── Feature Bundle Status ──────────────────────────────────────────

test.describe("AI Feature Bundle Status", () => {
  test("all AI tools return correct 501 response when uninstalled", async ({ request }) => {
    // Map from tool ID used for the API POST to the lookup key in isFeatureInstalled
    const aiTools = [
      { tool: "remove-background", featureKey: "remove-background", bundle: "background-removal" },
      { tool: "upscale", featureKey: "upscale", bundle: "upscale-enhance" },
      { tool: "blur-faces", featureKey: "blur-faces", bundle: "face-detection" },
      { tool: "erase-object", featureKey: "erase-object", bundle: "object-eraser-colorize" },
      { tool: "ocr", featureKey: "ocr", bundle: "ocr" },
      { tool: "colorize", featureKey: "colorize", bundle: "object-eraser-colorize" },
      {
        tool: "ai-canvas-expand",
        featureKey: "ai-canvas-expand",
        bundle: "object-eraser-colorize",
      },
      { tool: "enhance-faces", featureKey: "enhance-faces", bundle: "upscale-enhance" },
      { tool: "noise-removal", featureKey: "noise-removal", bundle: "upscale-enhance" },
      { tool: "red-eye-removal", featureKey: "red-eye-removal", bundle: "face-detection" },
      { tool: "restore-photo", featureKey: "restore-photo", bundle: "photo-restoration" },
      { tool: "passport-photo", featureKey: "passport-photo", bundle: "background-removal" },
    ];

    let testedCount = 0;

    for (const { tool, featureKey, bundle } of aiTools) {
      const installed = await isFeatureInstalled(request, featureKey);
      if (installed) continue;

      testedCount++;
      const res = await request.post(apiToolPath(tool), {
        headers: { Authorization: `Bearer ${token}` },
        multipart: {
          file: { name: "test.png", mimeType: "image/png", buffer: TINY_PNG },
          settings: JSON.stringify({}),
        },
      });
      expect(res.status(), `${tool} should return 501`).toBe(501);
      const body = await res.json();
      expect(body.code, `${tool} missing code`).toBe("FEATURE_NOT_INSTALLED");
      expect(body.feature, `${tool} wrong bundle`).toBe(bundle);
      expect(body.featureName, `${tool} missing featureName`).toBeTruthy();
      expect(
        typeof body.estimatedSize === "string",
        `${tool} estimatedSize should be a string`,
      ).toBe(true);
    }

    // If all bundles are installed, skip the test gracefully
    if (testedCount === 0) {
      test.skip();
    }
  });
});

// ─── Transparency Fixer ────────────────────────────────────────────

test.describe("Transparency Fixer", () => {
  test("transparency fixer returns 202 or 501", async ({ request }) => {
    const portrait = contentFixture("portrait-color.jpg");
    const res = await request.post("/api/v1/tools/image/transparency-fixer", {
      headers: { Authorization: `Bearer ${token}` },
      multipart: {
        file: { name: "portrait.jpg", mimeType: "image/jpeg", buffer: portrait },
        settings: JSON.stringify({}),
      },
    });

    if (res.status() === 501) {
      const body = await res.json();
      expect(body.code).toBe("FEATURE_NOT_INSTALLED");
      expect(body.feature).toBe("background-removal");
    } else {
      // Async tool returns 202
      expect(res.status()).toBe(202);
      const body = await res.json();
      expect(body.jobId).toBeTruthy();
      expect(body.async).toBe(true);
    }
  });

  test("transparency fixer with custom defringe", async ({ request }) => {
    const res = await request.post("/api/v1/tools/image/transparency-fixer", {
      headers: { Authorization: `Bearer ${token}` },
      multipart: {
        file: { name: "test.png", mimeType: "image/png", buffer: TINY_PNG },
        settings: JSON.stringify({ defringe: 50, outputFormat: "png" }),
      },
    });

    if (res.status() === 501) {
      const body = await res.json();
      expect(body.code).toBe("FEATURE_NOT_INSTALLED");
    } else {
      expect(res.status()).toBe(202);
      const body = await res.json();
      expect(body.jobId).toBeTruthy();
    }
  });

  test("transparency fixer with webp output", async ({ request }) => {
    const res = await request.post("/api/v1/tools/image/transparency-fixer", {
      headers: { Authorization: `Bearer ${token}` },
      multipart: {
        file: { name: "test.jpg", mimeType: "image/jpeg", buffer: JPG_100x100 },
        settings: JSON.stringify({ outputFormat: "webp" }),
      },
    });

    if (res.status() === 501) {
      const body = await res.json();
      expect(body.code).toBe("FEATURE_NOT_INSTALLED");
    } else {
      expect(res.status()).toBe(202);
      const body = await res.json();
      expect(body.jobId).toBeTruthy();
    }
  });

  test("transparency fixer rejects empty file", async ({ request }) => {
    const res = await request.post("/api/v1/tools/image/transparency-fixer", {
      headers: { Authorization: `Bearer ${token}` },
      multipart: {
        settings: JSON.stringify({}),
      },
    });
    expect(res.ok()).toBe(false);
    const body = await res.json();
    expect(body.error).toBeDefined();
  });
});

// ─── Smart Crop — Additional ──────────────────────────────────────

test.describe("Smart Crop — additional", () => {
  test("smart crop with square output", async ({ request }) => {
    const portrait = contentFixture("portrait-color.jpg");
    const result = await callAiTool(
      request,
      "smart-crop",
      portrait,
      { width: 500, height: 500 },
      "portrait.jpg",
      "image/jpeg",
    );
    if (!result.installed) {
      test.skip();
      return;
    }
    expect(result.ok).toBe(true);
    expect(result.body.downloadUrl).toBeTruthy();
  });

  test("smart crop on multi-face image", async ({ request }) => {
    const multiFace = contentFixture("multi-face.webp");
    const result = await callAiTool(
      request,
      "smart-crop",
      multiFace,
      { width: 300, height: 300 },
      "multi-face.webp",
      "image/webp",
    );
    if (!result.installed) {
      test.skip();
      return;
    }
    expect(result.ok).toBe(true);
    expect(result.body.downloadUrl).toBeTruthy();
  });
});

// ─── Colorize — Additional ───────────────────────────────────────

test.describe("Colorize — additional", () => {
  test("colorize with auto model", async ({ request }) => {
    const bwPortrait = contentFixture("portrait-bw.jpeg");
    const result = await callAiTool(
      request,
      "colorize",
      bwPortrait,
      { model: "auto" },
      "bw.jpeg",
      "image/jpeg",
    );
    if (!result.installed) {
      test.skip();
      return;
    }
    expect(result.ok).toBe(true);
    expect(result.body.downloadUrl).toBeTruthy();
    expect(result.body.processedSize).toBeGreaterThan(0);
  });
});

// ─── Auth Failure ──────────────────────────────────────────────────

test.describe("Auth failure", () => {
  test("remove-background without token returns 401", async ({ request }) => {
    const res = await request.post("/api/v1/tools/image/remove-background", {
      multipart: {
        file: { name: "test.png", mimeType: "image/png", buffer: TINY_PNG },
        settings: JSON.stringify({}),
      },
    });
    expect(res.status()).toBe(401);
  });

  test("upscale without token returns 401", async ({ request }) => {
    const res = await request.post("/api/v1/tools/image/upscale", {
      multipart: {
        file: { name: "test.png", mimeType: "image/png", buffer: TINY_PNG },
        settings: JSON.stringify({ scale: 2, model: "auto" }),
      },
    });
    expect(res.status()).toBe(401);
  });

  test("ocr without token returns 401", async ({ request }) => {
    const res = await request.post("/api/v1/tools/image/ocr", {
      multipart: {
        file: { name: "test.png", mimeType: "image/png", buffer: TINY_PNG },
        settings: JSON.stringify({}),
      },
    });
    expect(res.status()).toBe(401);
  });

  test("transparency-fixer without token returns 401", async ({ request }) => {
    const res = await request.post("/api/v1/tools/image/transparency-fixer", {
      multipart: {
        file: { name: "test.png", mimeType: "image/png", buffer: TINY_PNG },
        settings: JSON.stringify({}),
      },
    });
    expect(res.status()).toBe(401);
  });

  test("blur-faces without token returns 401", async ({ request }) => {
    const res = await request.post("/api/v1/tools/image/blur-faces", {
      multipart: {
        file: { name: "test.png", mimeType: "image/png", buffer: TINY_PNG },
        settings: JSON.stringify({ blurRadius: 30 }),
      },
    });
    expect(res.status()).toBe(401);
  });

  test("colorize without token returns 401", async ({ request }) => {
    const res = await request.post("/api/v1/tools/image/colorize", {
      multipart: {
        file: { name: "test.png", mimeType: "image/png", buffer: TINY_PNG },
        settings: JSON.stringify({}),
      },
    });
    expect(res.status()).toBe(401);
  });
});
