/* Shared OMR sheet geometry — one source of truth for the sheet PRINTER and
   the sheet SCANNER. All coordinates are millimetres on an A4 page
   (210 × 297). The printer renders bubbles at these exact positions; the
   scanner finds the four corner registration marks (fiducials) and maps
   image pixels back onto this mm grid, so bubble centres are known. */

export const OMR_PAGE = { w: 210, h: 297 };

/** solid corner squares used for alignment */
export const OMR_FIDUCIAL = { size: 8, margin: 8 };

// keep clear of the corner fiducials (they occupy x 194–202, y 8–16)
export const OMR_QR = { size: 22, x: OMR_PAGE.w - 52 - 22, y: 10 };

/** bubble grid — 4 options (A–D) per row, one row per question */
export const OMR_GRID = {
  x: 52, // left edge of the option-A bubble centre column (grid centred)
  y: 82, // centre of the first question row (below header/info/instructions)
  optionPitchX: 10.5, // A → B → C → D horizontal distance
  rowPitchY: 6.6, // question 1 → 2 → … vertical distance
  bubbleR: 2.5, // bubble radius (mm)
  maxRows: 30,
};

export function omrBubbleCenter(question: number, option: number): { x: number; y: number } {
  return {
    x: OMR_GRID.x + option * OMR_GRID.optionPitchX,
    y: OMR_GRID.y + question * OMR_GRID.rowPitchY,
  };
}

/** the four fiducial centres (TL, TR, BL, BR) in mm */
export function omrFiducialCenters(): { x: number; y: number }[] {
  const m = OMR_FIDUCIAL.margin + OMR_FIDUCIAL.size / 2;
  return [
    { x: m, y: m },
    { x: OMR_PAGE.w - m, y: m },
    { x: m, y: OMR_PAGE.h - m },
    { x: OMR_PAGE.w - m, y: OMR_PAGE.h - m },
  ];
}

/** QR payload: OMR|scheduleId|roll|setLabel */
export function omrQrPayload(scheduleId: number, roll: string, setLabel: string | null): string {
  return `OMR|${scheduleId}|${roll}|${setLabel ?? ""}`;
}

export function parseOmrQr(text: string): { scheduleId: number; roll: string; setLabel: string | null } | null {
  const parts = text.trim().split("|");
  if (parts.length !== 4 || parts[0] !== "OMR") return null;
  const scheduleId = Number(parts[1]);
  if (!Number.isInteger(scheduleId) || !parts[2]) return null;
  return { scheduleId, roll: parts[2], setLabel: parts[3] || null };
}
