/* global React, Icon, IconBtn, db */
const { useState, useEffect, useCallback, useRef } = React;

// ============================================================
// Calculator — keyboard + click, history of last 30 expressions
// ============================================================
function CalculatorTool() {
  const [display, setDisplay] = useState('0');
  const [expr, setExpr] = useState('');      // running expression shown above the display
  const [history, setHistory] = useState([]);
  const [overwrite, setOverwrite] = useState(true); // next digit replaces display
  const [memory, setMemory] = useState(0);

  // ---- Load history ----
  useEffect(() => {
    let mounted = true;
    db.kv.get('calculatorHistory').then(rec => {
      if (mounted && Array.isArray(rec?.v)) setHistory(rec.v);
    });
    return () => { mounted = false; };
  }, []);
  const saveHistory = (h) => { setHistory(h); db.kv.put({ k: 'calculatorHistory', v: h.slice(0, 30) }); };

  // ---- Core evaluator — strict subset of math, no eval() ----
  const evaluate = (s) => {
    if (!s || !/^[\d+\-*/().% \s]+$/.test(s)) return NaN;
    // Replace % with /100 so 50% acts like 0.5
    const normalized = s.replace(/(\d+(?:\.\d+)?)\s*%/g, '($1/100)');
    try {
      // eslint-disable-next-line no-new-func
      const v = Function('"use strict"; return (' + normalized + ')')();
      return typeof v === 'number' && Number.isFinite(v) ? v : NaN;
    } catch { return NaN; }
  };

  // ---- Display formatting ----
  const fmt = (n) => {
    if (!Number.isFinite(n)) return 'Error';
    const abs = Math.abs(n);
    if (abs !== 0 && (abs < 1e-6 || abs >= 1e12)) return n.toExponential(6).replace(/\.?0+e/, 'e');
    // Up to 12 significant digits, trim trailing zeros
    const s = n.toPrecision(12);
    return parseFloat(s).toString();
  };

  // ---- Actions ----
  const inputDigit = (d) => {
    if (display === 'Error') { setDisplay(d); setOverwrite(false); return; }
    if (overwrite) { setDisplay(d === '.' ? '0.' : d); setOverwrite(false); return; }
    if (d === '.' && display.includes('.')) return;
    setDisplay(prev => prev === '0' && d !== '.' ? d : prev + d);
  };

  const inputOp = (op) => {
    if (display === 'Error') return;
    setExpr(prev => (prev + ' ' + display + ' ' + op).trim());
    setOverwrite(true);
  };

  const equals = () => {
    if (display === 'Error') return;
    const full = (expr + ' ' + display).trim();
    const v = evaluate(full);
    const result = fmt(v);
    if (result !== 'Error') {
      saveHistory([{ expr: full, result, ts: Date.now() }, ...history]);
    }
    setDisplay(result);
    setExpr('');
    setOverwrite(true);
  };

  const clearAll = () => { setDisplay('0'); setExpr(''); setOverwrite(true); };
  const clearEntry = () => { setDisplay('0'); setOverwrite(true); };
  const backspace = () => {
    if (overwrite || display === 'Error') return;
    setDisplay(prev => (prev.length > 1 ? prev.slice(0, -1) : '0'));
  };
  const toggleSign = () => {
    if (display === 'Error' || display === '0') return;
    setDisplay(prev => (prev.startsWith('-') ? prev.slice(1) : '-' + prev));
  };
  const percent = () => {
    const v = parseFloat(display);
    if (!Number.isFinite(v)) return;
    setDisplay(fmt(v / 100));
    setOverwrite(true);
  };

  const memOp = (op) => {
    const v = parseFloat(display);
    if (!Number.isFinite(v)) return;
    if (op === 'add') setMemory(m => m + v);
    if (op === 'sub') setMemory(m => m - v);
    if (op === 'recall') { setDisplay(fmt(memory)); setOverwrite(true); }
    if (op === 'clear') setMemory(0);
  };

  // ---- Keyboard ----
  useEffect(() => {
    const onKey = (e) => {
      // Don't hijack typing in inputs (history search etc.) — but our calc has no input field.
      if (e.target.tagName === 'INPUT' || e.target.tagName === 'TEXTAREA') return;
      const k = e.key;
      if (/^[0-9]$/.test(k)) { e.preventDefault(); inputDigit(k); }
      else if (k === '.') { e.preventDefault(); inputDigit('.'); }
      else if (k === '+' || k === '-' || k === '*' || k === '/') { e.preventDefault(); inputOp(k); }
      else if (k === 'Enter' || k === '=') { e.preventDefault(); equals(); }
      else if (k === 'Escape') { e.preventDefault(); clearAll(); }
      else if (k === 'Backspace') { e.preventDefault(); backspace(); }
      else if (k === '%') { e.preventDefault(); percent(); }
    };
    window.addEventListener('keydown', onKey);
    return () => window.removeEventListener('keydown', onKey);
  }, [display, expr, overwrite, history]);

  const recall = (h) => { setDisplay(h.result); setOverwrite(true); };
  const clearHistory = () => saveHistory([]);

  // ---- Keypad layout ----
  const keys = [
    { lbl: 'C',  on: clearAll,        cls: 'op' },
    { lbl: 'CE', on: clearEntry,      cls: 'op' },
    { lbl: '⌫',  on: backspace,       cls: 'op', title: 'Backspace' },
    { lbl: '÷',  on: () => inputOp('/'), cls: 'op accent' },
    { lbl: '7',  on: () => inputDigit('7') },
    { lbl: '8',  on: () => inputDigit('8') },
    { lbl: '9',  on: () => inputDigit('9') },
    { lbl: '×',  on: () => inputOp('*'),    cls: 'op accent' },
    { lbl: '4',  on: () => inputDigit('4') },
    { lbl: '5',  on: () => inputDigit('5') },
    { lbl: '6',  on: () => inputDigit('6') },
    { lbl: '−',  on: () => inputOp('-'),    cls: 'op accent' },
    { lbl: '1',  on: () => inputDigit('1') },
    { lbl: '2',  on: () => inputDigit('2') },
    { lbl: '3',  on: () => inputDigit('3') },
    { lbl: '+',  on: () => inputOp('+'),    cls: 'op accent' },
    { lbl: '±',  on: toggleSign,            cls: 'op' },
    { lbl: '0',  on: () => inputDigit('0') },
    { lbl: '.',  on: () => inputDigit('.') },
    { lbl: '=',  on: equals,                cls: 'eq' },
  ];

  return (
    <div className="calc-tool">
      <div className="calc-main">
        {/* Memory row */}
        <div className="calc-memory">
          <button className="calc-mem-btn" onClick={() => memOp('clear')} title="Memory clear">MC</button>
          <button className="calc-mem-btn" onClick={() => memOp('recall')} title="Memory recall">MR</button>
          <button className="calc-mem-btn" onClick={() => memOp('add')} title="Memory add">M+</button>
          <button className="calc-mem-btn" onClick={() => memOp('sub')} title="Memory subtract">M−</button>
          <div className={`calc-mem-ind ${memory !== 0 ? 'is-on' : ''}`}>
            <span>M</span>
            <em>{memory !== 0 ? fmt(memory) : '—'}</em>
          </div>
          <button className="calc-mem-btn percent" onClick={percent} title="Percent">%</button>
        </div>

        {/* Display */}
        <div className="calc-display">
          <div className="calc-expr">{expr}</div>
          <div className="calc-out">{display}</div>
        </div>

        {/* Keypad */}
        <div className="calc-keypad">
          {keys.map((k, i) => (
            <button
              key={i}
              className={`calc-key ${k.cls || ''}`}
              onClick={k.on}
              title={k.title}
            >
              {k.lbl}
            </button>
          ))}
        </div>
      </div>

      <aside className="calc-history">
        <div className="calc-history-head">
          <h3>History</h3>
          {history.length > 0 && (
            <button className="calc-history-clear" onClick={clearHistory} title="Clear history">
              <Icon name="delete_sweep" />
            </button>
          )}
        </div>
        {history.length === 0 ? (
          <div className="calc-history-empty">
            <Icon name="history" />
            <div>No calculations yet.</div>
            <div className="calc-hint">Press <kbd>Enter</kbd> after a calculation to save it here.</div>
          </div>
        ) : (
          <ul className="calc-history-list">
            {history.map((h, i) => (
              <li key={i}>
                <button className="calc-history-row" onClick={() => recall(h)} title="Recall result">
                  <span className="calc-history-expr">{h.expr.replace(/\*/g,'×').replace(/\//g,'÷').replace(/-/g,'−')}</span>
                  <span className="calc-history-result">= {h.result}</span>
                </button>
              </li>
            ))}
          </ul>
        )}
      </aside>
    </div>
  );
}

window.CalculatorTool = CalculatorTool;
