const MizoCtx = React.createContext(null);
const SectionCtx = React.createContext(false);
const useMizo = () => React.useContext(MizoCtx);

function makeFmt(lang, cur) {
  const loc = lang === 'fr' ? 'fr-CA' : 'en-CA', cu = cur || 'CAD';
  const c2 = new Intl.NumberFormat(loc, { style: 'currency', currency: cu });
  const c0 = new Intl.NumberFormat(loc, { style: 'currency', currency: cu, maximumFractionDigits: 0 });
  const n = new Intl.NumberFormat(loc, { maximumFractionDigits: 2 });
  const n1 = new Intl.NumberFormat(loc, { minimumFractionDigits: 1, maximumFractionDigits: 1 });
  return {
    money: (v) => c2.format(v),
    money0: (v) => c0.format(v),
    kmoney: (v) => (Math.abs(v) >= 1000 ? (lang === 'fr' ? n1.format(v / 1000) + ' k$' : '$' + n1.format(v / 1000) + 'k') : c0.format(v)),
    num: (v) => n.format(v),
    pct: (v) => n1.format(v) + (lang === 'fr' ? ' %' : '%'),
    date: (d, o) => new Date(d + 'T12:00').toLocaleDateString(loc, o || { month: 'short', day: 'numeric' }),
  };
}

function recipeCost(r, invMap) {
  const lines = r.lines.map((l) => { const ing = invMap[l.ing]; return { ...l, ingObj: ing, cost: ing ? ing.cost * l.qty : 0 }; });
  const ingredients = lines.reduce((s, l) => s + l.cost, 0);
  const total = ingredients + (r.pack || 0);
  const fc = r.price > 0 ? (total / r.price) * 100 : 0;
  return { lines, total, fc, margin: r.price - total, monthly: (r.price - total) * r.sold };
}
const fcTone = (fc, target) => (fc <= target ? 'pos' : fc <= target + 3 ? 'warn' : 'neg');
const stockState = (i) => { const r = i.onHand / i.par; return r < 0.5 ? 'low' : r < 0.85 ? 'reorder' : 'ok'; };

function Icon({ n, s, style, className }) {
  return <i className={'ph ph-' + n + (className ? ' ' + className : '')} style={{ fontSize: s, ...style }} aria-hidden="true"></i>;
}

function Delta({ v, invert, suffix }) {
  const { fmt } = useMizo();
  const good = invert ? v < 0 : v > 0;
  return (
    <span className={'delta ' + (v === 0 ? 'flat' : good ? 'pos' : 'neg')}>
      <Icon n={v > 0 ? 'arrow-up-right' : v < 0 ? 'arrow-down-right' : 'minus'} />
      {fmt.pct(Math.abs(v))}{suffix ? <span className="delta-suffix">{suffix}</span> : null}
    </span>
  );
}

function Pill({ tone, children }) {
  return <span className={'pill pill-' + tone}>{children}</span>;
}

function Seg({ value, options, onChange, size }) {
  return (
    <div className={'mseg' + (size === 'sm' ? ' mseg-sm' : '')} role="tablist">
      {options.map(([v, label]) => (
        <button key={v} role="tab" aria-selected={value === v} className={'mseg-opt' + (value === v ? ' on' : '')} onClick={() => onChange(v)}>{label}</button>
      ))}
    </div>
  );
}

function BarChart({ data, la, lb, fmtv, height = 240, highlightLast }) {
  const [hover, setHover] = React.useState(null);
  const max = Math.max(...data.map((d) => Math.max(d.a, d.b || 0))) * 1.08;
  const ticks = [0, 0.25, 0.5, 0.75, 1].map((f) => max * f);
  return (
    <div className="bars" style={{ '--h': height + 'px' }}>
      <div className="bars-grid">
        {ticks.slice().reverse().map((t, i) => <div key={i} className="bars-tick"><span>{fmtv(t)}</span></div>)}
      </div>
      <div className="bars-cols">
        {data.map((d, i) => (
          <div key={i} className={'bars-col' + (hover === i ? ' hov' : '') + (highlightLast && i === data.length - 1 ? ' last' : '')} onMouseEnter={() => setHover(i)} onMouseLeave={() => setHover(null)}>
            <div className="bars-pair">
              <div className="bar bar-a" style={{ height: (d.a / max) * 100 + '%' }}></div>
              {d.b != null ? <div className="bar bar-b" style={{ height: (d.b / max) * 100 + '%' }}></div> : null}
            </div>
            <div className="bars-label">{d.label}</div>
            {hover === i ? (
              <div className="bars-tip">
                <div className="bars-tip-t">{d.label}</div>
                <div><i className="dot dot-a"></i>{la} <b>{fmtv(d.a, true)}</b></div>
                {d.b != null ? <div><i className="dot dot-b"></i>{lb} <b>{fmtv(d.b, true)}</b></div> : null}
                {d.b != null ? <div className="bars-tip-net">= <b>{fmtv(d.a - d.b, true)}</b></div> : null}
              </div>
            ) : null}
          </div>
        ))}
      </div>
    </div>
  );
}

function HBars({ items, fmtv, tone }) {
  const max = Math.max(...items.map((i) => i.v));
  return (
    <div className="hbars">
      {items.map((it, i) => (
        <div key={i} className="hbar-row">
          <div className="hbar-top"><span className="hbar-label">{it.label}</span><span className="hbar-val">{fmtv(it.v)}</span></div>
          <div className="hbar-track"><div className={'hbar-fill' + (tone ? ' ' + tone : '') + (i === 0 ? ' first' : '')} style={{ width: (it.v / max) * 100 + '%' }}></div></div>
          {it.sub ? <div className="hbar-sub">{it.sub}</div> : null}
        </div>
      ))}
    </div>
  );
}

function Level({ value, par }) {
  const r = Math.min(value / par, 1.3);
  const st = value / par < 0.5 ? 'neg' : value / par < 0.85 ? 'warn' : 'pos';
  return <div className="level"><div className={'level-fill ' + st} style={{ width: Math.min(r / 1.3, 1) * 100 + '%' }}></div><div className="level-par"></div></div>;
}

function Drawer({ open, onClose, children }) {
  React.useEffect(() => {
    const k = (e) => e.key === 'Escape' && onClose();
    if (open) window.addEventListener('keydown', k);
    return () => window.removeEventListener('keydown', k);
  }, [open]);
  return ReactDOM.createPortal(
    <div className={'drawer-wrap' + (open ? ' open' : '')} aria-hidden={!open}>
      <div className="drawer-scrim" onClick={onClose}></div>
      <aside className="drawer">{open ? children : null}</aside>
    </div>, document.body
  );
}

function Modal({ open, onClose, title, children, actions, wide }) {
  const box = React.useRef(null), tid = React.useRef('mdl-' + Math.random().toString(36).slice(2, 8));
  React.useEffect(() => {
    if (!open) return;
    const prev = document.activeElement;
    const k = (e) => { if (e.key === 'Escape') onClose(); if (e.key === 'Tab' && box.current) { const f = [...box.current.querySelectorAll('button,input,select,textarea,[tabindex]:not([tabindex="-1"])')].filter((x) => !x.disabled); if (!f.length) return; if (e.shiftKey && document.activeElement === f[0]) { e.preventDefault(); f[f.length - 1].focus(); } else if (!e.shiftKey && document.activeElement === f[f.length - 1]) { e.preventDefault(); f[0].focus(); } } };
    window.addEventListener('keydown', k);
    setTimeout(() => { if (box.current) { const first = box.current.querySelector('.mdl-body input,.mdl-body select,.mdl-body textarea') || box.current.querySelector('.dialog-actions .btn-primary'); if (first) first.focus(); } }, 30);
    return () => { window.removeEventListener('keydown', k); if (prev && prev.focus) prev.focus(); };
  }, [open]);
  if (!open) return null;
  return ReactDOM.createPortal(
    <div className="dialog-backdrop mdl-backdrop" onMouseDown={(e) => e.target === e.currentTarget && onClose()}>
      <div ref={box} className={'dialog mdl' + (wide ? ' mdl-wide' : '')} role="dialog" aria-modal="true" aria-labelledby={tid.current}>
        <div className="mdl-head">
          <div className="dialog-title" id={tid.current}>{title}</div>
          <button className="btn btn-icon btn-secondary" onClick={onClose} aria-label="Close" title="Esc"><Icon n="x" s="1.1rem" /></button>
        </div>
        <div className="mdl-body">{children}</div>
        {actions ? <div className="dialog-actions">{actions}</div> : null}
      </div>
    </div>, document.body
  );
}

function PageHead({ title, sub, children }) {
  const inSec = React.useContext(SectionCtx);
  if (inSec) return sub || children ? <header className="page-head page-head-sec">{sub ? <p className="page-sub">{sub}</p> : <span></span>}{children ? <div className="page-head-actions">{children}</div> : null}</header> : null;
  return (
    <header className="page-head">
      <div className="page-head-text"><h1>{title}</h1>{sub ? <p className="page-sub">{sub}</p> : null}</div>
      {children ? <div className="page-head-actions">{children}</div> : null}
    </header>
  );
}

function Stat({ label, value, children, tone }) {
  return (
    <div className="stat">
      <div className="stat-label">{label}</div>
      <div className={'stat-value' + (tone ? ' ' + tone : '')}>{value}</div>
      {children ? <div className="stat-foot">{children}</div> : null}
    </div>
  );
}

function Toggle({ on, onChange, label }) {
  return <button type="button" role="switch" aria-checked={!!on} aria-label={label} className={'switch' + (on ? ' on' : '')} onClick={() => onChange(!on)}><span></span></button>;
}

const Meander = () => <div className="meander" aria-hidden="true"></div>;

Object.assign(window, { MizoCtx, SectionCtx, Toggle, useMizo, makeFmt, recipeCost, fcTone, stockState, Icon, Delta, Pill, Seg, BarChart, HBars, Level, Drawer, Modal, PageHead, Stat, Meander });
