// Editable design settings for the generated application documents.
//
// Same contract as lib/prompts.js: the defaults live here, an override is a row
// in the `design` table, and deleting the row restores the default.
//
// Two layouts ship today:
//
//   sidebar — the classic: neutral greys, tinted sidebar, DIN-5008 letter. The
//             accent is a single restrained colour; hierarchy comes from weight
//             and tracking. Right for almost every office application.
//
//   social  — a playful media-kit look (rounded cards, pills, hearts, a script
//             headline, a full-page tinted background). Right for creative,
//             social-media and design-adjacent roles — and deliberately loud.
//
// The cover letter always follows the résumé's layout, so both documents arrive
// as one coherent set — that is the whole point of picking a design here.
//
// The palette stays closed (no free colour picker): every tone is one that still
// works when an HR department prints it in greyscale.

// Accent colours. In `sidebar` the accent is the *only* colour; in `social` the
// whole page palette (background, cards, pills) is derived from it, so the
// playful layout works in pink as well as in deep blue.
const AKZENTE = [
  { key: 'anthrazit', label: 'Anthrazit', rgb: [23, 23, 23] },
  { key: 'tiefblau', label: 'Tiefblau', rgb: [30, 58, 95] },
  { key: 'bordeaux', label: 'Bordeaux', rgb: [122, 31, 47] },
  { key: 'waldgruen', label: 'Waldgrün', rgb: [27, 67, 50] },
  { key: 'stahlblau', label: 'Stahlblau', rgb: [51, 65, 85] },
  { key: 'kupfer', label: 'Kupfer', rgb: [124, 62, 24] },
  { key: 'pink', label: 'Pink (verspielt)', rgb: [232, 54, 143] },
  { key: 'violett', label: 'Violett (verspielt)', rgb: [147, 51, 187] },
];

const LAYOUTS = [
  { key: 'sidebar', label: 'Klassisch mit Sidebar (Standard)' },
  { key: 'social', label: 'Social Media (verspielt)' },
];

const SIDEBAR_VARIANTEN = [
  { key: 'neutral', label: 'Neutral grau (Standard)' },
  { key: 'getoent', label: 'Im Akzent getönt' },
  { key: 'weiss', label: 'Weiß (ohne Band)' },
];

const FOTO_FORMEN = [
  { key: 'eckig', label: 'Eckig' },
  { key: 'rund', label: 'Rund' },
];

const SCHRIFT_STUFEN = [
  { key: '90', label: '90 % (kompakt)' },
  { key: '95', label: '95 %' },
  { key: '100', label: '100 % (Standard)' },
  { key: '105', label: '105 %' },
  { key: '110', label: '110 % (groß)' },
];

// Defaults per layout: the playful layout is pink and round by default, because
// anthracite-and-square would defeat the point of choosing it. Any of these can
// still be overridden individually.
const LAYOUT_DEFAULTS = {
  sidebar: { akzent: 'anthrazit', foto_form: 'eckig' },
  social: { akzent: 'pink', foto_form: 'rund' },
};

const DEFAULTS = {
  layout: 'sidebar',
  akzent: 'anthrazit',
  sidebar: 'neutral',
  foto_anzeigen: '1',
  foto_form: 'eckig',
  schrift: '100',
};

const FELDER = [
  { key: 'layout', label: 'Layout', optionen: LAYOUTS },
  { key: 'akzent', label: 'Akzentfarbe', optionen: AKZENTE },
  { key: 'sidebar', label: 'Sidebar-Hintergrund', optionen: SIDEBAR_VARIANTEN, nurLayout: 'sidebar' },
  { key: 'foto_form', label: 'Form des Bewerberfotos', optionen: FOTO_FORMEN },
  { key: 'schrift', label: 'Schriftgröße', optionen: SCHRIFT_STUFEN },
];

const NEUTRAL_SIDEBAR = [242, 243, 245];

// Mix a colour towards white. amount = 0 -> white, 1 -> the colour itself.
function tint(rgb, amount) {
  return rgb.map((c) => Math.round(c * amount + 255 * (1 - amount)));
}
// Mix a colour towards black.
function shade(rgb, amount) {
  return rgb.map((c) => Math.round(c * amount));
}

function findOption(list, key, fallbackKey) {
  return list.find((o) => o.key === key) || list.find((o) => o.key === fallbackKey);
}

// A checkbox paired with a hidden fallback submits *both* values, which Express
// hands over as an array — the last entry is the effective one.
function one(v) {
  return Array.isArray(v) ? v[v.length - 1] : v;
}

// Fold the stored overrides onto the defaults, dropping unknown keys/values so a
// stale row, a hand-crafted query string or a checkbox pair can never produce an
// invalid theme. Fields not explicitly set fall back to the *layout's* default,
// which is why switching to "social" turns pink without touching anything else.
function settings(overrides = {}) {
  const layoutRaw = one(overrides.layout);
  const layout = LAYOUTS.some((l) => l.key === layoutRaw) ? String(layoutRaw) : DEFAULTS.layout;

  const out = { ...DEFAULTS, ...(LAYOUT_DEFAULTS[layout] || {}), layout };

  for (const f of FELDER) {
    if (f.key === 'layout') continue;
    const v = one(overrides[f.key]);
    if (v && f.optionen.some((o) => o.key === String(v))) out[f.key] = String(v);
  }
  const foto = one(overrides.foto_anzeigen);
  if (foto === '0' || foto === '1') out.foto_anzeigen = foto;
  return out;
}

// Build the concrete theme the renderer draws with. Everything the PDF code
// needs to know about the user's choices is in here — the renderer itself has
// no idea these are configurable.
function resolve(overrides = {}) {
  const s = settings(overrides);
  const accent = findOption(AKZENTE, s.akzent, 'anthrazit').rgb;
  const social = s.layout === 'social';

  let sidebarBg;
  if (s.sidebar === 'weiss') sidebarBg = [255, 255, 255];
  else if (s.sidebar === 'getoent') sidebarBg = tint(accent, 0.08);
  else sidebarBg = NEUTRAL_SIDEBAR;

  // The playful layout derives its whole palette from the accent: a tinted page,
  // near-white cards with a soft border, pill chips, and a warm dark ink that is
  // the accent shaded down rather than plain black.
  const rc = social
    ? {
      ink: shade(accent, 0.35),
      sub: tint(shade(accent, 0.55), 0.75),
      hair: tint(accent, 0.30),
      accent,
      pageBg: tint(accent, 0.10),
      cardBg: [255, 255, 255],
      cardBorder: tint(accent, 0.28),
      // Sparkles/blob sit on the tinted page, so they need more punch than the
      // card border or they simply vanish.
      deko: tint(accent, 0.45),
      pillBg: tint(accent, 0.18),
      pillInk: shade(accent, 0.6),
      sidebarBg,          // unused in this layout, kept so the shape stays stable
      track: tint(accent, 0.45),
      onSide: shade(accent, 0.35),
      onSideSub: tint(shade(accent, 0.55), 0.75),
    }
    : {
      ink: [33, 33, 33],
      sub: [92, 96, 100],
      hair: [208, 210, 214],
      accent,
      pageBg: null,       // no page tint in the classic layout
      cardBg: [255, 255, 255],
      cardBorder: [208, 210, 214],
      deko: [208, 210, 214],   // the classic layout draws no sparkles; kept for shape parity
      pillBg: tint(accent, 0.12),
      pillInk: accent,
      sidebarBg,
      track: [199, 202, 208],
      onSide: [38, 40, 44],
      onSideSub: [96, 100, 106],
    };

  // The cover letter always mirrors the résumé, so the two documents read as one
  // set — a playful CV never arrives with a stiff monochrome letter.
  const lc = social
    ? {
      ink: rc.ink,
      muted: rc.sub,
      hair: rc.hair,
      accent,
      pageBg: rc.pageBg,
      cardBg: rc.cardBg,
      cardBorder: rc.cardBorder,
      deko: rc.deko,
      pillBg: rc.pillBg,
      pillInk: rc.pillInk,
    }
    : {
      ink: [26, 26, 26],
      muted: [92, 96, 100],
      hair: [206, 208, 212],
      accent,
      pageBg: null,
      cardBg: [255, 255, 255],
      cardBorder: [206, 208, 212],
      deko: [206, 208, 212],
      pillBg: tint(accent, 0.12),
      pillInk: accent,
    };

  return {
    layout: s.layout,
    // Which typefaces the renderer registers and draws with. The playful layout
    // uses a geometric sans plus a script face for the "Hallo, ich bin" line;
    // the classic one stays on Lato and embeds nothing extra.
    fonts: social
      ? { sans: 'Poppins', script: 'Pacifico' }
      : { sans: 'Lato', script: null },
    rc,
    lc,
    foto: {
      anzeigen: s.foto_anzeigen !== '0',
      rund: s.foto_form === 'rund',
    },
    // Starting scale for the one-page fit. The auto-scaler may still shrink
    // below this when there is a lot of content — it never grows past it.
    scale: (Number(s.schrift) || 100) / 100,
  };
}

// Field list for the Vorlagen UI, with the current selection marked. Fields that
// only apply to one layout carry `nurLayout` so the form can hide them.
function list(overrides = {}) {
  const s = settings(overrides);
  return FELDER.map((f) => ({
    key: f.key,
    label: f.label,
    aktuell: s[f.key],
    nurLayout: f.nurLayout || null,
    optionen: f.optionen.map((o) => ({ key: o.key, label: o.label, gewaehlt: o.key === s[f.key] })),
  }));
}

// True when the user deviates from what the chosen layout would ship with.
function isAngepasst(overrides = {}) {
  const s = settings(overrides);
  const basis = { ...DEFAULTS, ...(LAYOUT_DEFAULTS[s.layout] || {}), layout: s.layout };
  return s.layout !== DEFAULTS.layout || Object.keys(basis).some((k) => s[k] !== basis[k]);
}

module.exports = {
  DEFAULTS, LAYOUT_DEFAULTS, AKZENTE, LAYOUTS, FELDER,
  settings, resolve, list, isAngepasst,
  defaultTheme: () => resolve({}),
};
