/**
 * Archetype: bentoGrid — asymmetric tiled layout.
 *
 * The pattern Apple popularized for WWDC keynotes and that every modern
 * deck has adopted since. 12-column grid + tiles of varying size signal
 * importance through scale. Each tile is a self-contained mini-slide.
 *
 * Slots:
 *   title    (optional) shared header above the grid
 *   tiles    (required) array of tiles:
 *            {
 *              colStart: 1-12, colSpan: 4|6|8|12,
 *              rowStart: 1-N,  rowSpan: 1|2|3,
 *              kind: 'stat' | 'feature' | 'quote' | 'image' | 'callout',
 *              eyebrow?, headline?, body?, value?, unit?, label?,
 *              accent?: 'primary'|'accent'|'highlight',
 *              icon?: 'circle'|'square'|'arc'|'diamond'|'chevron',
 *            }
 *
 * Layout uses a 12-col grid with 3-row default; tiles can span 4/6/8/12
 * cols and 1/2/3 rows. Gap matches the spacing preset's contentGutter.
 * Cards use the active shape's corner radius — glass-translucent on
 * dark themes (Apple "liquid glass" feel), solid surface on light.
 */
import { applyChrome, placeText, rule } from './_helpers.js';
import { textStyle } from '../typography.js';
import { cardShape, shapeOpts } from '../shapes.js';
import { shade } from '../palettes.js';
import { glassCard } from '../components.js';

export const id = 'bentoGrid';
export const slots = ['title', 'tiles'];

/** Luma-aware dark check — used to pick glass-card vs flat-card surface. */
function isDarkBg(hex) {
  const s = String(hex).replace(/^#/, '');
  if (!/^[0-9A-Fa-f]{6}$/.test(s)) return false;
  const r = parseInt(s.slice(0, 2), 16);
  const g = parseInt(s.slice(2, 4), 16);
  const b = parseInt(s.slice(4, 6), 16);
  return (0.299 * r + 0.587 * g + 0.114 * b) < 110;
}

/* ─── icon glyph in a tile corner ─────────────────────────────────── */
function drawIcon(slide, resolved, { kind, x, y, size, color }) {
  const palette = resolved.palette;
  const fill = palette[color] || palette.primary;
  if (kind === 'circle') {
    slide.addShape('ellipse', { x, y, w: size, h: size, fill: { color: fill }, line: { type: 'none' } });
  } else if (kind === 'square') {
    slide.addShape('rect', { x, y, w: size, h: size, fill: { color: fill }, line: { type: 'none' } });
  } else if (kind === 'arc') {
    slide.addShape('ellipse', { x: x - size * 0.3, y: y - size * 0.3, w: size * 1.6, h: size * 1.6,
      fill: { type: 'none' }, line: { color: fill, width: 2 } });
  } else if (kind === 'diamond') {
    slide.addShape('diamond', { x, y, w: size, h: size, fill: { color: fill }, line: { type: 'none' } });
  } else if (kind === 'chevron') {
    slide.addShape('rightArrow', { x, y, w: size, h: size * 0.7, fill: { color: fill }, line: { type: 'none' } });
  }
}

/* ─── one tile renderer ───────────────────────────────────────────── */
function renderTile(slide, resolved, tile, frame) {
  const palette = resolved.palette;
  const isDark = isDarkBg(palette.bg);

  // Use the dedicated glass-card primitive on dark themes — it draws
  // a proper translucent-gradient surface + 0.5pt inner stroke. On
  // light themes a flat surface card reads cleaner.
  if (isDark) {
    glassCard(slide, resolved, {
      x: frame.x, y: frame.y, w: frame.w, h: frame.h,
      tint: tile.accent,    // subtle colour wash per tile
    });
  } else {
    const shapeKind = cardShape(resolved.shape);
    slide.addShape(shapeKind, {
      x: frame.x, y: frame.y, w: frame.w, h: frame.h,
      ...shapeOpts(resolved.shape, 'card', palette.surface),
    });
  }

  const pad = resolved.spacing.blockPadding;
  const inner = { x: frame.x + pad, y: frame.y + pad, w: frame.w - pad * 2, h: frame.h - pad * 2 };
  const accentColor = palette[tile.accent] || palette.primary;

  // Optional icon in the top-right corner.
  if (tile.icon) {
    drawIcon(slide, resolved, {
      kind: tile.icon, x: frame.x + frame.w - pad - 0.3,
      y: frame.y + pad, size: 0.3, color: tile.accent || 'primary',
    });
  }

  let yCursor = inner.y;

  if (tile.eyebrow) {
    slide.addText(String(tile.eyebrow).toUpperCase(), {
      x: inner.x, y: yCursor, w: inner.w * 0.9, h: 0.28,
      ...textStyle(resolved.typography, 'eyebrow', {
        color: accentColor, align: 'left', bold: true, charSpacing: 2,
      }),
    });
    yCursor += 0.35;
  }

  // The hero element — either a big stat or a headline.
  if (tile.kind === 'stat' && tile.value !== undefined) {
    // Stat tile: big value + smaller unit + tiny label.
    const statH = Math.min(inner.h * 0.55, 2.2);
    // Conservative font sizing keyed to tile height + width so the
    // value never wraps regardless of tile geometry.
    const statFont = Math.min(Math.max(36, statH * 38), Math.max(36, inner.w * 24));
    const chunks = [{
      text: String(tile.value),
      options: {
        fontFace: resolved.typography.display.fontFace,
        fontSize: statFont,
        bold: true,
        color: palette.ink,
        charSpacing: -2,
      },
    }];
    if (tile.unit) chunks.push({
      text: ' ' + tile.unit,
      options: {
        fontFace: resolved.typography.body.fontFace,
        fontSize: statFont * 0.32,
        bold: true,
        color: palette.subtle,
      },
    });
    slide.addText(chunks, {
      x: inner.x, y: yCursor, w: inner.w, h: statH,
      align: 'left', valign: 'middle', fit: 'shrink', wrap: false,
    });
    yCursor += statH + 0.12;
    if (tile.label) {
      slide.addText(String(tile.label), {
        x: inner.x, y: yCursor, w: inner.w, h: inner.h - (yCursor - inner.y),
        ...textStyle(resolved.typography, 'body', {
          color: palette.text, align: 'left', valign: 'top',
        }),
      });
    }
  } else if (tile.kind === 'quote' && tile.headline) {
    slide.addText(`"${tile.headline}"`, {
      x: inner.x, y: yCursor, w: inner.w, h: inner.h - (yCursor - inner.y) - 0.4,
      ...textStyle(resolved.typography, 'subtitle', {
        color: palette.text, align: 'left', italic: true, valign: 'top',
      }),
    });
    if (tile.body) {
      slide.addText(`— ${tile.body}`, {
        x: inner.x, y: inner.y + inner.h - 0.35, w: inner.w, h: 0.3,
        ...textStyle(resolved.typography, 'caption', {
          color: palette.subtle, align: 'left',
        }),
      });
    }
  } else if (tile.headline) {
    // Feature tile: medium headline + body description.
    const hSize = Math.min(28, Math.max(18, inner.h * 11));
    slide.addText(String(tile.headline), {
      x: inner.x, y: yCursor, w: inner.w, h: Math.min(1.0, inner.h * 0.4),
      ...textStyle(resolved.typography, 'title', {
        color: tile.kind === 'callout' ? accentColor : palette.text,
        fontSize: hSize,
        align: 'left', valign: 'top',
      }),
    });
    yCursor += Math.min(1.0, inner.h * 0.4) + 0.12;
    if (tile.body) {
      slide.addText(String(tile.body), {
        x: inner.x, y: yCursor, w: inner.w, h: inner.h - (yCursor - inner.y),
        ...textStyle(resolved.typography, 'body', {
          color: palette.text, align: 'left', valign: 'top',
        }),
      });
    }
  }
}

/* ─── archetype entry ─────────────────────────────────────────────── */
export default function render(slide, resolved, content, _pptx, ctx) {
  applyChrome(slide, resolved, { bgOverride: content.background, seed: 131, ctx });

  const { header, body, contentGutter } = resolved.spacing;
  const palette = resolved.palette;

  // Optional title.
  if (content.title) {
    placeText(slide, resolved, 'title', content.title, {
      x: header.x, y: header.y, w: header.w, h: 0.8,
    }, { color: palette.text, align: 'left' });
  }

  const tiles = Array.isArray(content.tiles) ? content.tiles : [];
  if (!tiles.length) return;

  // Determine row count from max rowStart+rowSpan; default 3.
  const cols = 12;
  const rows = Math.max(3, tiles.reduce((m, t) => Math.max(m, (t.rowStart || 1) + (t.rowSpan || 1) - 1), 3));
  const gap = contentGutter;
  const cellW = (body.w - gap * (cols - 1)) / cols;
  const cellH = (body.h - gap * (rows - 1)) / rows;

  tiles.forEach((tile) => {
    const colStart = Math.max(1, Math.min(cols, tile.colStart || 1));
    const colSpan  = Math.max(1, Math.min(cols - colStart + 1, tile.colSpan || 4));
    const rowStart = Math.max(1, Math.min(rows, tile.rowStart || 1));
    const rowSpan  = Math.max(1, Math.min(rows - rowStart + 1, tile.rowSpan || 1));
    const x = body.x + (colStart - 1) * (cellW + gap);
    const y = body.y + (rowStart - 1) * (cellH + gap);
    const w = colSpan * cellW + (colSpan - 1) * gap;
    const h = rowSpan * cellH + (rowSpan - 1) * gap;
    renderTile(slide, resolved, tile, { x, y, w, h });
  });
}
