/* ============================================================
   Omnitok Analytics — icons + chart primitives  → window
   ============================================================ */
const { useState, useRef, useEffect, useMemo } = React;

/* ---------------- Icons (stroke, 24x24) ---------------- */
const _i = (paths, fill) => (p) => React.createElement('svg', {
  viewBox:'0 0 24 24', fill: fill?'currentColor':'none',
  stroke: fill?'none':'currentColor', strokeWidth:2, strokeLinecap:'round', strokeLinejoin:'round',
  ...p
}, paths.map((d,i)=> React.createElement('path',{key:i,d})));

const Icon = {
  grid:_i(['M3 3h7v7H3zM14 3h7v7h-7zM14 14h7v7h-7zM3 14h7v7H3z']),
  box:_i(['M21 16V8a2 2 0 0 0-1-1.7l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.7l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16z','M3.3 7 12 12l8.7-5','M12 22V12']),
  store:_i(['M3 9l1-5h16l1 5','M4 9v11h16V9','M9 20v-6h6v6','M3 9h18']),
  globe:_i(['M12 22a10 10 0 1 0 0-20 10 10 0 0 0 0 20z','M2 12h20','M12 2a15 15 0 0 1 0 20 15 15 0 0 1 0-20z']),
  device:_i(['M4 4h16v12H4z','M2 20h20','M9 16h6']),
  layers:_i(['M12 2 2 7l10 5 10-5-10-5z','M2 17l10 5 10-5','M2 12l10 5 10-5']),
  clock:_i(['M12 22a10 10 0 1 0 0-20 10 10 0 0 0 0 20z','M12 6v6l4 2']),
  users:_i(['M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2','M9 11a4 4 0 1 0 0-8 4 4 0 0 0 0 8','M22 21v-2a4 4 0 0 0-3-3.9','M16 3.1A4 4 0 0 1 16 11']),
  eye:_i(['M2 12s3.5-7 10-7 10 7 10 7-3.5 7-10 7-10-7-10-7z','M12 15a3 3 0 1 0 0-6 3 3 0 0 0 0 6z']),
  download:_i(['M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4','M7 10l5 5 5-5','M12 15V3']),
  chevDown:_i(['M6 9l6 6 6-6']),
  chevRight:_i(['M9 18l6-6-6-6']),
  arrowUp:_i(['M12 19V5','M5 12l7-7 7 7']),
  arrowDown:_i(['M12 5v14','M5 12l7 7 7-7']),
  search:_i(['M11 19a8 8 0 1 0 0-16 8 8 0 0 0 0 16z','M21 21l-4.3-4.3']),
  x:_i(['M18 6 6 18','M6 6l12 12']),
  filter:_i(['M22 3H2l8 9.5V19l4 2v-8.5L22 3z']),
  calendar:_i(['M3 4h18v18H3z','M16 2v4','M8 2v4','M3 10h18']),
  csv:_i(['M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z','M14 2v6h6']),
  pdf:_i(['M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z','M14 2v6h6','M9 13h6','M9 17h6']),
  image:_i(['M3 3h18v18H3z','M8.5 11a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3z','M21 15l-5-5L5 21']),
  trend:_i(['M3 17l6-6 4 4 8-8','M17 7h4v4']),
  spark:_i(['M5 3l1.5 4.5L11 9l-4.5 1.5L5 15l-1.5-4.5L-1 9l4.5-1.5z'],true),
  info:_i(['M12 22a10 10 0 1 0 0-20 10 10 0 0 0 0 20z','M12 16v-4','M12 8h.01']),
  swap:_i(['M7 10H3l4-4','M3 10l4 4','M17 14h4l-4 4','M21 14l-4-4','M3 10h14','M21 14H7']),
  star:_i(['M12 2l3 6.3 6.9 1-5 4.9 1.2 6.8L12 17.8 5.9 21l1.2-6.8-5-4.9 6.9-1z'],true),
  monitor:_i(['M3 4h18v12H3z','M8 20h8','M12 16v4']),
  smartphone:_i(['M7 2h10v20H7z','M11 18h2']),
  pin:_i(['M12 22s8-7 8-12a8 8 0 1 0-16 0c0 5 8 12 8 12z','M12 12a2.5 2.5 0 1 0 0-5 2.5 2.5 0 0 0 0 5z'],false),
  bolt:_i(['M13 2 3 14h7l-1 8 10-12h-7l1-8z'],true),
  external:_i(['M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6','M15 3h6v6','M10 14 21 3']),
  sliders:_i(['M4 21v-7','M4 10V3','M12 21v-9','M12 8V3','M20 21v-5','M20 12V3','M1 14h6','M9 8h6','M17 16h6']),
  check:_i(['M20 6 9 17l-5-5']),
  database:_i(['M12 8c4.4 0 8-1.3 8-3s-3.6-3-8-3-8 1.3-8 3 3.6 3 8 3z','M4 5v6c0 1.7 3.6 3 8 3s8-1.3 8-3V5','M4 11v6c0 1.7 3.6 3 8 3s8-1.3 8-3v-6']),
  help:_i(['M12 22a10 10 0 1 0 0-20 10 10 0 0 0 0 20z','M9.1 9a3 3 0 0 1 5.8 1c0 2-3 3-3 3','M12 17h.01']),
  bell:_i(['M18 8a6 6 0 0 0-12 0c0 7-3 9-3 9h18s-3-2-3-9','M13.7 21a2 2 0 0 1-3.4 0']),
};
window.Icon = Icon;

/* ---------------- shared tooltip ---------------- */
function useTip(){
  const [tip,setTip]=useState(null);
  const node = tip ? React.createElement('div',{className:'cht-tip',style:{left:tip.x+12,top:tip.y+12,opacity:1}},
    tip.title&&React.createElement('div',{className:'tt-t',key:'t'},tip.title),
    (tip.rows||[]).map((r,i)=>React.createElement('div',{className:'tt-r',key:i},
      r.color&&React.createElement('span',{className:'d',style:{background:r.color}}), r.label))
  ) : null;
  return {tip,setTip,node};
}
window.useTip = useTip;

/* ---------------- Area + line trend chart ---------------- */
function TrendChart({data, height=220, color='#4D4A9D', color2='#FF177B', series2=null, labelFor}){
  const ref=useRef(null); const [w,setW]=useState(640);
  const {setTip,node}=useTip();
  useEffect(()=>{ const ro=new ResizeObserver(es=>{ for(const e of es) setW(e.contentRect.width); }); if(ref.current) ro.observe(ref.current); return ()=>ro.disconnect(); },[]);
  const pad={l:38,r:14,t:14,b:26};
  const iw=Math.max(40,w-pad.l-pad.r), ih=height-pad.t-pad.b;
  const max=Math.max(1,...data.map(d=>d.v), ...(series2?series2.map(d=>d.v):[0]));
  const nice=niceMax(max);
  const X=i=> pad.l + (data.length<=1?iw/2: i/(data.length-1)*iw);
  const Y=v=> pad.t + ih - (v/nice)*ih;
  const path=(arr)=> arr.map((d,i)=> (i?'L':'M')+X(i).toFixed(1)+' '+Y(d.v).toFixed(1)).join(' ');
  const area=(arr)=> path(arr)+` L${X(arr.length-1).toFixed(1)} ${(pad.t+ih).toFixed(1)} L${X(0).toFixed(1)} ${(pad.t+ih).toFixed(1)} Z`;
  const ticks=4; const yt=Array.from({length:ticks+1},(_,i)=> nice*i/ticks);
  const gid='ga'+Math.round(Math.random()*1e6);
  const step=Math.ceil(data.length/8);
  return React.createElement('div',{ref,style:{width:'100%',position:'relative'}},
    React.createElement('svg',{width:w,height,style:{display:'block',overflow:'visible'},
      onMouseLeave:()=>setTip(null),
      onMouseMove:(ev)=>{ const rect=ev.currentTarget.getBoundingClientRect(); const mx=ev.clientX-rect.left;
        let i=Math.round((mx-pad.l)/iw*(data.length-1)); i=Math.max(0,Math.min(data.length-1,i));
        const rows=[{color, label:(labelFor?labelFor(0):'')+OA.fmt(data[i].v)+' '+OA.t('contentEvents')}];
        if(series2) rows.push({color:color2,label:OA.fmt(series2[i].v)+' '+(labelFor?labelFor(1):'')});
        setTip({x:ev.clientX,y:ev.clientY,title:OA.fmtDateFull(data[i].ts),rows});
      }
    },
      React.createElement('defs',null,
        React.createElement('linearGradient',{id:gid,x1:0,y1:0,x2:0,y2:1},
          React.createElement('stop',{offset:'0%',stopColor:color,stopOpacity:.28}),
          React.createElement('stop',{offset:'100%',stopColor:color,stopOpacity:0}))),
      yt.map((v,i)=>React.createElement('g',{key:i},
        React.createElement('line',{x1:pad.l,x2:w-pad.r,y1:Y(v),y2:Y(v),stroke:'#E5E5E5',strokeWidth:1,strokeDasharray:i?'3 4':'0'}),
        React.createElement('text',{x:pad.l-8,y:Y(v)+4,textAnchor:'end',fontSize:10.5,fontWeight:700,fill:'#A3A3A3'},OA.fmtCompact(v)))),
      React.createElement('path',{d:area(data),fill:`url(#${gid})`}),
      series2&&React.createElement('path',{d:path(series2),fill:'none',stroke:color2,strokeWidth:2,strokeDasharray:'5 4',opacity:.8}),
      React.createElement('path',{d:path(data),fill:'none',stroke:color,strokeWidth:2.5}),
      data.map((d,i)=> i%step===0||i===data.length-1 ? React.createElement('text',{key:i,x:X(i),y:height-7,textAnchor:'middle',fontSize:10,fontWeight:700,fill:'#A3A3A3'},OA.fmtDate(d.ts)):null)
    ), node);
}
window.TrendChart=TrendChart;

/* ---------------- Horizontal ranking bars ---------------- */
function RankBars({items, total, color='#4D4A9D', max=8, onClick, fmtLabel, colorByIndex, money}){
  const top=items.slice(0,max);
  const mx=Math.max(1,...top.map(d=>d.v));
  const tot=total||items.reduce((s,d)=>s+d.v,0);
  return React.createElement('div',{className:'rank-list'},
    top.map((d,i)=> React.createElement('div',{key:d.k,className:'rank-row',onClick:onClick?()=>onClick(d):undefined},
      React.createElement('div',{className:'lbl'},
        React.createElement('span',{className:'rank '+(i<3?'top':''),style:{flexShrink:0}}, i+1),
        React.createElement('span',{className:'nm',title:fmtLabel?fmtLabel(d.k):d.k}, fmtLabel?fmtLabel(d.k):d.k)),
      React.createElement('div',{className:'bar'},
        React.createElement('div',{className:'f',style:{width:(d.v/mx*100)+'%',background:colorByIndex?OA.PALETTE[i%OA.PALETTE.length]:color}})),
      React.createElement('div',{className:'val'}, OA.fmt(d.v)),
      React.createElement('div',{className:'pct'}, OA.pct(d.v/tot*100,0))
    )));
}
window.RankBars=RankBars;

/* ---------------- Donut ---------------- */
function Donut({data, size=180, thickness=26, centerLabel, centerValue, onClick}){
  const {setTip,node}=useTip();
  const tot=data.reduce((s,d)=>s+d.v,0)||1;
  const r=(size-thickness)/2, cx=size/2, cy=size/2; let a=-Math.PI/2;
  const segs=data.map((d,i)=>{ const frac=d.v/tot; const a2=a+frac*Math.PI*2;
    const large=frac>0.5?1:0;
    const x1=cx+r*Math.cos(a), y1=cy+r*Math.sin(a), x2=cx+r*Math.cos(a2), y2=cy+r*Math.sin(a2);
    const path=`M ${x1} ${y1} A ${r} ${r} 0 ${large} 1 ${x2} ${y2}`;
    const mid=(a+a2)/2; a=a2;
    return {path,color:d.color||OA.PALETTE[i%OA.PALETTE.length],d,frac,mid};
  });
  return React.createElement('div',{style:{position:'relative',width:size,height:size,flexShrink:0}},
    React.createElement('svg',{width:size,height:size,onMouseLeave:()=>setTip(null)},
      segs.map((s,i)=>React.createElement('path',{key:i,d:s.path,fill:'none',stroke:s.color,strokeWidth:thickness,
        strokeLinecap:'butt',style:{cursor:onClick?'pointer':'default',transition:'opacity .1s'},
        onMouseMove:(ev)=>setTip({x:ev.clientX,y:ev.clientY,title:s.d.k,rows:[{color:s.color,label:OA.fmt(s.d.v)+' · '+OA.pct(s.frac*100)}]}),
        onClick:onClick?()=>onClick(s.d):undefined}))),
    React.createElement('div',{style:{position:'absolute',inset:0,display:'flex',flexDirection:'column',alignItems:'center',justifyContent:'center',pointerEvents:'none'}},
      React.createElement('div',{style:{fontSize:24,fontWeight:800,color:'#262626',letterSpacing:'-.02em'}}, centerValue),
      React.createElement('div',{style:{fontSize:11,fontWeight:700,color:'#737373'}}, centerLabel)),
    node);
}
window.Donut=Donut;

/* ---------------- Legend ---------------- */
function Legend({items, onToggle, off}){
  return React.createElement('div',{className:'legend'},
    items.map((it,i)=>React.createElement('div',{key:it.k,className:'li'+(off&&off[it.k]?' off':''),onClick:onToggle?()=>onToggle(it.k):undefined},
      React.createElement('span',{className:'d',style:{background:it.color||OA.PALETTE[i%OA.PALETTE.length]}}),
      it.k, it.v!=null&&React.createElement('b',{style:{color:'#262626',marginLeft:2}}, OA.fmt(it.v)))));
}
window.Legend=Legend;

/* ---------------- Heatmap hour×weekday ---------------- */
function Heatmap({matrix, max, rowLabels, onCell}){
  const {setTip,node}=useTip();
  const cols=24;
  const color=v=>{ if(!v) return '#F1F0F8'; const t=Math.pow(v/max,0.6);
    // interpolate primary-light -> accent
    const lerp=(a,b)=>Math.round(a+(b-a)*t);
    const c1=[214,212,238], c2=[255,23,123];
    return `rgb(${lerp(c1[0],c2[0])},${lerp(c1[1],c2[1])},${lerp(c1[2],c2[2])})`;
  };
  return React.createElement('div',null,
    React.createElement('div',{style:{display:'grid',gridTemplateColumns:`34px repeat(${cols},1fr)`,gap:3}},
      React.createElement('div'),
      Array.from({length:cols},(_,h)=>React.createElement('div',{key:h,style:{fontSize:9,fontWeight:700,color:'#A3A3A3',textAlign:'center'}}, h%3===0?h:'')),
      matrix.map((row,ri)=>React.createElement(React.Fragment,{key:ri},
        React.createElement('div',{style:{fontSize:10.5,fontWeight:700,color:'#737373',display:'flex',alignItems:'center'}}, rowLabels[ri]),
        row.map((v,ci)=>React.createElement('div',{key:ci,className:'heat-cell',style:{background:color(v)},
          onMouseMove:(ev)=>setTip({x:ev.clientX,y:ev.clientY,title:rowLabels[ri]+' · '+ci+':00',rows:[{color:'#FF177B',label:OA.fmt(v)+' '+OA.t('contentEvents')}]}),
          onMouseLeave:()=>setTip(null),
          onClick:onCell?()=>onCell(ri,ci,v):undefined}))))),
    node);
}
window.Heatmap=Heatmap;

/* ---------------- mini sparkline ---------------- */
function Spark({data, color='#4D4A9D', w=120, h=34}){
  if(!data.length) return null;
  const max=Math.max(1,...data.map(d=>d.v));
  const X=i=> data.length<=1?w/2: i/(data.length-1)*w;
  const Y=v=> h-2-(v/max)*(h-6);
  const p=data.map((d,i)=>(i?'L':'M')+X(i).toFixed(1)+' '+Y(d.v).toFixed(1)).join(' ');
  const gid='sp'+Math.round(Math.random()*1e6);
  return React.createElement('svg',{width:w,height:h,style:{display:'block'}},
    React.createElement('defs',null,React.createElement('linearGradient',{id:gid,x1:0,y1:0,x2:0,y2:1},
      React.createElement('stop',{offset:'0%',stopColor:color,stopOpacity:.3}),
      React.createElement('stop',{offset:'100%',stopColor:color,stopOpacity:0}))),
    React.createElement('path',{d:p+` L${w} ${h} L0 ${h} Z`,fill:`url(#${gid})`}),
    React.createElement('path',{d:p,fill:'none',stroke:color,strokeWidth:2}));
}
window.Spark=Spark;

/* ---------------- grouped vertical bars (comparison) ---------------- */
function GroupBars({groups, series, height=260, fmt}){
  // groups: [{k, vals:[v1,v2,...]}], series:[{name,color}]
  const ref=useRef(null); const [w,setW]=useState(640); const {setTip,node}=useTip();
  useEffect(()=>{ const ro=new ResizeObserver(es=>{for(const e of es)setW(e.contentRect.width);}); if(ref.current)ro.observe(ref.current); return ()=>ro.disconnect();},[]);
  const pad={l:40,r:12,t:12,b:54}; const iw=Math.max(40,w-pad.l-pad.r), ih=height-pad.t-pad.b;
  const max=Math.max(1,...groups.flatMap(g=>g.vals)); const nice=niceMax(max);
  const gw=iw/groups.length; const bw=Math.min(34,gw/(series.length+0.6)/1);
  const Y=v=> pad.t+ih-(v/nice)*ih;
  const ticks=4; const yt=Array.from({length:ticks+1},(_,i)=>nice*i/ticks);
  return React.createElement('div',{ref,style:{width:'100%',position:'relative'}},
    React.createElement('svg',{width:w,height,onMouseLeave:()=>setTip(null)},
      yt.map((v,i)=>React.createElement('g',{key:i},
        React.createElement('line',{x1:pad.l,x2:w-pad.r,y1:Y(v),y2:Y(v),stroke:'#E5E5E5',strokeDasharray:i?'3 4':'0'}),
        React.createElement('text',{x:pad.l-8,y:Y(v)+4,textAnchor:'end',fontSize:10.5,fontWeight:700,fill:'#A3A3A3'},OA.fmtCompact(v)))),
      groups.map((g,gi)=>{ const gx=pad.l+gi*gw+gw/2;
        return React.createElement('g',{key:gi},
          g.vals.map((v,si)=>{ const totalW=series.length*bw+(series.length-1)*4; const x=gx-totalW/2+si*(bw+4);
            return React.createElement('rect',{key:si,x,y:Y(v),width:bw,height:Math.max(0,pad.t+ih-Y(v)),rx:4,fill:series[si].color,
              onMouseMove:(ev)=>setTip({x:ev.clientX,y:ev.clientY,title:g.k,rows:[{color:series[si].color,label:series[si].name+': '+(fmt?fmt(v):OA.fmt(v))}]}),
              style:{cursor:'default',transition:'.1s'}}); }),
          React.createElement('text',{x:gx,y:height-34,textAnchor:'middle',fontSize:10.5,fontWeight:700,fill:'#525252',
            transform:groups.length>6?`rotate(28 ${gx} ${height-34})`:undefined,
            style:groups.length>6?{textAnchor:'start'}:undefined}, g.k.length>12?g.k.slice(0,11)+'…':g.k)
        );
      })
    ), node);
}
window.GroupBars=GroupBars;

function niceMax(m){ if(m<=5) return 5; const pow=Math.pow(10,Math.floor(Math.log10(m))); const n=m/pow;
  let f; if(n<=1)f=1; else if(n<=2)f=2; else if(n<=2.5)f=2.5; else if(n<=5)f=5; else f=10; return f*pow; }
window.niceMax=niceMax;
