// ABOUTME: Export pipeline — composes scene + arbitrary text layers onto a canvas at exact Kobo dims.
// ABOUTME: Produces a download-ready PNG/JPG data URL plus utilities for image loading and compression.

async function exportScreensaver(state, orient, format /* 'png' | 'jpeg' */) {
  const W = orient === "portrait" ? 1264 : 1680;
  const H = orient === "portrait" ? 1680 : 1264;

  const canvas = document.createElement('canvas');
  canvas.width = W; canvas.height = H;
  const ctx = canvas.getContext('2d');

  // Background — uploaded photo, image scene asset, or rasterized SVG scene
  if (state.uploadedImage) {
    const img = await loadImage(state.uploadedImage);
    drawCover(ctx, img, W, H);
  } else {
    const def = getSceneDef(state.scene);
    if (def.kind === "image") {
      const img = await loadImage(def.src);
      drawCover(ctx, img, W, H);
    } else {
      const url = await sceneToDataURL(def.Component, `export-${state.scene}`);
      if (url) {
        const img = await loadImage(url);
        drawCover(ctx, img, W, H);
        URL.revokeObjectURL(url);
      } else {
        ctx.fillStyle = "#1a103e"; ctx.fillRect(0, 0, W, H);
      }
    }
  }

  if (document.fonts && document.fonts.ready) await document.fonts.ready;

  for (const layer of state.layers || []) {
    drawTextLayer(ctx, layer, W, H, state.customColor);
  }

  const mime = format === "jpeg" ? "image/jpeg" : "image/png";
  const quality = format === "jpeg" ? 0.92 : undefined;
  const dataUrl = canvas.toDataURL(mime, quality);
  return { dataUrl, width: W, height: H };
}

function drawTextLayer(ctx, layer, W, H, customColor) {
  if (!layer.text) return;
  const isDivider = layer.kind === "divider";
  const font = resolveFont(layer.font);
  const color = resolveColorValue(layer.color, customColor);
  const sizePx = layer.size;
  const fontFamily = isDivider ? "'Cinzel', serif" : font.family;
  const fontWeight = isDivider ? 500 : font.weight;
  const fontStyle = isDivider ? "normal" : (font.italic ? "italic " : "");

  ctx.save();
  ctx.font = `${fontStyle}${fontWeight} ${sizePx}px ${fontFamily}`;
  ctx.textAlign = "center";
  ctx.textBaseline = "middle";
  if (isDivider) {
    ctx.letterSpacing = "0.5em";
  } else if (font.letterSpacing) {
    ctx.letterSpacing = `${font.letterSpacing}em`;
  } else {
    ctx.letterSpacing = "0";
  }
  ctx.globalAlpha = layer.opacity ?? 1;

  const x = layer.x * W;
  const y = layer.y * H;
  const strength = layer.glow ?? 70;
  const lines = String(layer.text).split("\n");
  const lineHeight = sizePx * 1.05;
  const totalHeight = lineHeight * lines.length;
  const startY = y - totalHeight / 2 + lineHeight / 2;
  const drawAllLines = () => {
    lines.forEach((line, i) => ctx.fillText(line, x, startY + i * lineHeight));
  };

  // Outer glow: stacked draws with expanding shadowBlur. Halo color matches the
  // text when light, falls back to starlight when dark for legibility.
  if (strength > 0) {
    const s = strength / 100;
    const lum = colorLuminance(color);
    const halo = lum > 0.55 ? color : "#fff8e0";
    const passes = [
      { blur: 6,  alpha: Math.min(1, s * 1.0)  },
      { blur: 16, alpha: Math.min(1, s * 0.85) },
      { blur: 36, alpha: Math.min(1, s * 0.6)  },
      { blur: 70, alpha: Math.min(1, s * 0.4)  },
    ];
    for (const p of passes) {
      ctx.shadowColor = hexToRgba(halo, p.alpha);
      ctx.shadowBlur = p.blur;
      ctx.shadowOffsetX = 0;
      ctx.shadowOffsetY = 0;
      ctx.fillStyle = color;
      drawAllLines();
    }
    // Soft drop shadow for legibility
    ctx.shadowColor = `rgba(0,0,0,${(s * 0.55).toFixed(3)})`;
    ctx.shadowBlur = 12;
    ctx.shadowOffsetY = 3;
    ctx.fillStyle = color;
    drawAllLines();
  }

  // Final crisp pass with no shadow
  ctx.shadowColor = "transparent";
  ctx.shadowBlur = 0;
  ctx.shadowOffsetY = 0;
  ctx.fillStyle = color;
  drawAllLines();
  ctx.restore();
}

function drawCover(ctx, img, W, H) {
  const ir = img.width / img.height;
  const cr = W / H;
  let sx, sy, sw, sh;
  if (ir > cr) {
    sh = img.height;
    sw = sh * cr;
    sx = (img.width - sw) / 2;
    sy = 0;
  } else {
    sw = img.width;
    sh = sw / cr;
    sx = 0;
    sy = (img.height - sh) / 2;
  }
  ctx.drawImage(img, sx, sy, sw, sh, 0, 0, W, H);
}

function loadImage(src) {
  return new Promise((resolve, reject) => {
    const img = new Image();
    img.crossOrigin = "anonymous";
    img.onload = () => resolve(img);
    img.onerror = reject;
    img.src = src;
  });
}

function downloadDataUrl(dataUrl, filename) {
  const a = document.createElement('a');
  a.href = dataUrl;
  a.download = filename;
  document.body.appendChild(a);
  a.click();
  a.remove();
}

function readFileAsDataURL(file) {
  return new Promise((resolve, reject) => {
    const reader = new FileReader();
    reader.onload = () => resolve(reader.result);
    reader.onerror = reject;
    reader.readAsDataURL(file);
  });
}

async function compressImage(dataUrl, maxDim = 2400, quality = 0.88) {
  const img = await loadImage(dataUrl);
  let { width, height } = img;
  if (Math.max(width, height) > maxDim) {
    const r = maxDim / Math.max(width, height);
    width = Math.round(width * r);
    height = Math.round(height * r);
  }
  const c = document.createElement('canvas');
  c.width = width; c.height = height;
  c.getContext('2d').drawImage(img, 0, 0, width, height);
  return c.toDataURL('image/jpeg', quality);
}

Object.assign(window, { exportScreensaver, drawTextLayer, downloadDataUrl, readFileAsDataURL, compressImage, loadImage });
