/* global React */
// BootStick terminal demo — modeled on the real zsh script.
// Cenas espelham o que o usuário vê de verdade: logo ASCII, step indicator,
// menus com [N] e ▶, confirmação visual [1]Sim/[2]Não, fases reais do
// createinstallmedia, montagem da EFI.

const { useState, useEffect, useRef } = React;

const LOGO = [
  "  ____              _    _____ _   _      _    ",
  " |  _ \\            | |  / ____| | (_)    | |   ",
  " | |_) | ___   ___ | |_| (___ | |_ _  ___| | __",
  " |  _ < / _ \\ / _ \\| __|\\___ \\| __| |/ __| |/ / ",
  " | |_) | (_) | (_) | |_ ____) | |_| | (__|   <  ",
  " |____/ \\___/ \\___/ \\__|_____/ \\__|_|\\___|_|\\_\\ ",
];

// step indicator: each entry is {label, state}
//   state: "dim" | "ok" | "now" | "next"
function stepLine(steps) {
  return { t: "steps", steps };
}

const SCENES = [
  // -------------------------------------------------------------------
  // 1. Main menu — initial state
  // -------------------------------------------------------------------
  {
    lines: [
      { t: "logo" },
      { t: "spacer" },
      { t: "version" },
      { t: "divider" },
      { t: "subtitle", c: "Pendrive bootável macOS · OpenCore" },
      { t: "spacer" },
      stepLine([
        { label: "macOS",  state: "dim" },
        { label: "Disco",  state: "dim" },
        { label: "Format", state: "dim" },
        { label: "Boot",   state: "dim" },
        { label: "EFI",    state: "dim" },
      ]),
      { t: "spacer" },
      { t: "kv2", k: "Disco:", v: "—",  vClass: "dim" },
      { t: "kv2", k: "macOS:", v: "—",  vClass: "dim" },
      { t: "spacer" },
      { t: "menu", sel: 1, items: [
        { n: 1, c: "Obter instalador macOS" },
        { n: 2, c: "Selecionar disco USB/SSD" },
        { n: 3, c: "Ajuda / sobre" },
        { n: 4, c: "Sair" },
      ]},
      { t: "spacer" },
      { t: "hint", c: "↑↓ navegar   Enter selecionar   número atalho" },
    ],
    hold: 2400,
    title: "BootStick — menu principal",
  },

  // -------------------------------------------------------------------
  // 2. Choose macOS installer
  // -------------------------------------------------------------------
  {
    lines: [
      { t: "header2", c: "Obter instalador macOS" },
      { t: "divider" },
      { t: "spacer" },
      { t: "subtitle", c: "Encontrados em /Applications:" },
      { t: "spacer" },
      { t: "picker-row", sel: true,  cols: ["Install macOS Sequoia", "v15.5",   "~14 GB"] },
      { t: "picker-row", sel: false, cols: ["Install macOS Sonoma",  "v14.7",   "~13 GB"] },
      { t: "picker-row", sel: false, cols: ["Install macOS Ventura", "v13.7",   "~12 GB"] },
      { t: "spacer" },
      { t: "subtitle", c: "Outras opções:" },
      { t: "picker-row", sel: false, cols: ["↓  Baixar dos servidores Apple..."] },
      { t: "picker-row", sel: false, cols: ["📂 Selecionar .app manualmente (gibMacOS etc.)"] },
      { t: "spacer" },
      { t: "hint", c: "↑↓ navegar   Enter selecionar   número atalho   Q voltar" },
    ],
    hold: 2600,
    title: "BootStick — selecionar instalador",
  },

  // -------------------------------------------------------------------
  // 3. Choose external disk
  // -------------------------------------------------------------------
  {
    lines: [
      { t: "header2", c: "Selecionar disco" },
      { t: "divider" },
      { t: "spacer" },
      { t: "picker-head", cols: ["Disco", "Nome", "Tamanho"] },
      { t: "spacer" },
      { t: "picker-row", sel: true,  cols: ["/dev/disk4",  "Samsung USB 3.1", "32.0 GB"] },
      { t: "picker-row", sel: false, cols: ["/dev/disk5",  "SanDisk Ultra",   "64.0 GB"] },
      { t: "picker-row", sel: false, cols: ["↺  Atualizar lista de discos"] },
      { t: "spacer" },
      { t: "warn", c: "⚠  Discos internos não aparecem — só removíveis." },
      { t: "spacer" },
      { t: "hint", c: "↑↓ navegar   Enter selecionar   Q voltar" },
    ],
    hold: 2400,
    title: "BootStick — selecionar disco",
  },

  // -------------------------------------------------------------------
  // 4. Format confirmation with [1] Sim / [2] Não visual picker
  // -------------------------------------------------------------------
  {
    lines: [
      { t: "header2", c: "Formatar disco" },
      { t: "divider" },
      { t: "spacer" },
      { t: "kv2", k: "Nome:",    v: "Samsung USB 3.1" },
      { t: "kv2", k: "Destino:", v: "/dev/disk4" },
      { t: "kv2", k: "Volume:",  v: "Install macOS" },
      { t: "kv2", k: "Esquema:", v: "GPT + Mac OS Extended (Journaled)" },
      { t: "spacer" },
      { t: "subtitle", c: "Conteúdo atual:" },
      { t: "raw", c: "  /dev/disk4 (external, physical):" },
      { t: "raw", c: "  #:                  TYPE NAME    SIZE       IDENTIFIER" },
      { t: "raw", c: "  0:  GUID_partition_scheme       *32.0 GB    disk4" },
      { t: "raw", c: "  1:  EFI EFI                     209.7 MB    disk4s1" },
      { t: "raw", c: "  2:  Microsoft Basic Data        31.8 GB     disk4s2" },
      { t: "spacer" },
      { t: "warn", c: "⚠  Todo o conteúdo do disco será APAGADO permanentemente." },
      { t: "spacer" },
      { t: "prompt2", c: "Formatar /dev/disk4 agora?" },
      { t: "confirm2", selYes: true, yes: "[1]  Sim", no: "[2]  Não" },
      { t: "spacer" },
      { t: "hint", c: "↑↓ navegar   Enter confirmar   Esc cancelar" },
    ],
    hold: 2800,
    title: "BootStick — confirmar formatação",
  },

  // -------------------------------------------------------------------
  // 5. createinstallmedia in progress (multi-phase)
  // -------------------------------------------------------------------
  {
    lines: [
      { t: "header2", c: "Criar instalador bootável" },
      { t: "divider" },
      { t: "spacer" },
      { t: "kv2", k: "Disco:",      v: "Samsung USB 3.1" },
      { t: "kv2", k: "Instalador:", v: "Install macOS Sequoia" },
      { t: "kv2", k: "Volume:",     v: "/Volumes/Install macOS" },
      { t: "spacer" },
      { t: "log",  c: "·  Iniciando createinstallmedia...",  tag: "" },
      { t: "spacer" },
      { t: "progress2", pct: 100, label: "Apagando disco",      elapsed: "12s",  done: true },
      { t: "progress2", pct:  68, label: "Copiando arquivos",   elapsed: "4m18s", done: false },
      { t: "spacer" },
      { t: "subtitle", c: "Pode levar 15–40 minutos. Não feche o Terminal." },
    ],
    hold: 2800,
    title: "BootStick — gravando instalador",
  },

  // -------------------------------------------------------------------
  // 6. EFI mounted + finished
  // -------------------------------------------------------------------
  {
    lines: [
      { t: "header2", c: "Montar partição EFI" },
      { t: "divider" },
      { t: "spacer" },
      { t: "spinner", c: "Montando /dev/disk4s1 ..." },
      { t: "ok",   c: "✓ EFI aberta no Finder — copie sua pasta EFI do OpenCore." },
      { t: "spacer" },
      stepLine([
        { label: "macOS ✓",   state: "ok" },
        { label: "Disco ✓",   state: "ok" },
        { label: "Format ✓",  state: "ok" },
        { label: "Boot ✓",    state: "ok" },
        { label: "EFI →",     state: "now" },
      ]),
      { t: "spacer" },
      { t: "done", c: "tudo pronto — seu pendrive Hackintosh está bootável" },
      { t: "spacer" },
      { t: "hint", c: "Pressione ENTER para continuar..." },
    ],
    hold: 3400,
    title: "BootStick — pronto",
  },
];

// --------------------------------------------------------------------
// Line renderers
// --------------------------------------------------------------------

function Caret() { return <span className="bs-caret" />; }

function StepIndicator({ steps, typed }) {
  // typed=N means show first N step labels (and dim arrows accordingly).
  // For the steps line, we render fully once "typed" reaches 1 (boolean-ish).
  if (!typed) return <div className="bs-steps">&nbsp;</div>;
  return (
    <div className="bs-steps">
      {steps.map((s, i) => (
        <React.Fragment key={i}>
          <span className={`bs-step bs-step-${s.state}`}>{s.label}</span>
          {i < steps.length - 1 && <span className="bs-step-arrow">──▶</span>}
        </React.Fragment>
      ))}
    </div>
  );
}

function Line({ ln, typed }) {
  switch (ln.t) {
    case "logo":
      return (
        <pre className="bs-logo">
          {LOGO.join("\n")}
        </pre>
      );
    case "version":
      return (
        <div className="bs-version">
          <span className="bs-version-tag">v1.6.0</span>
          <span className="bs-version-dim">·  build 2026.05.26  ·  Hackintosh / OpenCore</span>
        </div>
      );
    case "divider":
      return <div className="bs-divider">──────────────────────────────────────────────────</div>;
    case "subtitle":
      return <div className="bs-subtitle">{typed}{typed?.length < (ln.c || "").length && <Caret />}</div>;
    case "spacer":
      return <div style={{ height: 6 }} />;
    case "header2":
      return <div className="bs-header2"><span className="bs-header2-mark">▸</span> BootStick <span className="bs-header2-title">{typed}{typed?.length < (ln.c || "").length && <Caret />}</span></div>;
    case "steps":
      return <StepIndicator steps={ln.steps} typed={typed >= 1 ? 1 : 0} />;
    case "kv2":
      return (
        <div className="bs-kv2">
          <span className="bs-kv2-k">{ln.k}</span>
          <span className={`bs-kv2-v ${ln.vClass || ""}`}>{typed}{typed?.length < (ln.v || "").length && <Caret />}</span>
        </div>
      );
    case "menu": {
      const fullyTyped = typed >= 1;
      return (
        <div className="bs-menu">
          {ln.items.map(it => {
            const isSel = it.n === ln.sel;
            return (
              <div key={it.n} className={`bs-menu-item ${isSel ? "bs-menu-item-sel" : ""}`}>
                <span className="bs-menu-mark">{isSel ? "▶" : " "}</span>
                <span className="bs-menu-n">[{it.n}]</span>
                <span className="bs-menu-text">{fullyTyped ? it.c : ""}{!fullyTyped && <Caret />}</span>
              </div>
            );
          })}
        </div>
      );
    }
    case "picker-head":
      return (
        <div className="bs-picker bs-picker-head">
          {ln.cols.map((c, i) => <span key={i} className="bs-picker-col">{c}</span>)}
        </div>
      );
    case "picker-row": {
      const fullyTyped = typed >= 1;
      return (
        <div className={`bs-picker ${ln.sel ? "bs-picker-sel" : ""}`}>
          <span className="bs-picker-mark">{ln.sel ? "▶" : " "}</span>
          {ln.cols.map((c, i) => (
            <span key={i} className="bs-picker-col">{fullyTyped ? c : ""}{!fullyTyped && i === 0 && <Caret />}</span>
          ))}
        </div>
      );
    }
    case "raw":
      return <div className="bs-raw">{ln.c}</div>;
    case "warn":
      return <div className="bs-warn">{typed}{typed?.length < (ln.c || "").length && <Caret />}</div>;
    case "prompt2":
      return <div className="bs-prompt2"><span className="bs-pmark">▸</span> {typed}{typed?.length < (ln.c || "").length && <Caret />}</div>;
    case "confirm2": {
      return (
        <div className="bs-confirm2">
          <div className={`bs-confirm2-row ${ln.selYes ? "bs-confirm2-sel" : ""}`}>
            <span className="bs-confirm2-mark">{ln.selYes ? "▶" : " "}</span>
            <span className="bs-confirm2-text">{ln.yes}</span>
          </div>
          <div className={`bs-confirm2-row ${!ln.selYes ? "bs-confirm2-sel" : ""}`}>
            <span className="bs-confirm2-mark">{!ln.selYes ? "▶" : " "}</span>
            <span className="bs-confirm2-text">{ln.no}</span>
          </div>
        </div>
      );
    }
    case "log":
      return <div className="bs-log2">{typed}{typed?.length < (ln.c || "").length && <Caret />}</div>;
    case "ok":
      return <div className="bs-ok">{typed}{typed?.length < (ln.c || "").length && <Caret />}</div>;
    case "hint":
      return <div className="bs-hint">{typed}</div>;
    case "spinner":
      return (
        <div className="bs-spinner">
          <span className="bs-spinner-frame">⠹</span>
          <span className="bs-spinner-msg">{typed}{typed?.length < (ln.c || "").length && <Caret />}</span>
        </div>
      );
    case "progress2":
      return (
        <div className="bs-prog2">
          <span className="bs-prog2-bar">
            <span className="bs-prog2-fill" style={{ width: `${ln.pct}%` }} />
          </span>
          <span className="bs-prog2-pct">{String(ln.pct).padStart(3, " ")}%</span>
          <span className="bs-prog2-label">{ln.label}</span>
          <span className="bs-prog2-elapsed">{ln.elapsed}</span>
          {ln.done && <span className="bs-prog2-done">✓</span>}
        </div>
      );
    case "done":
      return <div className="bs-done">✓ {typed}{typed?.length < (ln.c || "").length && <Caret />}</div>;
    default:
      return null;
  }
}

// --------------------------------------------------------------------
// Demo runner
// --------------------------------------------------------------------

function TerminalDemo() {
  const [sceneIdx, setSceneIdx] = useState(0);
  const [typed, setTyped] = useState({});
  const sceneRef = useRef(0);
  const timeoutsRef = useRef([]);

  useEffect(() => {
    sceneRef.current = sceneIdx;
    setTyped({});
    timeoutsRef.current.forEach(clearTimeout);
    timeoutsRef.current = [];

    const scene = SCENES[sceneIdx];
    let acc = 100;
    scene.lines.forEach((ln, i) => {
      // Instant lines (no typed content): mark typed=1 after small delay.
      const instantTypes = new Set([
        "logo", "version", "divider", "spacer", "steps", "menu",
        "picker-head", "picker-row", "raw", "confirm2", "progress2",
      ]);
      if (instantTypes.has(ln.t)) {
        const tid = setTimeout(() => {
          if (sceneRef.current !== sceneIdx) return;
          setTyped(prev => ({ ...prev, [i]: 1 }));
        }, acc);
        timeoutsRef.current.push(tid);
        acc += ln.t === "logo" ? 200 : 40;
        return;
      }

      const target = (ln.c || ln.v || "").length;
      if (target === 0) {
        const tid = setTimeout(() => {
          if (sceneRef.current !== sceneIdx) return;
          setTyped(prev => ({ ...prev, [i]: 0 }));
        }, acc);
        timeoutsRef.current.push(tid);
        acc += 30;
        return;
      }

      const charDelay = target > 60 ? 4 : target > 30 ? 8 : 14;
      for (let k = 1; k <= target; k++) {
        const tid = setTimeout(() => {
          if (sceneRef.current !== sceneIdx) return;
          setTyped(prev => ({ ...prev, [i]: k }));
        }, acc + k * charDelay);
        timeoutsRef.current.push(tid);
      }
      acc += target * charDelay + 40;
    });

    const advance = setTimeout(() => {
      setSceneIdx(s => (s + 1) % SCENES.length);
    }, acc + scene.hold);
    timeoutsRef.current.push(advance);

    return () => {
      timeoutsRef.current.forEach(clearTimeout);
      timeoutsRef.current = [];
    };
  }, [sceneIdx]);

  const scene = SCENES[sceneIdx];

  return (
    <div className="bs-term">
      <div className="bs-term-chrome">
        <div className="bs-term-dots">
          <span className="bs-dot bs-dot-r" />
          <span className="bs-dot bs-dot-y" />
          <span className="bs-dot bs-dot-g" />
        </div>
        <div className="bs-term-title">{scene.title}</div>
        <div className="bs-term-tag">zsh · bootstick.sh</div>
      </div>
      <div className="bs-term-body">
        {scene.lines.map((ln, i) => {
          const txt = ln.c || ln.v || "";
          const n = typed[i];
          // For instant types n is 1 once "shown"; for typing types n is char count.
          const typedSlice = typeof n === "number" && txt ? txt.slice(0, n) : (n ? 1 : 0);
          return (
            <Line
              key={`${sceneIdx}-${i}`}
              ln={ln}
              typed={txt ? typedSlice : n}
            />
          );
        })}
      </div>
      <div className="bs-term-foot">
        <div className="bs-stepdots">
          {SCENES.map((_, i) => (
            <span key={i} className={`bs-stepdot ${i === sceneIdx ? "on" : ""} ${i < sceneIdx ? "past" : ""}`} />
          ))}
        </div>
        <button
          className="bs-stepskip"
          onClick={() => setSceneIdx(s => (s + 1) % SCENES.length)}
          aria-label="próximo passo"
        >
          próximo passo →
        </button>
      </div>
    </div>
  );
}

window.TerminalDemo = TerminalDemo;
