import { afterEach, describe, expect, it, vi } from "vitest";

import {
  FEEDBACK_IMAGE_SOURCE_MAX_BYTES,
  fitWithinDimension,
  prepareFeedbackImage,
  validateFeedbackImage,
} from "../feedback-image";

describe("feedback image preparation", () => {
  afterEach(() => {
    vi.unstubAllGlobals();
    vi.restoreAllMocks();
  });

  it("accepts supported formats and rejects unsupported or oversized files", () => {
    expect(
      validateFeedbackImage({ type: "image/png", size: 100 } as File),
    ).toBeNull();
    expect(
      validateFeedbackImage({ type: "image/gif", size: 100 } as File),
    ).toBe("Please choose a JPEG, PNG, or WebP image.");
    expect(
      validateFeedbackImage({
        type: "image/jpeg",
        size: FEEDBACK_IMAGE_SOURCE_MAX_BYTES + 1,
      } as File),
    ).toBe("Each image must be 5 MB or smaller.");
  });

  it("fits images within the maximum dimension without stretching", () => {
    expect(fitWithinDimension(3200, 1600, 1600)).toEqual({
      width: 1600,
      height: 800,
    });
    expect(fitWithinDimension(640, 480, 1600)).toEqual({
      width: 640,
      height: 480,
    });
  });

  it("resizes and compresses large screenshots", async () => {
    const close = vi.fn();
    vi.stubGlobal(
      "createImageBitmap",
      vi.fn(async () => ({ width: 3200, height: 1600, close })),
    );
    const drawImage = vi.fn();
    vi.spyOn(HTMLCanvasElement.prototype, "getContext").mockReturnValue({
      drawImage,
    } as unknown as CanvasRenderingContext2D);
    vi.spyOn(HTMLCanvasElement.prototype, "toBlob").mockImplementation(
      (callback, type) => {
        callback(new Blob(["compressed"], { type: type ?? "image/webp" }));
      },
    );
    const file = new File(
      [new Uint8Array(FEEDBACK_IMAGE_SOURCE_MAX_BYTES - 1)],
      "screen.png",
      { type: "image/png" },
    );

    const result = await prepareFeedbackImage(file);

    expect(result.name).toBe("screen.webp");
    expect(result.type).toBe("image/webp");
    expect(drawImage).toHaveBeenCalledWith(
      expect.anything(),
      0,
      0,
      1600,
      800,
    );
    expect(close).toHaveBeenCalledTimes(1);
  });
});
