/**
 * Archetype: freeform — escape hatch.
 *
 * When none of the curated archetypes fits, the agent passes a list of
 * `items` and we place them by type. This loses some of the system's
 * design guarantees but the items still get themed colours + fonts.
 *
 * Slots:
 *   - title (optional)
 *   - items  array of { type, ...positionAndContent }
 *       type: 'text' | 'bullets' | 'image' | 'rect' | 'chart'
 *       x/y/w/h are in 0..1 normalised against the safe area (so the
 *       agent thinks "I want this at 60% of the slide width" not "I
 *       want this at 8 inches")
 */
import { applyChrome, callout, placeBullets, placeText } from './_helpers.js';
import { textStyle } from '../typography.js';
import { resolveChart } from '../charts/index.js';

export const id = 'freeform';
export const slots = ['title', 'items'];

function denorm(safe, item) {
  return {
    x: safe.x + (item.x ?? 0) * safe.w,
    y: safe.y + (item.y ?? 0) * safe.h,
    w: (item.w ?? 1) * safe.w,
    h: (item.h ?? 1) * safe.h,
  };
}

export default function render(slide, resolved, content, pptx, ctx) {
  applyChrome(slide, resolved, { bgOverride: content.background, seed: 97, ctx });
  const { safe, header } = resolved.spacing;

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

  for (const raw of (content.items || [])) {
    const frame = denorm(safe, raw);
    const role = raw.role || 'body';
    switch ((raw.type || 'text').toLowerCase()) {
      case 'text': {
        const colorHex = resolved.palette[raw.color] || raw.color || resolved.palette.text;
        slide.addText(String(raw.text || ''), {
          ...frame,
          ...textStyle(resolved.typography, role, { color: colorHex, align: raw.align || 'left' }),
        });
        break;
      }
      case 'bullets':
      case 'list':
        placeBullets(slide, resolved, raw.items || [], frame);
        break;
      case 'image':
        slide.addImage({ ...frame, path: raw.path, data: raw.data });
        break;
      case 'rect':
      case 'card':
        callout(slide, resolved, frame, resolved.palette[raw.color] || raw.color || resolved.palette.surface);
        break;
      case 'chart': {
        const c = resolveChart(raw, resolved);
        if (c && pptx) slide.addChart(pptx.ChartType[c.type] || c.type, c.data, { ...frame, ...c.opts });
        break;
      }
      default:
        // Unknown items fall back to text — never error during render.
        slide.addText(String(raw.text || raw.type || ''), {
          ...frame,
          ...textStyle(resolved.typography, 'body', { color: resolved.palette.text }),
        });
    }
  }
}
