/**
 * Branded boot/install splash for the madarX OS CLI.
 *
 * Zero dependencies — node builtins + the ANSI primitives in ./banner.js only —
 * so it is safe to import from the CLI supervisor (lib/cli/run.js) and from the
 * postinstall script (scripts/postinstall-splash.mjs) without pulling in the
 * runtime or opening the database.
 *
 * Look is the brand-guidelines v1.3 "Sovereign-Mono" splash (see preview.svg):
 * the whole step list prints upfront — pending in Graphite, the active step
 * carries the single live Mars spinner, settled steps resolve to a neutral
 * Platinum ✓ (never green, so Mars never repeats on a settled surface). Closes
 * on a Muted dateline. Degrades to a plain auditable record off-TTY.
 */

import { _palette as P, fg, bold, dim, wordmark, colorEnabled, visibleLength } from './banner.js';

const ON = colorEnabled();
const isTTY = ON && Boolean(process.stdout && process.stdout.isTTY);

// Monospace-safe braille spinner — reads as motion without noise.
const SPINNER = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'];
const sleep = (ms) => new Promise((r) => setTimeout(r, ms));

const GLYPH = {
  done: fg(P.platinum, '✓'),
  fail: fg(P.mars, '✗'),
  pending: fg(P.graphite, '·'),
  bead: fg(P.mars, '●'),
};

// ── cursor hygiene: hide during animation, always restore ─────────────────────
let cursorHidden = false;
function hideCursor() { if (isTTY && !cursorHidden) { process.stdout.write('\x1b[?25l'); cursorHidden = true; } }
function showCursor() { if (cursorHidden) { process.stdout.write('\x1b[?25h'); cursorHidden = false; } }
process.on('exit', showCursor);
process.on('SIGINT', () => { showCursor(); process.exit(130); });

// A step line at a given state. `state`: 'pending' | 'active' | 'done' | 'fail'.
function lineFor(label, state, frame) {
  if (state === 'pending') return `  ${GLYPH.pending} ${fg(P.graphite, label)}`;
  if (state === 'active') return `  ${fg(P.mars, frame)} ${fg(P.bone, label)}`;
  if (state === 'fail') return `  ${GLYPH.fail} ${fg(P.bone, label)}`;
  return `  ${GLYPH.done} ${fg(P.bone, label)}`;
}

/**
 * Run a list of boot steps, rendered the way preview.svg shows them: the whole
 * list appears at once (pending/Graphite), then each step lights its Mars
 * spinner while its real work runs and resolves to a Platinum ✓.
 *
 * @param {Array<{label: string, work: () => Promise<any>}>} steps
 */
export async function bootSequence(steps) {
  if (!isTTY) {
    // CI / piped / NO_COLOR: no animation, just the record an auditor would want.
    for (const s of steps) {
      try { await s.work(); process.stdout.write(lineFor(s.label, 'done') + '\n'); }
      catch { process.stdout.write(lineFor(s.label, 'fail') + '\n'); }
    }
    return;
  }

  const n = steps.length;
  hideCursor();
  try {
    // Paint the full list pending, then park the cursor below it.
    for (const s of steps) process.stdout.write(lineFor(s.label, 'pending') + '\n');

    // Redraw line `i` (0 = top) in place: jump up, clear, write, jump back down.
    const redraw = (i, text) => {
      const up = n - i;
      process.stdout.write(`\x1b[${up}A\r\x1b[2K${text}\r\x1b[${up}B`);
    };

    for (let i = 0; i < n; i++) {
      const s = steps[i];
      let spinning = true, f = 0;
      const anim = (async () => {
        while (spinning) { redraw(i, lineFor(s.label, 'active', SPINNER[f++ % SPINNER.length])); await sleep(80); }
      })();
      try { await s.work(); spinning = false; await anim; redraw(i, lineFor(s.label, 'done')); }
      catch { spinning = false; await anim; redraw(i, lineFor(s.label, 'fail')); }
    }
  } finally {
    showCursor();
  }
}

/** The dateline rule: a Muted mono `date · place · version` stamp. */
export function dateline(version, place = 'Designed in UAE') {
  const stamp = new Date().toISOString().slice(0, 10).replace(/-/g, '.');
  const v = version ? `  ·  v${version}` : '';
  return fg(P.muted, `${stamp}  ·  ${place}${v}`);
}

// ── optional framed panel (used by `madarx run` ready-state, not the splash) ──

/** A framed panel. Graphite border; a single Mars bead leads the headline. */
export function readyBox(lines) {
  const pad = 2;
  const inner = Math.max(...lines.map(visibleLength)) + pad * 2;
  const top = fg(P.graphite, '╭' + '─'.repeat(inner) + '╮');
  const bot = fg(P.graphite, '╰' + '─'.repeat(inner) + '╯');
  const bar = fg(P.graphite, '│');
  const body = lines.map((l) => {
    const gap = inner - visibleLength(l) - pad * 2;
    return `${bar}${' '.repeat(pad)}${l}${' '.repeat(pad + gap)}${bar}`;
  });
  return ['  ' + top, ...body.map((b) => '  ' + b), '  ' + bot].join('\n');
}

/** Standard "ready" panel for a booted instance (the `madarx run` close). */
export function readyPanel({ version, url } = {}) {
  const head = `${GLYPH.bead} ${bold(fg(P.platinum, 'madarX is ready'))}`;
  const hint = `${fg(P.muted, 'run')} ${fg(P.mars, 'madarx')} ${fg(P.muted, '→ dashboard on')} ${fg(P.bone, url || 'http://127.0.0.1:8787')}`;
  return [readyBox([head, hint]), '  ' + dateline(version)].join('\n');
}

export { GLYPH, isTTY as splashIsTTY };
