/**
 * Synthetic-screenshot builder for the grounding bench.
 *
 * Generates deterministic PNGs of fake desktop UIs (buttons, dialogs,
 * grids) with KNOWN button bounds. The bench scores adapter accuracy
 * against these known truths.
 *
 * Why not use real screenshots: ground-truth coords for real screens
 * change with theme, DPI, OS rendering. Synthetic images are reproducible
 * across CI / dev / production, and the bench numbers are comparable
 * over time.
 *
 * Why `sharp` (already in Loxia's deps): it can synthesize raw images
 * from a buffer + composite primitives in pure Node, no native canvas
 * library required.
 *
 * @typedef {{ x: number, y: number, width: number, height: number }} Rect
 * @typedef {{
 *   id: string,
 *   rect: Rect,
 *   color: [number, number, number],
 *   label?: string,
 * }} ButtonSpec
 */

import sharp from 'sharp';

/** Default canvas background — light gray, like most OSes' window chrome. */
const DEFAULT_BACKGROUND = { r: 245, g: 245, b: 247 };

/** Channel count for the raw RGB buffer sharp consumes. */
const RGB_CHANNELS = 3;

/**
 * Build a single-frame synthetic UI screenshot.
 *
 * @param {Object} spec
 * @param {number}        spec.width
 * @param {number}        spec.height
 * @param {ButtonSpec[]}  spec.buttons
 * @param {{r:number,g:number,b:number}} [spec.background]
 * @returns {Promise<Buffer>} PNG buffer
 */
export async function buildScreenshot({ width, height, buttons, background = DEFAULT_BACKGROUND }) {
  validateDimensions(width, height);
  validateButtons(buttons, width, height);

  // Start with a solid background canvas.
  const base = sharp({
    create: { width, height, channels: RGB_CHANNELS, background },
  });

  // Each button → a solid-colour overlay rectangle composited at its
  // known position. Sharp accepts an array of overlays in one call;
  // we batch for performance.
  const overlays = buttons.map(b => ({
    input: rectBuffer(b.rect.width, b.rect.height, b.color),
    raw: { width: b.rect.width, height: b.rect.height, channels: RGB_CHANNELS },
    top:  b.rect.y,
    left: b.rect.x,
  }));

  return base.composite(overlays).png().toBuffer();
}

/** True center of a button — used by the bench to score predictions. */
export function buttonCenter(button) {
  return {
    x: button.rect.x + Math.floor(button.rect.width / 2),
    y: button.rect.y + Math.floor(button.rect.height / 2),
  };
}

// ── helpers (private to this module) ────────────────────────────────

/**
 * Construct a raw RGB buffer for a solid-colour rectangle. sharp
 * composites these onto the base canvas.
 */
function rectBuffer(width, height, [r, g, b]) {
  const buf = Buffer.alloc(width * height * RGB_CHANNELS);
  for (let i = 0; i < buf.length; i += RGB_CHANNELS) {
    buf[i]     = r;
    buf[i + 1] = g;
    buf[i + 2] = b;
  }
  return buf;
}

function validateDimensions(w, h) {
  if (!Number.isInteger(w) || !Number.isInteger(h) || w < 1 || h < 1) {
    throw new Error(`buildScreenshot: width/height must be positive integers, got ${w}x${h}`);
  }
}

function validateButtons(buttons, canvasW, canvasH) {
  if (!Array.isArray(buttons) || buttons.length === 0) {
    throw new Error('buildScreenshot: at least one button is required');
  }
  buttons.forEach((b, i) => {
    if (!b.id || typeof b.id !== 'string') {
      throw new Error(`button[${i}]: id (string) is required`);
    }
    if (!b.rect || !b.color) {
      throw new Error(`button[${i}]: rect and color are required`);
    }
    const { x, y, width: w, height: h } = b.rect;
    if (!Number.isInteger(x) || !Number.isInteger(y) ||
        !Number.isInteger(w) || !Number.isInteger(h) ||
        w < 1 || h < 1 || x < 0 || y < 0 ||
        x + w > canvasW || y + h > canvasH) {
      throw new Error(`button[${i}] (${b.id}): rect ${JSON.stringify(b.rect)} out of canvas ${canvasW}x${canvasH}`);
    }
    if (!Array.isArray(b.color) || b.color.length !== 3 ||
        !b.color.every(c => Number.isInteger(c) && c >= 0 && c <= 255)) {
      throw new Error(`button[${i}] (${b.id}): color must be [r,g,b] ints in 0..255`);
    }
  });
}
