import { getDocument } from "pdfjs-dist/legacy/build/pdf.mjs";
import sharp from "sharp";

const TARGET_DPI = 200;
const PDF_DEFAULT_DPI = 72;
const SCALE = TARGET_DPI / PDF_DEFAULT_DPI;

export interface PageImage {
  page: number;
  buffer: Buffer;
  width: number;
  height: number;
}

interface CanvasAndContext {
  canvas: { toBuffer(mime: string): Buffer };
  context: unknown;
}

interface CanvasFactory {
  create(width: number, height: number): CanvasAndContext;
}

export async function pdfToImages(pdfBuffer: Buffer): Promise<PageImage[]> {
  const data = new Uint8Array(pdfBuffer);
  const loadingTask = getDocument({ data, useSystemFonts: true });
  const pdfDocument = await loadingTask.promise;
  const pageCount = pdfDocument.numPages;
  const images: PageImage[] = [];

  const canvasFactory = pdfDocument.canvasFactory as unknown as CanvasFactory;

  console.log(`[pdf] Rendering ${pageCount} page(s) at ${TARGET_DPI} DPI (scale ${SCALE.toFixed(2)})`);

  for (let i = 1; i <= pageCount; i++) {
    const page = await pdfDocument.getPage(i);
    const viewport = page.getViewport({ scale: SCALE });

    const { canvas, context } = canvasFactory.create(
      Math.floor(viewport.width),
      Math.floor(viewport.height)
    );

    // eslint-disable-next-line @typescript-eslint/no-explicit-any
    await page.render({ canvas: canvas as any, viewport } as any).promise;

    const pngBuffer = canvas.toBuffer("image/png");
    page.cleanup();

    let buf = await sharp(pngBuffer).jpeg({ quality: 90 }).toBuffer();
    let meta = await sharp(buf).metadata();
    const w = meta.width || 0;
    const h = meta.height || 0;

    // Duplex scanners flip the sheet between sides, so odd pages
    // (back/response card) are 180-deg rotated relative to even pages
    // (front/survey). Landscape pages need rotation to portrait;
    // the direction depends on which side of the sheet was scanned.
    const isBackSide = i % 2 === 1;

    if (w > h) {
      const angle = isBackSide ? -90 : 90;
      buf = await sharp(buf).rotate(angle).jpeg({ quality: 90 }).toBuffer();
      meta = await sharp(buf).metadata();
    } else if (isBackSide) {
      buf = await sharp(buf).rotate(180).jpeg({ quality: 90 }).toBuffer();
      meta = await sharp(buf).metadata();
    }

    images.push({
      page: i,
      buffer: buf,
      width: meta.width || Math.floor(viewport.width),
      height: meta.height || Math.floor(viewport.height),
    });
  }

  await pdfDocument.destroy();
  return images;
}

export async function imageToBase64(buffer: Buffer): Promise<string> {
  const processed = await sharp(buffer)
    .resize(1200, undefined, { withoutEnlargement: true })
    .jpeg({ quality: 85 })
    .toBuffer();
  return processed.toString("base64");
}

export async function processUploadedImage(buffer: Buffer): Promise<Buffer> {
  return sharp(buffer)
    .resize(1600, undefined, { withoutEnlargement: true })
    .normalize()
    .sharpen()
    .jpeg({ quality: 90 })
    .toBuffer();
}
