/**
 * pres/palettes — named palettes with six semantic roles.
 *
 * Every component (text, shape, chart, divider, background) reads from
 * the six roles. Swapping a palette restyles the entire deck because
 * nothing hardcodes a hex.
 *
 * Roles:
 *   bg       — slide background (or base background under decoration)
 *   surface  — cards, callouts, light blocks placed on top of bg
 *   text     — primary body text colour
 *   subtle   — captions, secondary labels, muted dividers
 *   primary  — brand-leading accent: titles, key data points, CTAs
 *   accent   — secondary accent: highlights, chart series #2, eyebrows
 *
 * Hex strings are stored without the leading "#" because pptxgenjs
 * accepts both but the no-# form is canonical in PPTX XML.
 */

/**
 * Palette = 8 semantic roles:
 *   bg        slide background
 *   surface   raised panels / cards / soft callouts
 *   text      primary body colour
 *   subtle    captions, dividers, secondary labels
 *   primary   the deck's leading accent — titles, key data, primary CTAs
 *   accent    secondary accent — chart series #2, eyebrows, links
 *   ink       deepest emphasis — headlines that need to shout, pull-quote glyphs
 *   highlight bright marker colour — pill backgrounds, badges, tag chips
 *             (deliberately distinct from `accent` so component chrome has its own slot)
 */
export const PALETTES = {
  // ─── editorial-warm family ─────────────────────────────────────────
  'cream-charcoal': {
    family: 'editorial',
    bg:        'FAF6EE',
    surface:   'FFFFFF',
    text:      '1A1A1A',
    subtle:    '7A7368',
    primary:   'C04A2D',
    accent:    'E0B872',
    ink:       '0E0908',
    highlight: 'E5594F',
  },
  'ink-paper': {
    family: 'editorial',
    bg:        'FCFCF7',
    surface:   'FFFFFF',
    text:      '0E0E0E',
    subtle:    '5A5A5A',
    primary:   '1B1B1B',
    accent:    'B89060',
    ink:       '000000',
    highlight: 'FFE45E',
  },
  'mint-charcoal': {
    family: 'editorial',
    bg:        'F2F7F4',
    surface:   'FFFFFF',
    text:      '1A2620',
    subtle:    '6A7B73',
    primary:   '2E5E50',
    accent:    'A8C9B4',
    ink:       '0A1410',
    highlight: 'FFB300',
  },

  // ─── tech-bold family ──────────────────────────────────────────────
  'electric-night': {
    family: 'tech',
    bg:        '0A0E1B',
    surface:   '151B2E',
    text:      'F5F7FA',
    subtle:    '8A93A8',
    primary:   '5B8DEF',
    accent:    'F25F4C',
    ink:       'FFFFFF',
    highlight: 'FFD166',
  },
  'cyber-dawn': {
    family: 'tech',
    bg:        'FFFFFF',
    surface:   'F4F6FA',
    text:      '0A0E1B',
    subtle:    '6E7488',
    primary:   '4F6DF5',
    accent:    'F25F4C',
    ink:       '000000',
    highlight: '14B8A6',
  },
  'neon-violet': {
    family: 'tech',
    bg:        '0F0A1B',
    surface:   '1A1330',
    text:      'F5F0FF',
    subtle:    '8E84B5',
    primary:   'A87FFF',
    accent:    'FFD166',
    ink:       'FFFFFF',
    highlight: 'FF6FA3',
  },
  // Linear product palette — explicitly WARM grays (not blue-grays).
  // Background #08090A, surface #1C1D1F, text #F7F8F8 — matches
  // Linear's post-refresh dark mode tone. Purple orb #5E6AD2 lives in
  // the primary slot for hero accent moments.
  'linear-product': {
    family: 'tech',
    bg:        '08090A',
    surface:   '1C1D1F',
    text:      'F7F8F8',
    subtle:    '9A9CA0',
    primary:   '5E6AD2',
    accent:    '7B68EE',
    ink:       'FFFFFF',
    highlight: '4EA8DE',
  },

  // ─── data-heavy family ─────────────────────────────────────────────
  'bloomberg': {
    family: 'data',
    bg:        'FFFFFF',
    surface:   'F4F4F4',
    text:      '1A1A1A',
    subtle:    '6B6B6B',
    primary:   'FF6600',
    accent:    '0066CC',
    ink:       '000000',
    highlight: 'FFEB00',
  },
  'mono-data': {
    family: 'data',
    bg:        'FFFFFF',
    surface:   'F2F2F2',
    text:      '1A1A1A',
    subtle:    '8C8C8C',
    primary:   '111111',
    accent:    'D62728',
    ink:       '000000',
    highlight: 'FFD60A',
  },
  'finch': {
    family: 'data',
    bg:        'FAFAF7',
    surface:   'FFFFFF',
    text:      '1D1D1F',
    subtle:    '86868B',
    primary:   '055CA8',
    accent:    '00A878',
    ink:       '0A0E1B',
    highlight: 'FFD166',
  },

  // ─── mono-keynote family (Vercel / Geist energy) ───────────────────
  // Pure-mode palettes for the Vercel-class theme. Single accent (Geist
  // blue), surfaces in pure greyscale, ink + highlight reserved for
  // the rare moments of colour.
  'mono-light': {
    family: 'mono',
    bg:        'FFFFFF',
    surface:   'FAFAFA',
    text:      '0A0A0A',
    subtle:    '737373',
    primary:   '0070F3',   // Geist blue
    accent:    '0A0A0A',
    ink:       '000000',
    highlight: 'FFE45E',   // sticky-note yellow for callout highlights
  },
  'mono-dark': {
    family: 'mono',
    bg:        '000000',
    surface:   '0A0A0A',
    text:      'FAFAFA',
    subtle:    '737373',
    primary:   '0070F3',   // Geist blue
    accent:    'FAFAFA',
    ink:       'FFFFFF',
    highlight: 'FFE45E',
  },
};

/**
 * Curated chart series for each palette — used by the chart wrapper so
 * multi-series visuals stay on-palette and visually distinguishable.
 * Five colours is enough for ~90% of business charts; beyond that we
 * recycle and rely on legend + shape differentiation.
 */
export const CHART_SERIES = {
  'cream-charcoal': ['C04A2D', '7A7368', 'E0B872', '4A8580', '3E2723'],
  'ink-paper':      ['1B1B1B', '5A5A5A', 'B89060', '7B4A24', 'A5A5A5'],
  'mint-charcoal':  ['2E5E50', 'A8C9B4', '6A7B73', '8B4513', '1A2620'],
  'electric-night': ['5B8DEF', 'F25F4C', '6DD3CE', 'FFD166', 'BC83FF'],
  'cyber-dawn':     ['4F6DF5', 'F25F4C', '14B8A6', 'F59E0B', '7C3AED'],
  'neon-violet':    ['A87FFF', 'FFD166', 'FF6FA3', '4ECDC4', 'A5D8FF'],
  'linear-product': ['5E6AD2', '7B68EE', '4EA8DE', 'F7B955', 'EF4444'],
  'bloomberg':      ['FF6600', '0066CC', 'CC3300', '009933', '6633CC'],
  'mono-data':      ['111111', '8C8C8C', 'D62728', '2CA02C', 'C5B0D5'],
  'finch':          ['055CA8', '00A878', 'F4A261', 'E76F51', '264653'],
  // Vercel/Geist palette family — single accent + greyscale ladder for
  // additional series. Avoids the rainbow chart look that fights the
  // monochrome canvas.
  'mono-light':     ['0070F3', '000000', '737373', '0A0A0A', 'B3B3B3'],
  'mono-dark':      ['0070F3', 'FFFFFF', '737373', 'CCCCCC', '4D4D4D'],
};

/**
 * Default palette per theme family. The theme's id determines which
 * family it belongs to; the agent can override with `palette: 'x'`.
 */
export const DEFAULT_PALETTE_BY_FAMILY = {
  editorial: 'cream-charcoal',
  tech:      'electric-night',
  data:      'bloomberg',
  mono:      'mono-light',
};

/**
 * Resolve a palette name → palette object. Falls back to the family
 * default if the name is unknown. Always returns a valid palette so
 * downstream code doesn't have to null-check.
 */
export function resolvePalette(name, themeFamily = 'editorial') {
  if (name && PALETTES[name]) return { name, ...PALETTES[name] };
  const fallback = DEFAULT_PALETTE_BY_FAMILY[themeFamily] || 'cream-charcoal';
  return { name: fallback, ...PALETTES[fallback] };
}

/**
 * Lighten / darken a hex by a percentage (0-100). Used by background
 * generators to derive secondary stops from a single palette role,
 * which keeps generated backgrounds anchored to the palette.
 */
export function shade(hex, percent) {
  const h = String(hex).replace(/^#/, '');
  if (!/^[0-9A-Fa-f]{6}$/.test(h)) return hex;
  const r = parseInt(h.slice(0, 2), 16);
  const g = parseInt(h.slice(2, 4), 16);
  const b = parseInt(h.slice(4, 6), 16);
  const k = percent / 100;
  const blend = (c) => Math.round(k < 0 ? c * (1 + k) : c + (255 - c) * k);
  const toHex = (n) => n.toString(16).padStart(2, '0').toUpperCase();
  return `${toHex(blend(r))}${toHex(blend(g))}${toHex(blend(b))}`;
}

/**
 * Mix two hex colours by `t` (0 → a, 1 → b). Useful for gradient stops
 * derived from palette roles.
 */
export function mix(a, b, t) {
  const parse = (hex) => {
    const s = String(hex).replace(/^#/, '');
    return [parseInt(s.slice(0, 2), 16), parseInt(s.slice(2, 4), 16), parseInt(s.slice(4, 6), 16)];
  };
  const [ar, ag, ab] = parse(a);
  const [br, bg, bb] = parse(b);
  const lerp = (x, y) => Math.round(x + (y - x) * t);
  const toHex = (n) => n.toString(16).padStart(2, '0').toUpperCase();
  return `${toHex(lerp(ar, br))}${toHex(lerp(ag, bg))}${toHex(lerp(ab, bb))}`;
}
