/**
 * Shared archetype helpers — text placement, footer chrome,
 * rule lines, callout cards. Every archetype reuses these so styling
 * stays consistent across slide types.
 */
import { textStyle } from '../typography.js';
import { cardShape, shapeOpts } from '../shapes.js';
import { applyBackground } from '../backgrounds/index.js';
import { headerChrome, footerChrome } from '../components.js';

/**
 * Apply background + (when ctx is supplied) the per-slide chrome.
 *
 * The slide master already paints the bg flat colour + the top accent
 * stripe. Background-generators (mesh / geometric / grid / etc.) draw
 * dynamic decorative shapes on top per slide; chrome renders dynamic
 * text (section name, slide number, brand, progress dots).
 *
 *   - `bgOverride` lets an individual slide request a different
 *     background style than the theme default.
 *   - `seed` is forwarded so deterministic background generators
 *     (mesh) place their blobs consistently per slide.
 *   - `ctx` from buildDeckContext: { slideIndex, totalSlides,
 *     sectionName, sectionIdx, sectionTotal, brand, isSectionStart }.
 *     When omitted the archetype is responsible for any extra chrome
 *     (hero/section/closing intentionally skip it).
 */
export function applyChrome(slide, resolved, { bgOverride, seed, ctx, chrome } = {}) {
  applyBackground(slide, resolved, bgOverride || resolved.bg, { seed });

  if (ctx && chrome !== false) {
    headerChrome(slide, resolved, {
      sectionName: ctx.sectionName,
      slideNumber: ctx.slideIndex + 1,
      totalSlides: ctx.totalSlides,
    });
    footerChrome(slide, resolved, {
      brand: ctx.brand,
      sectionTotal: ctx.sectionTotal,
      currentSectionIdx: ctx.sectionIdx,
    });
  }
}

/** Draw a single horizontal accent rule at (x, y, w). */
export function rule(slide, x, y, w, color, weight = 1) {
  slide.addShape('line', {
    x, y, w, h: 0,
    line: { color, width: weight },
  });
}

/** Draw a small uppercase eyebrow label above a title block.
 *
 * Skips the uppercase transform when the text contains template tokens
 * `{{name}}` so token names stay intact for pres.fill — tokens
 * uppercased to `{{NAME}}` would never match the lowercase values map
 * the agent passes to fill. We still bump letter-spacing for the eyebrow
 * look; the fill step (or downstream uppercase-in-data) can rebuild the
 * fully-rendered casing if needed.
 */
export function eyebrow(slide, resolved, text, { x, y, w, color }) {
  const raw = String(text || '');
  const hasTokens = /\{\{[^}]+\}\}/.test(raw);
  const display = hasTokens ? raw : raw.toUpperCase();
  slide.addText(display, {
    x, y, w, h: 0.25,
    ...textStyle(resolved.typography, 'eyebrow', {
      color: color || resolved.palette.primary,
      align: 'left',
    }),
  });
}

/** Place a single block of text — wraps {@link textStyle} for brevity. */
export function placeText(slide, resolved, role, text, frame, overrides = {}) {
  if (text === undefined || text === null || text === '') return;
  slide.addText(String(text), {
    ...frame,
    ...textStyle(resolved.typography, role, overrides),
  });
}

/** Place a stack of bullet items into a frame. */
export function placeBullets(slide, resolved, items, frame, overrides = {}) {
  const rows = (items || []).map((li) => {
    const text = typeof li === 'string' ? li : (li.text || '');
    const bullet = (typeof li === 'object' && li.bullet === false)
      ? false
      : { type: (typeof li === 'object' && li.ordered) ? 'number' : 'bullet' };
    return { text, options: { bullet } };
  });
  slide.addText(rows, {
    ...frame,
    ...textStyle(resolved.typography, 'body', { color: resolved.palette.text, ...overrides }),
    paraSpaceAfter: resolved.spacing.paragraphGap * 8, // pptxgenjs unit ≈ point
  });
}

/**
 * Draw a "callout card" — a filled rectangle with optional shadow
 * and the active shape's corner radius. Used to wrap stat numbers,
 * data tables, charts on `tech-bold`.
 */
export function callout(slide, resolved, frame, fillColor) {
  const opts = shapeOpts(resolved.shape, 'card', fillColor || resolved.palette.surface);
  slide.addShape(cardShape(resolved.shape), {
    x: frame.x, y: frame.y, w: frame.w, h: frame.h,
    ...opts,
  });
}
