// ei-viz.jsx — shared TFHT-branded visualization components.
// All derive from window.EI. Exported to window at the end.
const { useState, useRef, useEffect, useLayoutEffect } = React;

const NF = new Intl.NumberFormat('he-IL');
const fmt = n => NF.format(n);

// ── color ramp: light rose → brand crimson → deep crimson ───────────────
function mix(a, b, t) {
  const p = (x, y) => Math.round(x + (y - x) * t);
  return `rgb(${p(a[0],b[0])},${p(a[1],b[1])},${p(a[2],b[2])})`;
}
function ramp(t) { // t in 0..1
  t = Math.max(0, Math.min(1, t));
  const rose = [248, 209, 217], crimson = [210, 0, 53], deep = [128, 0, 35];
  return t < 0.5 ? mix(rose, crimson, t / 0.5) : mix(crimson, deep, (t - 0.5) / 0.5);
}

// ── animated count-up ───────────────────────────────────────────────────
function useCountUp(value, { decimals = 0, dur = 750 } = {}) {
  const [v, setV] = useState(value);
  const from = useRef(value), raf = useRef(0);
  useEffect(() => {
    const reduce = window.matchMedia('(prefers-reduced-motion: reduce)').matches;
    if (reduce) { setV(value); from.current = value; return; }
    const start = performance.now(), a = from.current, b = value;
    const tick = now => {
      const t = Math.min(1, (now - start) / dur);
      const e = 1 - Math.pow(1 - t, 3);
      setV(a + (b - a) * e);
      if (t < 1) raf.current = requestAnimationFrame(tick);
      else from.current = b;
    };
    raf.current = requestAnimationFrame(tick);
    return () => cancelAnimationFrame(raf.current);
  }, [value, dur]);
  const factor = Math.pow(10, decimals);
  return Math.round(v * factor) / factor;
}
function CountUp({ value, decimals = 0, prefix = '', suffix = '' }) {
  const v = useCountUp(value, { decimals });
  return <span>{prefix}{NF.format(v)}{suffix}</span>;
}

// ── tooltip (portals to body so it never clips inside an artboard) ───────
function Tip({ label, children, block = false, style = {} }) {
  const ref = useRef(null);
  const [show, setShow] = useState(false);
  const [pos, setPos] = useState({ left: 0, top: 0 });
  const open = () => {
    const el = ref.current; if (!el) return;
    const r = el.getBoundingClientRect();
    setPos({ left: r.left + r.width / 2, top: r.top - 10 });
    setShow(true);
  };
  const Tag = block ? 'div' : 'span';
  return (
    <Tag ref={ref} tabIndex={0}
      onMouseEnter={open} onMouseLeave={() => setShow(false)}
      onFocus={open} onBlur={() => setShow(false)}
      style={{ cursor: 'help', outline: 'none', ...style }}>
      {children}
      {show && ReactDOM.createPortal(
        <div style={{
          position: 'fixed', left: pos.left, top: pos.top, transform: 'translate(-50%,-100%)',
          zIndex: 99999, maxWidth: 300, width: 'max-content', direction: 'rtl',
          background: '#1D1D1B', color: '#fff', padding: '11px 14px', borderRadius: 12,
          fontFamily: "'Assistant',sans-serif", fontSize: 14.5, fontWeight: 500, lineHeight: 1.5,
          boxShadow: '0 12px 36px rgba(29,29,27,.34)', pointerEvents: 'none', textAlign: 'right',
        }}>
          {label}
          <span style={{ position: 'absolute', left: '50%', top: '100%', transform: 'translateX(-50%)',
            width: 0, height: 0, borderLeft: '7px solid transparent', borderRight: '7px solid transparent',
            borderTop: '7px solid #1D1D1B' }} />
        </div>, document.body)}
    </Tag>
  );
}

// little dotted-underline marker for "hover me" affordance
function Hoverable({ children }) {
  return <span style={{ borderBottom: '2px dotted rgba(210,0,53,.5)', paddingBottom: 1 }}>{children}</span>;
}

// ── brand chain/handcuff motif (decorative, crimson) ─────────────────────
function ChainMark({ size = 40, color = '#C31B08' }) {
  return (
    <svg width={size} height={size * 0.62} viewBox="0 0 64 40" fill="none" aria-hidden="true">
      <circle cx="13" cy="11" r="7.5" stroke={color} strokeWidth="3.2" />
      <circle cx="13" cy="11" r="2.4" fill={color} />
      <path d="M19 15.5 q7 4 7 11 v9" stroke={color} strokeWidth="3.2" fill="none" strokeLinecap="round" />
      <g stroke={color} strokeWidth="2.4" fill="none">
        <ellipse cx="33" cy="22" rx="3.4" ry="5" />
        <ellipse cx="40" cy="28" rx="3.4" ry="5" />
        <ellipse cx="47" cy="34" rx="3.4" ry="5" />
      </g>
    </svg>
  );
}

// ── filter bar: year segmented control + month select + active district ──
function FilterBar({ filter, setFilter, accent = '#C31B08' }) {
  const monthSel = filter.month || 0;
  const seg = {
    border: 'none', background: 'transparent', cursor: 'pointer', font: "inherit",
    fontFamily: "'Assistant',sans-serif", fontWeight: 700, fontSize: 16, color: '#5B5B59',
    padding: '8px 18px', borderRadius: 999, transition: 'all .15s',
  };
  return (
    <div style={{ display: 'flex', flexWrap: 'wrap', alignItems: 'center', gap: 14, direction: 'rtl' }}>
      <span style={{ fontFamily: "'Assistant',sans-serif", fontWeight: 700, fontSize: 14, color: '#5B5B59' }}>שנה</span>
      <div style={{ display: 'flex', gap: 4, background: '#F6F6F5', padding: 4, borderRadius: 999, border: '1px solid #E4E4E2' }}>
        {EI.YEARS.map(y => {
          const on = filter.year === y;
          return (
            <button key={y} onClick={() => setFilter(f => ({ ...f, year: y }))}
              style={{ ...seg, background: on ? accent : 'transparent', color: on ? '#fff' : '#5B5B59',
                boxShadow: on ? '0 2px 8px rgba(195,27,8,.3)' : 'none' }}>{y}</button>
          );
        })}
      </div>
      <span style={{ fontFamily: "'Assistant',sans-serif", fontWeight: 700, fontSize: 14, color: '#5B5B59' }}>חודש</span>
      <div style={{ position: 'relative' }}>
        <select value={monthSel} onChange={e => setFilter(f => ({ ...f, month: +e.target.value }))}
          style={{ appearance: 'none', WebkitAppearance: 'none', fontFamily: "'Assistant',sans-serif",
            fontWeight: 700, fontSize: 16, color: '#1D1D1B', background: '#fff', border: '1px solid #E4E4E2',
            borderRadius: 999, padding: '9px 40px 9px 18px', cursor: 'pointer', direction: 'rtl' }}>
          <option value={0}>כל החודשים</option>
          {EI.MONTHS.map((m, i) => <option key={i} value={i + 1}>{m}</option>)}
        </select>
        <svg style={{ position: 'absolute', left: 16, top: '50%', transform: 'translateY(-50%)', pointerEvents: 'none' }}
          width="12" height="12" viewBox="0 0 12 12" fill="none" stroke="#9a9a98" strokeWidth="1.8" strokeLinecap="round"><path d="M2 4l4 4 4-4" /></svg>
      </div>
      {filter.district && (
        <button onClick={() => setFilter(f => ({ ...f, district: null }))}
          style={{ display: 'inline-flex', alignItems: 'center', gap: 8, border: 'none', cursor: 'pointer',
            background: '#fff', border: '1px solid', borderColor: accent, color: accent, borderRadius: 999,
            padding: '8px 14px', fontFamily: "'Assistant',sans-serif", fontWeight: 700, fontSize: 15 }}>
          {EI.districtName(filter.district)}
          <span style={{ fontSize: 16, lineHeight: 1 }}>✕</span>
        </button>
      )}
    </div>
  );
}

// ── KPI stat block ───────────────────────────────────────────────────────
// variant: 'plain' (white) | 'solid' (crimson bg, white text)
function Kpi({ value, decimals = 0, prefix = '', suffix = '', label, tip, variant = 'plain', accent = '#D20035', big = false }) {
  const solid = variant === 'solid';
  return (
    <Tip label={tip} block style={{ display: 'block', flex: 1, minWidth: 0 }}>
      <div style={{
        background: solid ? accent : '#fff', borderRadius: 18, padding: big ? '30px 26px' : '24px 22px',
        border: solid ? 'none' : '1px solid #ECECEA', boxShadow: solid ? '0 10px 28px rgba(210,0,53,.22)' : '0 1px 3px rgba(29,29,27,.06)',
        direction: 'rtl', textAlign: 'right', height: '100%', boxSizing: 'border-box', transition: 'transform .15s, box-shadow .15s',
        position: 'relative', overflow: 'hidden',
      }}
        onMouseEnter={e => { e.currentTarget.style.transform = 'translateY(-3px)'; e.currentTarget.style.boxShadow = solid ? '0 16px 36px rgba(210,0,53,.3)' : '0 8px 22px rgba(29,29,27,.1)'; }}
        onMouseLeave={e => { e.currentTarget.style.transform = ''; e.currentTarget.style.boxShadow = solid ? '0 10px 28px rgba(210,0,53,.22)' : '0 1px 3px rgba(29,29,27,.06)'; }}>
        <div style={{ fontFamily: "'Assistant',sans-serif", fontWeight: 800, lineHeight: 1,
          fontSize: big ? 64 : 48, letterSpacing: '-0.02em', color: solid ? '#fff' : accent, fontVariantNumeric: 'tabular-nums' }}>
          <CountUp value={value} decimals={decimals} prefix={prefix} suffix={suffix} />
        </div>
        <div style={{ fontFamily: "'Assistant',sans-serif", fontWeight: 600, fontSize: 15.5, lineHeight: 1.35,
          color: solid ? 'rgba(255,255,255,.92)' : '#333', marginTop: 12 }}>
          <Hoverable>{label}</Hoverable>
        </div>
      </div>
    </Tip>
  );
}

// ── horizontal bar chart by district (click to filter) ───────────────────
function BarChart({ rows, metric = 'closures', filter, setFilter, suffix = '' }) {
  const max = Math.max(1, ...rows.map(r => r[metric]));
  return (
    <div style={{ direction: 'rtl', display: 'flex', flexDirection: 'column', gap: 10 }}>
      {rows.map(r => {
        const v = r[metric];
        const sel = filter.district === r.key;
        const dim = filter.district && !sel;
        const w = (v / max) * 100;
        return (
          <Tip key={r.key} block label={`${r.name}: ${fmt(v)}${suffix} · לחצו לסינון לפי מחוז זה`}>
            <div onClick={() => setFilter(f => ({ ...f, district: sel ? null : r.key }))}
              style={{ display: 'grid', gridTemplateColumns: '74px 1fr', alignItems: 'center', gap: 12,
                cursor: 'pointer', opacity: dim ? 0.4 : 1, transition: 'opacity .15s' }}>
              <div style={{ fontFamily: "'Assistant',sans-serif", fontWeight: sel ? 800 : 600, fontSize: 15,
                color: sel ? '#D20035' : '#333', textAlign: 'left' }}>{r.name}</div>
              <div style={{ position: 'relative', height: 30, background: '#F4F2F1', borderRadius: 8 }}>
                <div style={{ width: `${w}%`, height: '100%', borderRadius: 8, minWidth: v ? 30 : 0,
                  background: ramp(v / max), transition: 'width .5s cubic-bezier(.2,.7,.3,1)',
                  boxShadow: sel ? '0 0 0 2.5px #1D1D1B' : 'none', display: 'flex', alignItems: 'center',
                  justifyContent: 'flex-start', paddingRight: 10, boxSizing: 'border-box' }}>
                  {v > 0 && <span style={{ fontFamily: "'Assistant',sans-serif", fontWeight: 800, fontSize: 14,
                    color: v / max > 0.28 ? '#fff' : '#7a0020' }}>{fmt(v)}</span>}
                </div>
                {v === 0 && <span style={{ position: 'absolute', right: 10, top: '50%', transform: 'translateY(-50%)',
                  fontFamily: "'Assistant',sans-serif", fontWeight: 700, fontSize: 13, color: '#bdbdbb' }}>0</span>}
              </div>
            </div>
          </Tip>
        );
      })}
    </div>
  );
}

// ── stylized Israel map with clickable district markers ──────────────────
const ISRAEL_PATH = 'M62 6 L70 20 L71 44 L62 58 L69 66 L66 96 L64 120 L58 150 L52 188 L47 150 L41 120 L33 86 L30 72 L27 58 L33 46 L40 34 L44 28 L50 20 L55 10 Z';
function IsraelMap({ rows, metric = 'closures', filter, setFilter, height = 360 }) {
  const max = Math.max(1, ...rows.map(r => r[metric]));
  const [tip, setTip] = useState(null); // {label,left,top}
  const at = (e, label) => setTip({ label, left: e.clientX, top: e.clientY - 16 });
  const unit = metric === 'closures' ? 'סגירות' : 'קנסות';
  return (
    <div style={{ position: 'relative', width: '100%' }}>
      <svg viewBox="0 0 100 200" height={height} style={{ width: '100%', overflow: 'visible', direction: 'ltr', display: 'block' }}>
        <path d={ISRAEL_PATH} fill="#EFEDEB" stroke="#D9D7D4" strokeWidth="1.1" />
        {rows.map(r => {
          const v = r[metric];
          const sel = filter.district === r.key;
          const dim = filter.district && !sel;
          const rad = 4.5 + (v / max) * 11;
          const cy = r.y * 1.9;
          const label = `${r.name}: ${fmt(v)} ${unit} · לחצו לסינון`;
          return (
            <g key={r.key} style={{ cursor: 'pointer', opacity: dim ? 0.35 : 1, transition: 'opacity .15s' }}
              onMouseEnter={e => at(e, label)} onMouseMove={e => at(e, label)} onMouseLeave={() => setTip(null)}
              onClick={() => setFilter(f => ({ ...f, district: sel ? null : r.key }))}>
              <circle cx={r.x} cy={cy} r={rad} fill={v ? ramp(v / max) : '#E4E4E2'}
                stroke={sel ? '#1D1D1B' : '#fff'} strokeWidth={sel ? 2 : 1.2} />
              {v > 0 && <text x={r.x} y={cy} textAnchor="middle" dominantBaseline="central"
                style={{ fontFamily: "'Assistant',sans-serif", fontWeight: 800, fontSize: Math.max(6, rad * 0.8),
                  fill: v / max > 0.3 ? '#fff' : '#7a0020', pointerEvents: 'none' }}>{v}</text>}
              <text x={r.x} y={cy + rad + 8} textAnchor="middle"
                style={{ fontFamily: "'Assistant',sans-serif", fontWeight: sel ? 800 : 600, fontSize: 7.5,
                  fill: sel ? '#D20035' : '#5B5B59', direction: 'rtl', pointerEvents: 'none' }}>{r.name}</text>
            </g>
          );
        })}
      </svg>
      {tip && ReactDOM.createPortal(
        <div style={{ position: 'fixed', left: tip.left, top: tip.top, transform: 'translate(-50%,-100%)', zIndex: 99999,
          direction: 'rtl', background: '#1D1D1B', color: '#fff', padding: '9px 13px', borderRadius: 11,
          fontFamily: "'Assistant',sans-serif", fontSize: 14, fontWeight: 600, lineHeight: 1.4, whiteSpace: 'nowrap',
          boxShadow: '0 12px 36px rgba(29,29,27,.34)', pointerEvents: 'none' }}>{tip.label}</div>, document.body)}
    </div>
  );
}

// ── enforcement-rate gauge (semicircle): shows how empty enforcement is ──
function Gauge({ rate, size = 280 }) {
  // rate is a tiny % (e.g. 0.01). Map to needle on a 0..0.05% arc so motion is visible.
  const cap = 0.05;
  const t = Math.max(0, Math.min(1, rate / cap));
  const ang = -90 + t * 180; // -90 (left/empty) .. +90 (right)
  const animT = useCountUp(t, { decimals: 4, dur: 900 });
  const a = (animT * 180 - 90) * Math.PI / 180;
  const cx = size / 2, cy = size / 2, R = size / 2 - 18, nLen = R - 14;
  const arc = (a0, a1, color, w) => {
    const p = ang => [cx + R * Math.cos((ang - 90) * Math.PI / 180), cy + R * Math.sin((ang - 90) * Math.PI / 180)];
    const [x0, y0] = p(a0), [x1, y1] = p(a1);
    const large = (a1 - a0) > 180 ? 1 : 0;
    return <path d={`M${x0} ${y0} A${R} ${R} 0 ${large} 1 ${x1} ${y1}`} stroke={color} strokeWidth={w} fill="none" strokeLinecap="round" />;
  };
  const nx = cx + nLen * Math.cos(a), ny = cy + nLen * Math.sin(a);
  return (
    <svg viewBox={`0 0 ${size} ${size / 2 + 24}`} style={{ width: '100%', maxWidth: size }}>
      {/* track from 0deg(=-90) to 180deg(=90) along the top semicircle */}
      {arc(0, 60, '#8E0024', 16)}
      {arc(60, 120, '#D20035', 16)}
      {arc(120, 180, '#F3B6C2', 16)}
      <circle cx={cx} cy={cy} r="9" fill="#1D1D1B" />
      <line x1={cx} y1={cy} x2={nx} y2={ny} stroke="#1D1D1B" strokeWidth="5" strokeLinecap="round" />
      <text x={18} y={cy + 14} style={{ fontFamily: "'Assistant',sans-serif", fontWeight: 700, fontSize: 12, fill: '#8E0024' }}>אכיפה</text>
      <text x={size - 18} y={cy + 14} textAnchor="end" style={{ fontFamily: "'Assistant',sans-serif", fontWeight: 700, fontSize: 12, fill: '#c98' }}>אפס</text>
    </svg>
  );
}

// ── closure-duration timeline (30/60/90/120) with house glyphs ───────────
function House({ size = 13, color = '#C31B08' }) {
  return (
    <svg width={size} height={size} viewBox="0 0 16 16" fill="none" aria-hidden="true">
      <path d="M8 1.5 L14.5 6.5 V14.5 H1.5 V6.5 Z" stroke={color} strokeWidth="1.4" fill="none" />
    </svg>
  );
}
function DurationTimeline({ buckets, accent = '#C31B08' }) {
  const total = buckets.reduce((s, b) => s + b.count, 0) || 1;
  return (
    <div style={{ direction: 'rtl' }}>
      <div style={{ position: 'relative', display: 'flex', justifyContent: 'space-between',
        padding: '0 20px', marginBottom: 8 }}>
        <div style={{ position: 'absolute', top: 26, right: 36, left: 36, height: 5, background: accent, borderRadius: 3 }} />
        {buckets.map(b => (
          <Tip key={b.days} label={`${b.count} מתוך ${total} צווי סגירה ניתנו ל-${b.days} יום`} block
            style={{ position: 'relative', zIndex: 1, textAlign: 'center', flex: 1 }}>
            <div style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', cursor: 'help' }}>
              <div style={{ fontFamily: "'Assistant',sans-serif", fontWeight: 800, fontSize: 17, color: '#1D1D1B', marginBottom: 8 }}>{b.days} <span style={{ fontSize: 12, fontWeight: 700, color: '#5B5B59' }}>יום</span></div>
              <div style={{ width: 26, height: 26, borderRadius: '50%', background: '#fff', border: `4px solid ${accent}` }} />
              <div style={{ fontFamily: "'Assistant',sans-serif", fontWeight: 800, fontSize: 22, color: accent, marginTop: 10 }}>{b.count}</div>
              <div style={{ display: 'flex', flexWrap: 'wrap', justifyContent: 'center', gap: 3, maxWidth: 76, marginTop: 6 }}>
                {Array.from({ length: b.count }).map((_, i) => <House key={i} />)}
              </div>
            </div>
          </Tip>
        ))}
      </div>
    </div>
  );
}

// ── section heading ───────────────────────────────────────────────────────
function SectionTitle({ children, sub }) {
  return (
    <div style={{ direction: 'rtl', marginBottom: 18 }}>
      <h3 style={{ margin: 0, fontFamily: "'Assistant',sans-serif", fontWeight: 800, fontSize: 23, color: '#1D1D1B', letterSpacing: '-0.01em' }}>{children}</h3>
      {sub && <p style={{ margin: '4px 0 0', fontFamily: "'Assistant',sans-serif", fontSize: 14.5, color: '#5B5B59', lineHeight: 1.4 }}>{sub}</p>}
    </div>
  );
}

// ── source footnote ───────────────────────────────────────────────────────
function SourceNote({ compact = false }) {
  return (
    <div style={{ direction: 'rtl', fontFamily: "'Assistant',sans-serif", fontSize: compact ? 12 : 13,
      color: '#9a9a98', lineHeight: 1.5, borderTop: '1px solid #ECECEA', paddingTop: 14 }}>
      {EI.meta.sourceNote} <span style={{ color: '#bdbdbb' }}>· {EI.meta.updated}</span>
    </div>
  );
}

Object.assign(window, {
  CountUp, Tip, Hoverable, ChainMark, FilterBar, Kpi, BarChart, IsraelMap, Gauge,
  DurationTimeline, SectionTitle, SourceNote, eiRamp: ramp, eiFmt: fmt,
});
