/* ============================================================
   REYAH PLATFORM, shared components (React, Babel)
   Exposes components on window for client-app / admin-app.
   ============================================================ */

/* ---------------- icon set (inline, stroke) ---------------- */
const I = {
  grid:    "M3 3h7v7H3zM14 3h7v7h-7zM14 14h7v7h-7zM3 14h7v7H3z",
  pulse:   "M3 12h4l2 7 4-14 2 7h6",
  inbox:   "M22 12h-6l-2 3h-4l-2-3H2 M5 5h14l3 7v6a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2v-6z",
  reply:   "M9 17l-5-5 5-5 M4 12h11a5 5 0 0 1 5 5v2",
  calendar:"M8 2v4M16 2v4M3 10h18 M5 4h14a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2z",
  check:   "M20 6L9 17l-5-5",
  users:   "M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2 M9 11a4 4 0 1 0 0-8 4 4 0 0 0 0 8 M23 21v-2a4 4 0 0 0-3-3.87 M16 3.13a4 4 0 0 1 0 7.75",
  send:    "M22 2L11 13 M22 2l-7 20-4-9-9-4 20-7z",
  alert:   "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",
  shield:  "M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z",
  search:  "M21 21l-4.3-4.3 M11 19a8 8 0 1 0 0-16 8 8 0 0 0 0 16z",
  chevDown:"M6 9l6 6 6-6",
  chevRight:"M9 18l6-6-6-6",
  arrowUp: "M12 19V5 M5 12l7-7 7 7",
  arrowDown:"M12 5v14 M19 12l-7 7-7-7",
  arrowDR: "M7 7h10v10 M7 17L17 7",
  arrowRt: "M5 12h14M13 6l6 6-6 6",
  clock:   "M12 8v4l3 2 M12 22a10 10 0 1 0 0-20 10 10 0 0 0 0 20z",
  mail:    "M4 4h16a2 2 0 0 1 2 2v12a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2z M22 6l-10 7L2 6",
  phone:   "M22 16.92v3a2 2 0 0 1-2.18 2 19.8 19.8 0 0 1-8.63-3.07 19.5 19.5 0 0 1-6-6 19.8 19.8 0 0 1-3.07-8.67A2 2 0 0 1 4.11 2h3a2 2 0 0 1 2 1.72c.13.96.36 1.9.7 2.81a2 2 0 0 1-.45 2.11L8.09 9.91a16 16 0 0 0 6 6l1.27-1.27a2 2 0 0 1 2.11-.45c.91.34 1.85.57 2.81.7A2 2 0 0 1 22 16.92z",
  hire:    "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 M19 8v6 M22 11h-6",
  bell:    "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",
  settings:"M12 15a3 3 0 1 0 0-6 3 3 0 0 0 0 6z M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 1 1-2.83 2.83l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-4 0v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 1 1-2.83-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1 0-4h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 1 1 2.83-2.83l.06.06a1.65 1.65 0 0 0 1.82.33H9a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 4 0v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 1 1 2.83 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82V9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 0 4h-.09a1.65 1.65 0 0 0-1.51 1z",
  building:"M3 21h18 M5 21V7l7-4 7 4v14 M9 9h0M9 13h0M9 17h0M15 9h0M15 13h0M15 17h0",
  filter:  "M22 3H2l8 9.46V19l4 2v-8.54L22 3z",
  download:"M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4 M7 10l5 5 5-5 M12 15V3",
  dots:    "M12 13a1 1 0 1 0 0-2 1 1 0 0 0 0 2zM19 13a1 1 0 1 0 0-2 1 1 0 0 0 0 2zM5 13a1 1 0 1 0 0-2 1 1 0 0 0 0 2z",
  logout:  "M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4 M16 17l5-5-5-5 M21 12H9",
  book:    "M4 19.5A2.5 2.5 0 0 1 6.5 17H20 M6.5 2H20v20H6.5A2.5 2.5 0 0 1 4 19.5v-15A2.5 2.5 0 0 1 6.5 2z",
  target:  "M12 22a10 10 0 1 0 0-20 10 10 0 0 0 0 20z M12 18a6 6 0 1 0 0-12 6 6 0 0 0 0 12z M12 14a2 2 0 1 0 0-4 2 2 0 0 0 0 4z",
  zap:     "M13 2L3 14h9l-1 8 10-12h-9l1-8z",
  globe:   "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",
  close:   "M18 6L6 18 M6 6l12 12",
  key:     "M15.5 7.5a4 4 0 1 0-3.9 5 l-1.1 1.1-1.5-.2-.2 1.5-1.5-.2-.2 1.5H3v-2.6l4.6-4.6a4 4 0 0 1 7.9-1z M16.5 7.5h.01",
  userPlus:"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 M19 8v6 M22 11h-6",
  copy:    "M9 9h10a2 2 0 0 1 2 2v10a2 2 0 0 1-2 2H9a2 2 0 0 1-2-2V11a2 2 0 0 1 2-2z M5 15H4a2 2 0 0 1-2-2V3a2 2 0 0 1 2-2h10a2 2 0 0 1 2 2v1",
  message: "M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z",
  mic:     "M12 2a3 3 0 0 0-3 3v6a3 3 0 0 0 6 0V5a3 3 0 0 0-3-3z M19 10v1a7 7 0 0 1-14 0v-1 M12 18v4 M8 22h8",
  voicemail:"M5.5 16a3.5 3.5 0 1 0 0-7 3.5 3.5 0 1 0 0 7z M18.5 16a3.5 3.5 0 1 0 0-7 3.5 3.5 0 1 0 0 7z M5.5 16h13",
  edit:    "M11 4H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7 M18.5 2.5a2.12 2.12 0 0 1 3 3L12 15l-4 1 1-4z",
  pin:     "M12 22s7-5.5 7-12a7 7 0 1 0-14 0c0 6.5 7 12 7 12z M12 12a2.5 2.5 0 1 0 0-5 2.5 2.5 0 0 0 0 5z"
};

function Icon({n, w}){
  return (
    <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth={w||2} strokeLinecap="round" strokeLinejoin="round" style={{width:'1em',height:'1em'}}>
      {I[n].split(" M").map((seg,i)=> <path key={i} d={(i?"M":"")+seg} />)}
    </svg>
  );
}

/* ---------------- sidebar ---------------- */
function Sidebar({org, items, active, onNav, user, footerExtra}){
  return (
    <aside className="side">
      <div className="side__logo"><img src="assets/reyah-logo.png" alt="Reyah" /></div>
      <button className="side__org" onClick={org.onClick}>
        <b className="nm">{org.name}</b>
        <span className="chev"><Icon n="chevDown" /></span>
      </button>
      {items.map(function(grp){
        return (
          <React.Fragment key={grp.label}>
            <div className="side__label">{grp.label}</div>
            {grp.links.map(function(l){
              return (
                <button key={l.id} className={"navitem"+(active===l.id?" active":"")} onClick={function(){onNav(l.id);}}>
                  <Icon n={l.icon} />
                  <span>{l.label}</span>
                  {l.count!=null && <span className={"count"+(l.hot?" hot":"")}>{l.count}</span>}
                </button>
              );
            })}
          </React.Fragment>
        );
      })}
      <div className="side__foot">
        {footerExtra}
        <div className="side__user">
          <span className="av">{user.initials}</span>
          <span className="nm"><b>{user.name}</b><span>{user.role}</span></span>
          <button className="side__logout" title="Sign out" aria-label="Sign out" onClick={function(){
            var live = window.REYAH_AUTH && window.REYAH_CONFIG && !window.REYAH_CONFIG.useMock;
            if (live) { window.REYAH_AUTH.signOut(); } else { window.location.href="sign-in.html"; }
          }}><Icon n="logout" /></button>
        </div>
      </div>
    </aside>
  );
}

/* ---------------- global search ----------------
   Live filter over an `index` of {id,cat,label,sub,av,tag,tagKind,kw,onPick}.
   Matches against the precomputed lowercase `kw`, groups hits by `cat`, and
   drops a categorised results panel beneath the bar. Apps build the index. */
function SearchBox({index, placeholder}){
  const [q,setQ]=React.useState("");
  const [open,setOpen]=React.useState(false);
  const wrap=React.useRef(null);
  React.useEffect(function(){
    function onDoc(e){ if(wrap.current && !wrap.current.contains(e.target)) setOpen(false); }
    function onKey(e){ if(e.key==="Escape") setOpen(false); }
    document.addEventListener("mousedown",onDoc);
    document.addEventListener("keydown",onKey);
    return function(){ document.removeEventListener("mousedown",onDoc); document.removeEventListener("keydown",onKey); };
  },[]);
  const ql=q.trim().toLowerCase();
  const hits = ql ? (index||[]).filter(function(it){ return it.kw.indexOf(ql)>=0; }) : [];
  const groups={}; const order=[];
  hits.forEach(function(it){ if(!groups[it.cat]){ groups[it.cat]=[]; order.push(it.cat); } groups[it.cat].push(it); });
  function pick(it){ setOpen(false); setQ(""); it.onPick(); }
  return (
    <div className="topbar__search-wrap" ref={wrap}>
      <label className="topbar__search">
        <Icon n="search" />
        <input value={q} placeholder={placeholder||"Search doctors, replies, campaigns…"}
          onChange={function(e){ setQ(e.target.value); setOpen(true); }}
          onFocus={function(){ if(q) setOpen(true); }} />
        {q && <button type="button" className="topbar__search-clear" aria-label="Clear search"
          onClick={function(){ setQ(""); setOpen(false); }}><Icon n="close" /></button>}
      </label>
      {open && ql &&
        <div className="searchpop" role="listbox">
          {hits.length===0 && <div className="searchpop__empty">No matches for “{q}”</div>}
          {order.map(function(cat){
            return (
              <div className="searchgrp" key={cat}>
                <div className="searchgrp__h"><span>{cat}</span><span className="searchgrp__n">{groups[cat].length}</span></div>
                {groups[cat].slice(0,8).map(function(it){
                  return (
                    <button type="button" className="searchrow" key={it.id}
                      onMouseDown={function(e){ e.preventDefault(); }} onClick={function(){ pick(it); }}>
                      {it.av && <span className="searchrow__av">{it.av}</span>}
                      <span className="searchrow__main">
                        <span className="searchrow__label">{it.label}</span>
                        {it.sub && <span className="searchrow__sub">{it.sub}</span>}
                      </span>
                      {it.tag && <Tag kind={it.tagKind||"neutral"}>{it.tag}</Tag>}
                    </button>
                  );
                })}
                {groups[cat].length>8 && <div className="searchgrp__more">+{groups[cat].length-8} more</div>}
              </div>
            );
          })}
        </div>}
    </div>
  );
}

/* ---------------- topbar ---------------- */
function Topbar({title, sub, search, searchIndex, right}){
  return (
    <div className="topbar">
      <div className="topbar__title"><h1>{title}</h1>{sub && <span>{sub}</span>}</div>
      <div className="topbar__spacer" />
      {search!==false && (searchIndex
        ? <SearchBox index={searchIndex} placeholder={typeof search==="string"?search:null} />
        : <label className="topbar__search">
          <Icon n="search" />
          <input placeholder={search||"Search doctors, replies, campaigns…"} />
        </label>)}
      {right || (
        <React.Fragment>
          <button className="iconbtn" aria-label="Notifications"><Icon n="bell" /><span className="dot" /></button>
          <button className="iconbtn" aria-label="Settings"><Icon n="settings" /></button>
        </React.Fragment>
      )}
    </div>
  );
}

/* ---------------- KPI card ---------------- */
function Kpi({icon, label, value, unit, delta, deltaLabel, feature}){
  return (
    <div className={"kpi"+(feature?" feature":"")}>
      <div className="kpi__top">
        <span className="ic"><Icon n={icon} /></span>
        <span className="lab">{label}</span>
      </div>
      <div className="kpi__num">{value}{unit && <span className="u">{unit}</span>}</div>
      <div className="kpi__sub">
        {delta!=null && (
          <span className={"delta "+(delta>=0?"up":"down")}>
            <Icon n={delta>=0?"arrowUp":"arrowDown"} />{delta>=0?"+":""}{delta}
          </span>
        )}
        <span>{deltaLabel}</span>
      </div>
    </div>
  );
}

/* ---------------- status tag ---------------- */
function Tag({kind, children, dot}){
  return <span className={"tag tag--"+kind}>{dot&&<span className="d" />}{children}</span>;
}

/* ---- editable hire-status pill: small, content-width, click → dropdown ---- */
const HIRE_STATUS = [
  {v:"onboarding", label:"Onboarding",       kind:"info"},
  {v:"guarantee",  label:"Guarantee active", kind:"pos"}
];
function StatusPill({value, onChange}){
  const [open,setOpen]=React.useState(false);
  const ref=React.useRef(null);
  React.useEffect(function(){ function out(e){ if(ref.current && !ref.current.contains(e.target)) setOpen(false); } document.addEventListener("mousedown",out); return function(){ document.removeEventListener("mousedown",out); }; },[]);
  const cur = HIRE_STATUS.find(function(s){return s.v===value;}) || HIRE_STATUS[0];
  return (
    <span className="statpill" ref={ref} onClick={function(e){e.stopPropagation();}}>
      <button type="button" className={"tag tag--"+cur.kind+" statpill__btn"} onClick={function(){setOpen(!open);}}>
        <span className="d" />{cur.label}
        <svg className="statpill__chev" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.4" strokeLinecap="round" strokeLinejoin="round"><path d="M6 9l6 6 6-6"/></svg>
      </button>
      {open && <div className="statpill__menu">
        {HIRE_STATUS.map(function(s){
          return <button type="button" key={s.v} className={"statpill__opt"+(s.v===value?" active":"")} onClick={function(){ onChange&&onChange(s.v); setOpen(false); }}>
            <span className={"statpill__dot statpill__dot--"+s.kind} />{s.label}{s.v===value && <Icon n="check" />}
          </button>;
        })}
      </div>}
    </span>
  );
}
function Chan({c}){
  const map={email:"Email",sms:"SMS",vm:"Voicemail"};
  return <span className={"chan chan--"+c}>{map[c]||c}</span>;
}
function sentimentTag(s){
  if(s==="pos") return <Tag kind="pos" dot>Positive</Tag>;
  if(s==="neg") return <Tag kind="bad" dot>Opted out</Tag>;
  return <Tag kind="neutral" dot>Neutral</Tag>;
}

/* ---------------- charts (SVG, on-brand) ---------------- */
// dual line/area chart
function AreaLine({labels, series, height}){
  const W=680, H=height||220, pad={l:8,r:8,t:14,b:24};
  const all=[].concat.apply([], series.map(s=>s.data));
  const max=Math.max.apply(null, all)*1.15 || 1;
  const n=labels.length;
  const x=i=> pad.l + i*((W-pad.l-pad.r)/(n-1));
  const y=v=> pad.t + (1-v/max)*(H-pad.t-pad.b);
  function path(data, close){
    let d="M"+x(0)+","+y(data[0]);
    for(let i=1;i<n;i++) d+=" L"+x(i)+","+y(data[i]);
    if(close) d+=" L"+x(n-1)+","+(H-pad.b)+" L"+x(0)+","+(H-pad.b)+" Z";
    return d;
  }
  const [hi,setHi]=React.useState(null);
  const wrap=React.useRef(null);
  function move(e){
    const r=wrap.current.getBoundingClientRect();
    const sx=((e.clientX-r.left)/r.width)*W;
    let i=Math.round((sx-pad.l)/((W-pad.l-pad.r)/(n-1)));
    setHi(Math.max(0,Math.min(n-1,i)));
  }
  const xPct = i => (x(i)/W*100);
  const tipLeft = hi==null?0:Math.max(13,Math.min(87,xPct(hi)));
  return (
    <div ref={wrap} className="chartwrap" onMouseMove={move} onMouseLeave={function(){setHi(null);}} onTouchStart={function(e){if(e.touches[0])move(e.touches[0]);}} onTouchMove={function(e){if(e.touches[0]){move(e.touches[0]);}}}>
      <svg viewBox={"0 0 "+W+" "+H} style={{width:'100%',height:'auto',display:'block'}} preserveAspectRatio="none">
        <defs>
          {series.map((s,i)=>(
            <linearGradient key={i} id={"ag"+i} x1="0" y1="0" x2="0" y2="1">
              <stop offset="0%" stopColor={s.color} stopOpacity="0.18"/>
              <stop offset="100%" stopColor={s.color} stopOpacity="0"/>
            </linearGradient>
          ))}
        </defs>
        {[0,0.5,1].map((g,i)=>(
          <line key={i} x1={pad.l} x2={W-pad.r} y1={pad.t+g*(H-pad.t-pad.b)} y2={pad.t+g*(H-pad.t-pad.b)} stroke="#E9E5DE" strokeWidth="1"/>
        ))}
        {series.map((s,i)=>(
          <g key={i}>
            {s.fill!==false && <path d={path(s.data,true)} fill={"url(#ag"+i+")"} />}
            <path d={path(s.data)} fill="none" stroke={s.color} strokeWidth="2.4" strokeLinejoin="round" strokeLinecap="round"/>
            {s.data.map((v,j)=> <circle key={j} cx={x(j)} cy={y(v)} r={j===n-1?3.5:0} fill={s.color} />)}
          </g>
        ))}
        {labels.map((l,i)=> (i%Math.ceil(n/8)===0||i===n-1) &&
          <text key={i} x={x(i)} y={H-7} fill="#8A8F98" fontSize="10" fontFamily="var(--f-mono)" textAnchor="middle">{l}</text>)}
      </svg>
      {hi!=null && (
        <React.Fragment>
          <div className="chart-cross" style={{left:xPct(hi)+'%'}} />
          {series.map(function(s,i){ return <span key={i} className="chart-dot" style={{left:xPct(hi)+'%', top:(y(s.data[hi])/H*100)+'%', borderColor:s.color}} />; })}
          <div className="chart-tip" style={{left:tipLeft+'%'}}>
            <b>{labels[hi]}</b>
            {series.map(function(s,i){ return <div key={i} className="chart-tip__r"><i style={{background:s.color}} />{s.name?<span>{s.name}</span>:null}<em>{(typeof s.data[hi]==='number'?s.data[hi].toLocaleString():s.data[hi])}{s.unit||''}</em></div>; })}
          </div>
        </React.Fragment>
      )}
    </div>
  );
}

// vertical bars
function Bars({labels, data, color, height}){
  const W=680,H=height||200,pad={l:8,r:8,t:12,b:22};
  const max=Math.max.apply(null,data)*1.15||1, n=data.length;
  const bw=(W-pad.l-pad.r)/n*0.56;
  const x=i=> pad.l + i*((W-pad.l-pad.r)/n) + ((W-pad.l-pad.r)/n-bw)/2;
  const y=v=> pad.t+(1-v/max)*(H-pad.t-pad.b);
  return (
    <svg viewBox={"0 0 "+W+" "+H} style={{width:'100%',height:'auto',display:'block'}}>
      {data.map((v,i)=>(
        <rect key={i} x={x(i)} y={y(v)} width={bw} height={(H-pad.b)-y(v)} rx="4" fill={color||"#FF4A1C"} opacity={0.35+0.65*(v/max)} />
      ))}
      {labels.map((l,i)=> (i%Math.ceil(n/10)===0||i===n-1) &&
        <text key={i} x={x(i)+bw/2} y={H-6} fill="#8A8F98" fontSize="9.5" fontFamily="var(--f-mono)" textAnchor="middle">{l}</text>)}
    </svg>
  );
}

// donut / ring
function Donut({segments, size, center}){
  const S=size||150, r=S/2-14, cx=S/2, cy=S/2, C=2*Math.PI*r;
  const total=segments.reduce((a,b)=>a+b.value,0)||1;
  let off=0;
  return (
    <div style={{position:'relative',width:S,height:S}}>
      <svg viewBox={"0 0 "+S+" "+S} style={{width:S,height:S,transform:'rotate(-90deg)'}}>
        <circle cx={cx} cy={cy} r={r} fill="none" stroke="#F1EDE6" strokeWidth="14"/>
        {segments.map((s,i)=>{
          const len=s.value/total*C;
          const el=<circle key={i} cx={cx} cy={cy} r={r} fill="none" stroke={s.color} strokeWidth="14"
            strokeDasharray={len+" "+(C-len)} strokeDashoffset={-off} strokeLinecap="butt"/>;
          off+=len; return el;
        })}
      </svg>
      {center && <div style={{position:'absolute',inset:0,display:'flex',flexDirection:'column',alignItems:'center',justifyContent:'center',textAlign:'center'}}>
        <div style={{fontSize:'1.5rem',fontWeight:700,letterSpacing:'-0.03em',color:'var(--ink)'}}>{center.value}</div>
        <div style={{fontSize:'11px',color:'var(--muted)'}}>{center.label}</div>
      </div>}
    </div>
  );
}

// horizontal funnel
function Funnel({steps}){
  const max=steps[0].n||1;
  const colors=['#FF4A1C','#FB5A22','#F06A2A','#E11D2A','#C9182A','#A8131F'];
  return (
    <div style={{display:'flex',flexDirection:'column',gap:10}}>
      {steps.map(function(s,i){
        const w=Math.max(4, s.n/max*100);
        return (
          <div key={i} style={{display:'grid',gridTemplateColumns:'150px 1fr 96px',gap:14,alignItems:'center'}}>
            <span style={{fontSize:'var(--fs-sm)',color:'var(--ink-2)',fontWeight:500}}>{s.label}</span>
            <div style={{background:'var(--bg-soft-2)',borderRadius:8,overflow:'hidden',height:34}}>
              <div style={{width:w+'%',height:'100%',background:colors[i]||'#A8131F',borderRadius:8}}></div>
            </div>
            <span style={{textAlign:'right',fontVariantNumeric:'tabular-nums'}}>
              <b style={{fontSize:'1rem',fontWeight:700,color:'var(--ink)'}}>{s.n.toLocaleString()}</b>
              <span style={{fontSize:'var(--fs-xs)',color:'var(--muted)',marginLeft:6}}>{s.pct}%</span>
            </span>
          </div>
        );
      })}
    </div>
  );
}

/* ---------------- card / panel wrappers ---------------- */
function PCard({title, sub, action, children, pad}){
  return (
    <div className="pcard">
      {(title||action) &&
        <div className="pcard__head">
          <div><h3>{title}</h3>{sub && <div className="sub">{sub}</div>}</div>
          {action}
        </div>}
      <div className="pcard__body" style={pad===false?{padding:0}:null}>{children}</div>
    </div>
  );
}

function Feed({items}){
  return (
    <div className="feed">
      {items.map(function(f,i){
        return (
          <div className="feed__item" key={i}>
            <span className={"feed__ic "+f.ic}><Icon n={f.icon} /></span>
            <div className="feed__b"><b>{f.title}</b><p>{f.body}</p></div>
            <span className="feed__time">{f.time}</span>
          </div>
        );
      })}
    </div>
  );
}

function Meter({pct, kind}){
  return <div className={"meter"+(kind?" "+kind:"")}><i style={{width:Math.min(100,pct)+'%'}} /></div>;
}

function Seg({options, value, onChange}){
  return (
    <div className="seg">
      {options.map(function(o){
        const v=typeof o==='string'?o:o.value, l=typeof o==='string'?o:o.label;
        return <button key={v} className={value===v?"active":""} onClick={function(){onChange(v);}}>{l}</button>;
      })}
    </div>
  );
}

/* ---------------- metric drawer (slide-out) ---------------- */
const RANGE_OPTS=[{value:"7d",label:"7D"},{value:"30d",label:"30D"},{value:"3m",label:"3M"},{value:"12m",label:"12M"}];

function MetricDrawer({metric, onClose}){
  const [range,setRange]=React.useState("30d");
  React.useEffect(function(){
    function esc(e){ if(e.key==="Escape") onClose(); }
    document.addEventListener("keydown",esc);
    return function(){ document.removeEventListener("keydown",esc); };
  },[]);
  if(!metric) return null;
  const series=window.RYH.genSeries(metric.id, range, metric.raw, metric.kind);
  const peak=Math.max.apply(null,series.data);
  const low=Math.min.apply(null,series.data);
  const avg=series.data.reduce((a,b)=>a+b,0)/series.data.length;
  const fmt=metric.fmt||(v=>v);
  return (
    <div className="drawer-scrim" onClick={function(e){ if(e.target===e.currentTarget) onClose(); }}>
      <div className="drawer-panel" role="dialog" aria-label={metric.label}>
        <div className="drawer-head">
          <div className="drawer-head__top">
            <span className={"kpi__top"}><span className="ic" style={{background:'var(--accent-wash)',color:'var(--accent-2)'}}><Icon n={metric.icon} /></span></span>
            <button className="iconbtn" onClick={onClose} aria-label="Close" style={{marginLeft:'auto'}}><Icon n="close" /></button>
          </div>
          <div className="drawer-lab">{metric.label}</div>
          <div className="drawer-val">{metric.value}{metric.unit && <span className="u">{metric.unit}</span>}</div>
          <div className="drawer-sub">
            {metric.delta!=null && <span className={"delta "+((metric.deltaGood?-metric.delta:metric.delta)>=0?"up":"down")}><Icon n={metric.delta>=0?"arrowUp":"arrowDown"} />{metric.delta>=0?"+":""}{metric.delta}{metric.deltaUnit||""}</span>}
            <span>{metric.deltaLabel}</span>
            {metric.target && <span className="tag tag--neutral" style={{marginLeft:'auto'}}>Target · {metric.target}</span>}
          </div>
        </div>
        <div className="drawer-body">
          <div className="drawer-rangerow">
            <span className="drawer-secn">Trend</span>
            <Seg options={RANGE_OPTS} value={range} onChange={setRange} />
          </div>
          <div className="pcard" style={{marginTop:12}}>
            <div className="pcard__body">
              <AreaLine labels={series.labels} height={210}
                series={[{data:series.data, color:metric.color||"#FF4A1C", name:metric.label, unit:metric.unit||""}]} />
            </div>
          </div>
          <div className="drawer-mini">
            <div className="drawer-stat"><span>Average</span><b>{fmt(metric.kind==='count'||metric.kind==='cumulative'?Math.round(avg):+avg.toFixed(1))}</b></div>
            <div className="drawer-stat"><span>Peak</span><b>{fmt(peak)}</b></div>
            <div className="drawer-stat"><span>Low</span><b>{fmt(low)}</b></div>
          </div>
          {metric.breakdown && (
            <React.Fragment>
              <div className="drawer-secn" style={{marginTop:22}}>{metric.breakdownTitle||"Breakdown"}</div>
              <div className="pcard" style={{marginTop:10}}><div className="pcard__body" style={{paddingTop:8,paddingBottom:8}}>
                {metric.breakdown.map(function(b,i){
                  return (
                    <div key={i} style={{display:'grid',gridTemplateColumns:'1fr 64px 90px',gap:12,alignItems:'center',padding:'11px 0',borderBottom:i<metric.breakdown.length-1?'1px solid var(--line-soft)':'none'}}>
                      <span style={{fontSize:'var(--fs-sm)',color:'var(--ink-2)',fontWeight:500}}>{b.label}</span>
                      <span style={{fontSize:'var(--fs-sm)',fontWeight:700,textAlign:'right',color:'var(--ink)',fontVariantNumeric:'tabular-nums'}}>{b.value}</span>
                      <Meter pct={b.pct} kind={b.kind} />
                    </div>
                  );
                })}
              </div></div>
            </React.Fragment>
          )}
          {metric.note && <p style={{fontSize:'var(--fs-xs)',color:'var(--muted)',marginTop:16,lineHeight:1.5}}>{metric.note}</p>}
        </div>
      </div>
    </div>
  );
}

/* ---------------- data-derived KPI delta ----------------
   Computes the "vs last 30 days" delta from the metric's own trend
   data instead of a hard-coded number, so cards + drawers stay in
   sync and live data flows straight through. Pass a real series via
   metric.series['30d'] from the backend; otherwise it's generated. */
function trendDelta(m){
  var s = (m.series && m.series["30d"]) ? m.series["30d"] : window.RYH.genSeries(m.id,"30d",m.raw,m.kind);
  var first = s.data[0], last = s.data[s.data.length-1];
  var d = last - first;
  d = (m.kind==="rate"||m.kind==="time") ? +d.toFixed(1) : Math.round(d);
  return Object.assign({}, m, { delta:d, deltaLabel: m.deltaLabel || "vs last 30 days" });
}

/* ---------------- toggle switch ---------------- */
function Toggle({on, onChange}){
  return <button type="button" className={"switch"+(on?" on":"")} aria-pressed={!!on} onClick={function(){onChange(!on);}}><i /></button>;
}

/* ---------------- settings row ---------------- */
function SRow({title, desc, children}){
  return (
    <div className="setrow">
      <div className="lab"><b>{title}</b>{desc && <span>{desc}</span>}</div>
      <div style={{flex:"0 0 auto"}}>{children}</div>
    </div>
  );
}

/* ---------------- notifications dropdown ---------------- */
function NotificationsPanel({items, onClose, onAllRead}){
  return (
    <React.Fragment>
      <div className="noti__scrim" onClick={onClose} />
      <div className="noti" role="dialog" aria-label="Notifications">
        <div className="noti__head">
          <b>Notifications</b>
          <button className="btn-link" style={{fontSize:"12px"}} onClick={onAllRead}>Mark all read</button>
        </div>
        <div className="noti__list">
          {items.length===0 && <div className="empty"><Icon n="bell" /><div>You're all caught up</div></div>}
          {items.map(function(n,i){
            return (
              <div key={i} className={"noti__item"+(n.unread?" unread":"")}>
                <span className={"feed__ic "+n.ic}><Icon n={n.icon} /></span>
                <div className="noti__b"><b>{n.title}</b><p>{n.body}</p><time>{n.time}</time></div>
              </div>
            );
          })}
        </div>
      </div>
    </React.Fragment>
  );
}

/* ---------------- integration card + connect modal ---------------- */
// Live detail line under each integration — derived from the loaded dashboard
// data (refreshes with it) rather than a hardcoded fixture string.
function liveDetail(it, data){
  if(!data) return null;
  if(it.id==="ghl"){
    var b=(data.kpis&&data.kpis.bookings)||(data.bookings&&data.bookings.length)||0;
    return b+" call booking"+(b===1?"":"s")+" synced";
  }
  if(it.id==="plusvibe"){
    var doms=data.domains||[];
    var n=doms.reduce(function(s,d){return s+(d.sent||0);},0);
    return doms.length+" domain"+(doms.length===1?"":"s")+" · "+n.toLocaleString()+" sends";
  }
  return null;
}
function IntegrationCard({it, onConnect, onDisconnect, data}){
  const connected = it.status==="connected";
  const liveD = connected ? (liveDetail(it, data) || it.detail || "") : "";
  return (
    <div className="intg">
      <div className="intg__top">
        {it.logo
          ? <span className="intg__tile intg__tile--logo"><img src={it.logo} alt={it.name} /></span>
          : <span className="intg__tile" style={{background:it.color}}>{it.tile}</span>}
        <div style={{flex:1,minWidth:0}}>
          <b className="intg__name">{it.name}</b>
          <span className="intg__cat">{it.cat}{it.owner==="reyah" ? " · Managed by Reyah" : ""}</span>
        </div>
        {connected ? <Tag kind="pos" dot>Connected</Tag> : <Tag kind="neutral" dot>Not connected</Tag>}
      </div>
      <p className="intg__desc">{it.desc}</p>
      <div className="intg__foot">
        <span className="intg__detail">{liveD}</span>
        {it.owner==="reyah"
          ? <button className="btn btn--ghost btn--sm" onClick={function(){onConnect(it);}}>Manage</button>
          : (connected
              ? <span style={{display:"flex",gap:8}}>
                  <button className="btn btn--ghost btn--sm" onClick={function(){onConnect(it);}}>Manage</button>
                  <button className="btn btn--ghost btn--sm" onClick={function(){onDisconnect(it);}}>Disconnect</button>
                </span>
              : <button className="btn btn--primary btn--sm" onClick={function(){onConnect(it);}}>Connect <Icon n="arrowRt" /></button>)}
      </div>
    </div>
  );
}

function ConnectModal({it, onClose, onConfirm}){
  const cfg = window.REYAH_CONFIG || {connect:{}};
  const endpoint = (cfg.connect||{})[it.id==="gcal"?"googleCalendar":it.id] || "/api/connect/"+it.id;
  const connected = it.status==="connected";
  React.useEffect(function(){ function esc(e){ if(e.key==="Escape") onClose(); } document.addEventListener("keydown",esc); return function(){ document.removeEventListener("keydown",esc); }; },[]);
  return (
    <div className="modal__scrim" onClick={function(e){ if(e.target===e.currentTarget) onClose(); }}>
      <div className="modal" role="dialog" aria-label={"Connect "+it.name}>
        <div className="modal__head">
          {it.logo
            ? <span className="intg__tile intg__tile--logo"><img src={it.logo} alt={it.name} /></span>
            : <span className="intg__tile" style={{background:it.color}}>{it.tile}</span>}
          <div style={{flex:1}}><b style={{fontSize:"1.05rem",fontWeight:600,color:"var(--ink)"}}>{it.name}</b><div className="muted xs">{it.cat}</div></div>
          <button className="iconbtn" onClick={onClose} aria-label="Close"><Icon n="close" /></button>
        </div>
        <div className="modal__body">
          <p style={{fontSize:"var(--fs-sm)",color:"var(--body)",lineHeight:1.55}}>{it.desc}</p>
          <div className="modal__note">
            <Icon n="shield" />
            <div>
              <b>Wired for handoff.</b> Connecting opens a secure authorisation flow handled by the Reyah backend at <code>{endpoint}</code>. {it.id==="gcal" ? "You'll grant calendar access via Google, then bookings appear in your calendar automatically." : it.id==="ghl" ? "Authorise with GoHighLevel (OAuth or Private Integration Token)." : "Authorise with your PlusVibe API key + workspace ID."} No credentials are stored in the browser.
            </div>
          </div>
        </div>
        <div className="modal__foot">
          <button className="btn btn--ghost btn--sm" onClick={onClose}>Cancel</button>
          {connected
            ? <button className="btn btn--primary btn--sm" onClick={onClose}>Done</button>
            : <button className="btn btn--primary btn--sm" onClick={function(){onConfirm(it);}}>{it.id==="gcal"?"Authorise with Google":"Authorise & connect"} <Icon n="arrowRt" /></button>}
        </div>
      </div>
    </div>
  );
}

/* ---------------- transient toast (action feedback) ---------------- */
function ryToast(msg){
  var host=document.getElementById("ry-toasts");
  if(!host){ host=document.createElement("div"); host.id="ry-toasts"; host.className="ry-toasts"; document.body.appendChild(host); }
  var el=document.createElement("div"); el.className="ry-toast";
  var dot=document.createElement("span"); dot.className="ry-toast__c";
  var tx=document.createElement("span"); tx.textContent=msg;
  el.appendChild(dot); el.appendChild(tx); host.appendChild(el);
  setTimeout(function(){ el.style.opacity="0"; el.style.transform="translateY(8px)"; setTimeout(function(){ el.remove(); },260); }, 2600);
}
window.ryToast = ryToast;

/* ---------------- custom select (matches dashboard UI) ---------------- */
function RSelect({value, options, onChange, full, placeholder}){
  const [open,setOpen]=React.useState(false);
  const ref=React.useRef(null);
  React.useEffect(function(){ function out(e){ if(ref.current && !ref.current.contains(e.target)) setOpen(false); } document.addEventListener("mousedown",out); return function(){ document.removeEventListener("mousedown",out); }; },[]);
  return (
    <div className={"rsel"+(full?" rsel--full":"")} ref={ref}>
      <button type="button" className={"rsel__btn"+(open?" open":"")} onClick={function(){setOpen(!open);}}>
        <span className={value?"":"rsel__ph"}>{value||placeholder||"Select…"}</span>
        <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M6 9l6 6 6-6"/></svg>
      </button>
      {open && <div className="rsel__menu">
        {options.map(function(o){
          return <button type="button" key={o} className={"rsel__opt"+(o===value?" active":"")} onClick={function(){ onChange(o); setOpen(false); }}>{o}{o===value && <Icon n="check" />}</button>;
        })}
      </div>}
    </div>
  );
}

/* ---------------- lead / contact drawer (the GHL contact record) ---------------- */
function LeadDrawer({lead, stages, onClose, onMoveStage, onSaveNote, onSend, onOpenInbox}){
  const [note,setNote]=React.useState(lead.notes||"");
  const [dirty,setDirty]=React.useState(false);
  const [showAll,setShowAll]=React.useState(false);
  const tl=lead.timeline||[];
  React.useEffect(function(){ setNote(lead.notes||""); setDirty(false); },[lead.id]);
  React.useEffect(function(){ function esc(e){ if(e.key==="Escape") onClose(); } document.addEventListener("keydown",esc); return function(){ document.removeEventListener("keydown",esc); }; },[]);
  const actions=[
    {k:"call", icon:"phone", label:"Call", prov:"GHL"},
    {k:"email", icon:"mail", label:"Email", prov:"PlusVibe"},
    {k:"sms", icon:"message", label:"Text", prov:"GHL"}
  ];
  return (
    <div className="drawer-scrim" onClick={function(e){ if(e.target===e.currentTarget) onClose(); }}>
      <div className="drawer-panel" role="dialog" aria-label={lead.name}>
        <div className="drawer-head">
          <div className="drawer-head__top">
            <button className="iconbtn" onClick={onClose} aria-label="Close" style={{marginLeft:"auto"}}><Icon n="close" /></button>
          </div>
          <div className="drawer-val" style={{fontSize:"1.6rem"}}>{lead.name}</div>
          <div className="drawer-sub"><span>{lead.spec} · {lead.vr} · {lead.loc}</span><span style={{marginLeft:"auto"}}>{sentimentTag(lead.sentiment)}</span></div>
          <div className="lead-actions">
            {actions.map(function(a){
              return <button key={a.k} className="lead-act" onClick={function(){ onSend(a.k, lead); }} title={a.label+" · "+a.prov}>
                <Icon n={a.icon} /><span>{a.label}</span>
              </button>;
            })}
          </div>
        </div>
        <div className="drawer-body">
          <div className="lead-grid">
            <a className="lead-field" href={"tel:"+(lead.phone||"").replace(/\s/g,"")} onClick={function(e){ e.preventDefault(); onSend("call",lead); }}>
              <span className="lead-field__ic"><Icon n="phone" /></span>
              <div><span className="lead-field__l">Mobile · tap to call</span><b>{lead.phone}</b></div>
            </a>
            <a className="lead-field" href={"#"} onClick={function(e){ e.preventDefault(); onSend("email",lead); }}>
              <span className="lead-field__ic"><Icon n="mail" /></span>
              <div><span className="lead-field__l">Email · via PlusVibe</span><b>{lead.email}</b></div>
            </a>
            <div className="lead-field">
              <span className="lead-field__ic"><Icon n="pin" /></span>
              <div><span className="lead-field__l">Location</span><b>{lead.loc}</b></div>
            </div>
            <div className="lead-field">
              <span className="lead-field__ic"><Icon n="users" /></span>
              <div><span className="lead-field__l">Owner</span><b>{lead.owner||"-"}</b></div>
            </div>
          </div>

          <div className="lead-secn">Pipeline stage <span className="lead-sync"><Icon n="zap" /> Synced to GoHighLevel</span></div>
          <RSelect full value={lead.stage} options={stages} onChange={function(v){ onMoveStage(lead.id, v); }} />

          <div className="lead-secn">Notes <span className="lead-sync"><Icon n="zap" /> Synced to GoHighLevel</span></div>
          <textarea className="lead-notes" value={note} onChange={function(e){ setNote(e.target.value); setDirty(true); }} placeholder="Add a note about this doctor…" />
          {dirty && <div style={{display:"flex",justifyContent:"flex-end",marginTop:8}}><button className="btn btn--primary btn--sm" onClick={function(){ onSaveNote(lead.id, note); setDirty(false); }}>Save note</button></div>}

          <div className="lead-secn">Activity <span className="lead-sync" style={{color:"var(--muted)"}}>{tl.length} tracked</span></div>
          <Feed items={(showAll?tl:tl.slice(0,3)).map(function(e){ return {ic:e.ic, icon:e.icon, title:e.title, body:e.body||"", time:e.time}; })} />
          {tl.length>3 && <button className="btn btn--ghost btn--sm" style={{marginTop:10}} onClick={function(){ setShowAll(!showAll); }}>{showAll?"See less":"See all "+tl.length+" events"}</button>}

          {lead.thread && lead.thread.length>0 && (
            <React.Fragment>
              <div className="lead-secn">Recent messages</div>
              <div className="pcard"><div className="pcard__body" style={{display:"flex",flexDirection:"column",gap:12}}>
                {lead.thread.slice(-2).map(function(b,i){
                  return <div key={i} className={"bubble "+(b.us?"us":"them")} style={{maxWidth:"100%"}}><span className="who">{b.who} · {b.chan?b.chan.toUpperCase():""}</span>{b.t}</div>;
                })}
                <button className="btn btn--ghost btn--sm" style={{alignSelf:"flex-start"}} onClick={function(){ onOpenInbox(lead); }}>Open in inbox <Icon n="arrowRt" /></button>
              </div></div>
            </React.Fragment>
          )}
        </div>
      </div>
    </div>
  );
}

/* ---------------- boot screen (error / coming-soon) ----------------
   Full-viewport fallback used by the client/admin bootstraps when the
   live session or dashboard load fails. kind: "error" | "comingsoon". */
function BootScreen({kind, message, onRetry}){
  const comingSoon = kind==="comingsoon";
  return (
    <div style={{position:'fixed',inset:0,display:'flex',alignItems:'center',justifyContent:'center',padding:24}}>
      <div className="pcard" style={{maxWidth:440,width:'100%',textAlign:'center'}}>
        <div className="pcard__body" style={{padding:'40px 30px'}}>
          <span style={{width:52,height:52,borderRadius:14,display:'inline-flex',alignItems:'center',justifyContent:'center',fontSize:24,
            background:comingSoon?'var(--info-wash)':'var(--accent-wash)',color:comingSoon?'var(--info)':'var(--accent-2)'}}>
            <Icon n={comingSoon?"clock":"alert"} />
          </span>
          <h3 style={{marginTop:18,fontSize:'1.15rem',fontWeight:600,color:'var(--ink)'}}>{comingSoon?"Coming soon":"Something went wrong"}</h3>
          <p style={{marginTop:8,fontSize:'var(--fs-sm)',color:'var(--muted)',lineHeight:1.5}}>{message}</p>
          <div style={{display:'flex',gap:10,justifyContent:'center',marginTop:22}}>
            {onRetry && <button className="btn btn--primary btn--sm" onClick={onRetry}>Try again</button>}
            <button className="btn btn--ghost btn--sm" onClick={function(){ window.location.href="sign-in.html"; }}>Back to sign in</button>
          </div>
        </div>
      </div>
    </div>
  );
}

Object.assign(window, {
  I, Icon, Sidebar, Topbar, SearchBox, Kpi, Tag, Chan, sentimentTag,
  AreaLine, Bars, Donut, Funnel, PCard, Feed, Meter, Seg, MetricDrawer,
  trendDelta, Toggle, SRow, NotificationsPanel, IntegrationCard, ConnectModal, LeadDrawer, RSelect,
  StatusPill, BootScreen
});
