// Floating terminal/IDE overlay. Three "modes" so we can show different treatments
// across the 3 variants. All fake — purely visual with a few scripted commands.

function useIsMobile(breakpoint = 600) {
  const [isMobile, setIsMobile] = React.useState(() => window.innerWidth < breakpoint);
  React.useEffect(() => {
    const check = () => setIsMobile(window.innerWidth < breakpoint);
    window.addEventListener('resize', check);
    return () => window.removeEventListener('resize', check);
  }, [breakpoint]);
  return isMobile;
}

function Terminal({ open, onClose, accent = '#e8a84a', mode = 'repl' }) {
  const isMobile = useIsMobile();
  const [lines, setLines] = React.useState([]);
  const [input, setInput] = React.useState('');
  const [chain, setChain] = React.useState({
    height: null,
    mempoolBytes: null,
    mempoolTxs: null,
    fetchedAt: null,
  });
  const scrollRef = React.useRef(null);

  // Fetch live BTC chain data. Silent failure — UI uses fallbacks.
  const fetchChain = React.useCallback(async () => {
    try {
      const [hRes, mRes] = await Promise.allSettled([
        fetch('https://mempool.space/api/blocks/tip/height').then(r => r.text()),
        fetch('https://mempool.space/api/mempool').then(r => r.json()),
      ]);
      setChain(prev => {
        const next = { ...prev, fetchedAt: Date.now() };
        if (hRes.status === 'fulfilled') {
          const h = parseInt(hRes.value, 10);
          if (!isNaN(h) && h > 0) next.height = h;
        }
        if (mRes.status === 'fulfilled' && mRes.value) {
          if (typeof mRes.value.vsize === 'number') next.mempoolBytes = mRes.value.vsize;
          if (typeof mRes.value.count === 'number') next.mempoolTxs = mRes.value.count;
        }
        return next;
      });
    } catch (e) {
      // ignore — fallbacks will render
    }
  }, []);

  React.useEffect(() => {
    if (!open) return;
    setLines([
      { kind: 'sys', text: 'ecash-node v0.1.0-rc1 (drivechain-enabled)' },
      { kind: 'sys', text: 'connected to signet · 14,203 peers' },
      { kind: 'sys', text: `type 'help' for commands. hardfork in ${daysUntil()} days.` },
    ]);
    fetchChain();
  }, [open, fetchChain]);

  React.useEffect(() => {
    if (scrollRef.current) scrollRef.current.scrollTop = scrollRef.current.scrollHeight;
  }, [lines]);

  const runCmd = (raw) => {
    const cmd = raw.trim();
    const out = [{ kind: 'prompt', text: cmd }];
    if (!cmd) { setInput(''); return; }

    const [head, ...rest] = cmd.split(/\s+/);
    switch (head.toLowerCase()) {
      case 'help':
        out.push(
          { kind: 'out', text: 'commands:' },
          { kind: 'out', text: '  help               this list' },
          { kind: 'out', text: '  status             node status' },
          { kind: 'out', text: '  bip300 list        sidechains shipping at fork' },
          { kind: 'out', text: '  bip301 bmm         blind merge mining status' },
          { kind: 'out', text: '  hardfork           countdown' },
          { kind: 'out', text: "  whoami             paul's answer" },
          { kind: 'out', text: '  clear              clear screen' },
        );
        break;
      case 'clear':
        setLines([]); setInput(''); return;
      case 'status': {
        const h = chain.height || approxHeight();
        const mb = chain.mempoolBytes != null ? (chain.mempoolBytes / 1024 / 1024).toFixed(1) : '24.1';
        const tx = chain.mempoolTxs != null ? chain.mempoolTxs.toLocaleString() : '8,302';
        out.push(
          { kind: 'out', text: `block height    : ${h.toLocaleString()}` },
          { kind: 'out', text: `mempool         : ${mb} MB / ${tx} txs` },
          { kind: 'out', text: 'sidechains live : 0 (BIP300 not yet activated on BTC)' },
          { kind: 'out', text: `hardfork eta    : ${daysUntil()} days` },
        );
        // Trigger background refresh so the next status call has fresh data
        fetchChain();
        break;
      }
      case 'bip300':
        if (rest[0] === 'list') {
          out.push(
            { kind: 'out', text: 'ID  NAME           STATUS    PURPOSE' },
            { kind: 'out', text: '──  ─────────────  ────────  ─────────────────────────' },
            { kind: 'out', text: '01  thunder        ready     payments · large blocks' },
            { kind: 'out', text: '02  zside          ready     zk-snark privacy' },
            { kind: 'out', text: '03  bitnames       beta      decentralized identity' },
            { kind: 'out', text: '04  bitassets      beta      tokens · NFTs' },
            { kind: 'out', text: '05  evm            beta      eth contracts on btc' },
            { kind: 'out', text: '06  photon         alpha     quantum-resistant sigs' },
            { kind: 'out', text: '07  truthcoin      draft     prediction markets' },
            { kind: 'out', text: '08  filechain      draft     ipfs-style storage' },
            { kind: 'out', text: '' },
            { kind: 'out', text: 'shipping at fork: ready · beta · alpha' },
            { kind: 'out', text: 'see drivechain.info for full list' },
          );
        } else {
          out.push({ kind: 'err', text: "usage: bip300 list" });
        }
        break;
      case 'bip301':
        out.push(
          { kind: 'out', text: 'blind merge mining: inactive on BTC' },
          { kind: 'out', text: 'activates on eCash L1 at fork (2026-08-21)' },
          { kind: 'out', text: 'lets sidechains pay BTC miners for security' },
        );
        break;
      case 'hardfork': {
        const h = chain.height || approxHeight();
        const target = computeTargetBlock(h);
        out.push(
          { kind: 'out', text: `T-${daysUntil()} days, ${hoursUntil()} hours` },
          { kind: 'out', text: `target block: ~${target.toLocaleString()}` },
          { kind: 'out', text: 'target date:  2026-08-21 15:00 UTC' },
        );
        fetchChain();
        break;
      }
      case 'whoami':
        out.push({ kind: 'out', text: 'you are a person reading a website. good.' });
        break;
      case 'paul':
      case 'sztorc':
        out.push({ kind: 'out', text: "he's around. he's skeptical." });
        break;
      default:
        out.push({ kind: 'err', text: `command not found: ${head}` });
    }

    setLines(l => [...l, ...out]);
    setInput('');
  };

  if (!open) return null;

  // Different chrome per mode
  const title = mode === 'ide' ? '~/ecash/node.sh'
              : mode === 'blocks' ? 'block-stream · live'
              : 'ecash@node ~ %';

  const containerStyle = isMobile ? {
    position: 'fixed',
    left: 0, right: 0, bottom: 0,
    width: '100%',
    height: '78vh',
    borderRadius: '12px 12px 0 0',
    transform: 'none',
  } : {
    position: 'fixed',
    left: '50%', top: '50%',
    transform: 'translate(-50%, -50%)',
    width: 'clamp(320px, 92vw, 720px)',
    height: 'clamp(280px, 80vh, 480px)',
    borderRadius: 6,
  };

  return (
    <div style={{
      ...containerStyle,
      background: '#0a0a0c', border: '1px solid #2a2a30',
      boxShadow: '0 40px 120px rgba(0,0,0,0.7), 0 0 0 1px rgba(255,255,255,0.02)',
      display: 'flex', flexDirection: 'column', zIndex: 1001,
      fontFamily: '"JetBrains Mono", ui-monospace, monospace',
      color: '#d4d4d8', overflow: 'hidden',
    }}>
      {/* header */}
      <div style={{
        padding: 'clamp(8px, 2vh, 10px) clamp(10px, 2.5vw, 14px)',
        borderBottom: '1px solid #1f1f23',
        display: 'flex', alignItems: 'center', justifyContent: 'space-between',
        fontSize: 'clamp(9px, 2.5vw, 11px)', color: '#71717a',
      }}>
        <div style={{ display: 'flex', alignItems: 'center', gap: 'clamp(6px, 1.5vw, 10px)' }}>
          <div style={{ display: 'flex', gap: 'clamp(4px, 1vw, 6px)' }}>
            <span style={{ width: 'clamp(6px, 1.5vw, 10px)', height: 'clamp(6px, 1.5vw, 10px)', borderRadius: '50%', background: '#3a3a42' }} />
            <span style={{ width: 'clamp(6px, 1.5vw, 10px)', height: 'clamp(6px, 1.5vw, 10px)', borderRadius: '50%', background: '#3a3a42' }} />
            <span style={{ width: 'clamp(6px, 1.5vw, 10px)', height: 'clamp(6px, 1.5vw, 10px)', borderRadius: '50%', background: '#3a3a42' }} />
          </div>
          <span style={{ marginLeft: 'clamp(4px, 1vw, 8px)', letterSpacing: '0.04em' }}>{title}</span>
        </div>
        <button onClick={onClose} style={{
          background: 'none', border: 'none', color: '#71717a', cursor: 'pointer',
          fontSize: 'clamp(12px, 3vw, 16px)', padding: 2, lineHeight: 1,
        }}>×</button>
      </div>

      {/* body */}
      <div ref={scrollRef} style={{
        flex: 1, overflowY: 'auto', padding: 'clamp(10px, 2vh, 14px) clamp(12px, 2.5vw, 16px)',
        fontSize: 'clamp(10px, 2vw, 12.5px)', lineHeight: 1.55,
      }}>
        {lines.map((l, i) => (
          <div key={i} style={{
            color: l.kind === 'err' ? '#f87171'
                : l.kind === 'sys' ? '#71717a'
                : l.kind === 'prompt' ? '#e4e4e7'
                : '#a1a1aa',
            whiteSpace: isMobile ? 'pre-wrap' : 'pre',
            wordBreak: isMobile ? 'break-word' : 'normal',
            fontFamily: 'inherit',
          }}>
            {l.kind === 'prompt' ? <><span style={{ color: accent }}>$ </span>{l.text}</> : l.text}
          </div>
        ))}
      </div>

      {/* input */}
      <form onSubmit={e => { e.preventDefault(); runCmd(input); }} style={{
        borderTop: '1px solid #1f1f23', padding: 'clamp(8px, 1.5vh, 10px) clamp(12px, 2.5vw, 16px)',
        display: 'flex', gap: 'clamp(6px, 1.5vw, 8px)', alignItems: 'center',
      }}>
        <span style={{ color: accent, fontSize: 'clamp(11px, 2.5vw, 13px)' }}>$</span>
        <input
          autoFocus
          value={input}
          onChange={e => setInput(e.target.value)}
          style={{
            flex: 1, background: 'transparent', border: 'none', outline: 'none',
            color: '#e4e4e7', fontFamily: 'inherit', fontSize: 'clamp(11px, 2.5vw, 13px)',
          }}
        />
      </form>
    </div>
  );
}

function daysUntil() {
  const diff = window.HARDFORK_DATE.getTime() - Date.now();
  return Math.max(0, Math.floor(diff / 86400000));
}
function hoursUntil() {
  const diff = window.HARDFORK_DATE.getTime() - Date.now();
  return Math.max(0, Math.floor((diff % 86400000) / 3600000));
}

// Fallback when mempool.space is unreachable. Tuned to match ~empirical block
// production rate over the last few years (slightly above 144/day due to
// hashrate growth → blocks come in faster than the 10-min target).
function approxHeight() {
  const genesis = new Date('2009-01-03T18:15:05Z').getTime();
  const days = (Date.now() - genesis) / 86400000;
  return Math.round(days * 149.8);
}

// Project the BTC block height the fork will land on. Round to nearest 1000
// so it reads as a target rather than a fake-precise count.
function computeTargetBlock(currentHeight) {
  const blocksAhead = Math.round(daysUntil() * 144);
  const raw = currentHeight + blocksAhead;
  return Math.round(raw / 1000) * 1000;
}

window.Terminal = Terminal;
