/* cst-core.jsx — CS Tech platform core: brand tokens, accents, themes, helpers.
   Exported to window.CST for every other script. Loads first (after React/Babel). */

// ---- type ------------------------------------------------------------------
const FONT = "'Bricolage Grotesque', ui-sans-serif, system-ui, sans-serif";

// ---- ink + neutrals --------------------------------------------------------
const INK = '#0F1115';            // Terminal Ink (card surface)
const INK_DEEP = '#0B0D11';       // stage background
const TEXT = '#ECEDF1';           // Signal White
const HAZE = 'rgba(236,237,241,0.58)';   // muted text
const HAZE_DIM = 'rgba(236,237,241,0.40)';
const HAIR = 'rgba(236,237,241,0.10)';   // hairline / borders
const GLASS = 'rgba(236,237,241,0.05)';  // faint glass fill
const GLASS_HI = 'rgba(236,237,241,0.09)';

// ---- brand accents ---------------------------------------------------------
// AMBER is the immutable brand mark + the "starting / idea" color.
const AMBER = '#FFB454';
const AMBER_DEEP = '#F2913A';
// Operating-partner accent (tweakable). Teal is the default "decisions" color.
const OPERATING_OPTIONS = {
  Teal:   ['#46DDC6', '#2BB6D9', '#ECEDF1'],
  Blue:   ['#5B9DFF', '#5BD9FF', '#ECEDF1'],
  Violet: ['#A78BFF', '#E07BD8', '#ECEDF1'],
};
// Per-tool accent triads (graph uses indices, UI uses [0]).
const AMBER_TRIAD = [AMBER, AMBER_DEEP, '#ECEDF1'];

// semantic status colors (used on scorecards / pricing math)
const STATUS = {
  good:  '#5FD08C',   // strong / gain
  watch: '#FFC861',   // caution
  risk:  '#FF7E6E',   // threat / loss
  cold:  '#7FB2C9',   // neutral / informational
};

// ---- the three tools -------------------------------------------------------
// Each tool has a stable identity (icon glyph, blurb, lifecycle phase).
const TOOLS = [
  {
    id: 'validate',
    name: 'Validate an idea',
    glyph: '◇',
    phase: 'STARTING',
    ask: 'Is this idea worth it?',
    tag: 'Pressure-test it before you commit.',
    line: 'Describe it. We map who it’s for, what to watch, and where to start.',
  },
  {
    id: 'swot',
    name: 'SWOT',
    glyph: '◳',
    phase: 'RUNNING',
    ask: 'What’s my next move?',
    tag: 'Your next move — not a worksheet.',
    line: 'Six dimensions, each refreshable, each with the next move to make.',
  },
  {
    id: 'price',
    name: 'Price-It',
    glyph: '$',
    phase: 'RUNNING',
    ask: 'Am I charging enough?',
    tag: 'A job, a service, or the whole business — find the real number.',
    line: 'Find your true hourly rate, a price that hits target, or a valuation band.',
  },
];

// ---- helpers ---------------------------------------------------------------
const clamp = (n, lo = 0, hi = 100) => Math.max(lo, Math.min(hi, n));

// simple FNV-1a hash for result deduplication (returns hex string)
function hashResult(str) {
  let h = 2166136261 >>> 0;
  for (let i = 0; i < (str || '').length; i++) { h ^= str.charCodeAt(i); h = Math.imul(h, 16777619); }
  return (h >>> 0).toString(16);
}

// money formatting — compact, no fake precision
function money(n, { dp = 0 } = {}) {
  if (n == null || !isFinite(n)) return '—';
  const sign = n < 0 ? '-' : '';
  const a = Math.abs(n);
  if (a >= 1_000_000) return `${sign}$${(a / 1_000_000).toFixed(a >= 10_000_000 ? 1 : 2)}M`;
  if (a >= 10_000) return `${sign}$${Math.round(a / 1000)}k`;
  return `${sign}$${a.toLocaleString('en-US', { maximumFractionDigits: dp })}`;
}
const moneyFull = (n) => (n == null || !isFinite(n)) ? '—' :
  `${n < 0 ? '-' : ''}$${Math.abs(Math.round(n)).toLocaleString('en-US')}`;

// defensive JSON extraction from a model response (may wrap in prose/fences)
function parseJSONLoose(raw) {
  if (!raw || typeof raw !== 'string') return null;
  try {
    let s = raw.replace(/```json/gi, '').replace(/```/g, '').trim();
    const a = s.indexOf('{'), b = s.lastIndexOf('}');
    if (a < 0 || b < 0) return null;
    return JSON.parse(s.slice(a, b + 1));
  } catch (e) { return null; }
}

// call the live model with a graceful fallback; never throws
async function askAI(prompt) {
  try {
    // prefer the host-provided shim (design tool)
    if (window.claude && window.claude.complete) {
      const raw = await window.claude.complete(prompt);
      return raw || null;
    }
    // production: call our serverless proxy
    const res = await fetch('/api/complete', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ prompt }),
    });
    if (res.ok) {
      const data = await res.json();
      return data.text || null;
    }
  } catch (e) { /* offline / network error */ }
  return null;
}

window.CST = {
  FONT, INK, INK_DEEP, TEXT, HAZE, HAZE_DIM, HAIR, GLASS, GLASS_HI,
  AMBER, AMBER_DEEP, AMBER_TRIAD, OPERATING_OPTIONS, STATUS, TOOLS,
  clamp, money, moneyFull, parseJSONLoose, askAI, hashResult,
};
