/* ============================================================
   EMM — component library (React)
   Shared context: window.EMMCtx provides { lang, t }
   Exports building blocks to window.
   ============================================================ */
(function () {
  "use strict";
  const { useState, useEffect, useRef, useContext, createContext } = React;
  const E = window.EMM, S = window.EMM_I18N, C = E.fmt;

  const EMMCtx = createContext({ lang: "en", t: (k) => k });
  window.EMMCtx = EMMCtx;
  function useT() { return useContext(EMMCtx); }
  // translate a data-bound {en,hi} blob
  function L(obj, lang) { if (!obj) return ""; return obj[lang] || obj.en || obj.name || ""; }
  window.emmL = L;

  const SENT_LABEL = { pos: "positive", neu: "neutral", neg: "negative" };
  const SENT_COLOR = { pos: "var(--pos)", neu: "var(--neu)", neg: "var(--neg)" };

  // ---------- Panel / Card -----------------------------------
  function Panel({ title, sub, right, children, className = "", pad = true, span }) {
    return (
      <section className={"emm-panel " + className} style={span ? { gridColumn: "span " + span } : null}>
        {(title || right) && (
          <header className="emm-panel-head">
            <div>
              {title && <h3 className="emm-panel-title">{title}</h3>}
              {sub && <p className="emm-panel-sub">{sub}</p>}
            </div>
            {right && <div className="emm-panel-right">{right}</div>}
          </header>
        )}
        <div className={pad ? "emm-panel-body" : "emm-panel-body flush"}>{children}</div>
      </section>
    );
  }

  // ---------- Sentiment dot / chip ---------------------------
  function SentDot({ s, size = 8 }) {
    return <span className="emm-dot" style={{ width: size, height: size, background: SENT_COLOR[s] }} />;
  }
  function SentChip({ s }) {
    const { t } = useT();
    return (
      <span className={"emm-sentchip " + s}>
        <SentDot s={s} /> {t(SENT_LABEL[s])}
      </span>
    );
  }

  // ---------- KPI stat card ----------------------------------
  function KPIStat({ label, value, unit, delta, deltaGood, spark, sparkColor, onClick, accent, big, truncate, children }) {
    const up = delta > 0;
    const good = deltaGood === undefined ? up : deltaGood;
    return (
      <div className={"emm-kpi" + (onClick ? " clickable" : "") + (big ? " big" : "")} onClick={onClick}>
        <div className="emm-kpi-label">{label}</div>
        <div className="emm-kpi-row">
          <div className={"emm-kpi-value mono" + (truncate ? " trunc" : "")} style={accent ? { color: accent } : null}>
            {value}{unit && <span className="emm-kpi-unit">{unit}</span>}
          </div>
          {spark && <Sparkline values={spark} color={sparkColor || "var(--accent)"} width={64} height={26} />}
        </div>
        {children}
        {delta !== undefined && delta !== null && (
          <div className={"emm-kpi-delta mono " + (good ? "good" : "bad")}>
            <span className="arrow">{up ? "▲" : "▼"}</span> {Math.abs(delta)}%
            <span className="emm-kpi-delta-cap">{useT().t("vsPrev")}</span>
          </div>
        )}
      </div>
    );
  }

  // ---------- Breadcrumb -------------------------------------
  function Breadcrumb({ crumbs }) {
    return (
      <nav className="emm-crumbs mono" aria-label="breadcrumb">
        {crumbs.map((c, i) => (
          <span key={i} className="emm-crumb-wrap">
            {i > 0 && <span className="emm-crumb-sep">›</span>}
            {c.onClick && i < crumbs.length - 1 ? (
              <button className="emm-crumb link" onClick={c.onClick}>{c.label}</button>
            ) : (
              <span className={"emm-crumb" + (i === crumbs.length - 1 ? " current" : "")}>{c.label}</span>
            )}
          </span>
        ))}
      </nav>
    );
  }

  // ---------- Lens switch (L1..L5) ---------------------------
  const LENSES = [
    { id: "count", code: "L1", key: "L1", full: "L1full" },
    { id: "reach", code: "L2", key: "L2", full: "L2full" },
    { id: "duration", code: "L3", key: "L3", full: "L3full", rep: true },
    { id: "media", code: "L4", key: "L4", full: "L4full", rep: true },
    { id: "journalists", code: "L5", key: "L5", full: "L5full", rep: true },
  ];
  window.EMM_LENSES = LENSES;
  function LensSwitch({ lens, onLens }) {
    const { t } = useT();
    const active = LENSES.find((l) => l.id === lens) || LENSES[0];
    return (
      <div className="emm-lens">
        <div className="emm-lens-cap mono">{t("lensLabel")}</div>
        <div className="emm-lens-seg" role="tablist">
          {LENSES.map((l) => (
            <button key={l.id} role="tab" aria-selected={l.id === lens}
              className={"emm-lens-btn" + (l.id === lens ? " active" : "")}
              onClick={() => onLens(l.id)} title={t(l.full)}>
              <span className="mono code">{l.code}</span>
              <span className="name">{t(l.key)}</span>
              {l.rep && <span className="rep-dot" title={t("representative")} />}
            </button>
          ))}
        </div>
        <div className="emm-lens-desc mono">{t(active.full)}{active.rep && <em> · {t("representative")}</em>}</div>
      </div>
    );
  }

  // ---------- Time control -----------------------------------
  const TIMES = [
    { id: "today", key: "today", live: true },
    { id: "yesterday", key: "yesterday" },
    { id: "7d", key: "last7" },
    { id: "30d", key: "last30" },
  ];
  // relative day index → short date label (TODAY index = current date)
  function dayLabel(idx) {
    const d = new Date();
    d.setDate(d.getDate() - (E.TODAY - idx));
    return d.toLocaleDateString(undefined, { day: "2-digit", month: "short" });
  }
  function TimeControl({ time, onTime }) {
    const { t } = useT();
    const isCustom = typeof time === "string" && time.indexOf("custom:") === 0;
    const cr = isCustom ? E.customRange(time) : null;
    const [open, setOpen] = useState(false);
    const [from, setFrom] = useState(cr ? cr.from : Math.max(0, E.TODAY - 6));
    const [to, setTo] = useState(cr ? cr.to : E.TODAY);
    const wrapRef = useRef(null);
    useEffect(() => {
      if (!open) return;
      const onDoc = (e) => { if (wrapRef.current && !wrapRef.current.contains(e.target)) setOpen(false); };
      document.addEventListener("mousedown", onDoc);
      return () => document.removeEventListener("mousedown", onDoc);
    }, [open]);
    const dayOpts = Array.from({ length: E.DAYS }, (_, i) => i);
    function apply() {
      const a = Math.min(from, to), b = Math.max(from, to);
      onTime("custom:" + a + "-" + b);
      setOpen(false);
    }
    return (
      <div className="emm-time" role="tablist" ref={wrapRef} style={{ position: "relative" }}>
        {TIMES.map((tm) => (
          <button key={tm.id} role="tab" aria-selected={tm.id === time}
            className={"emm-time-btn" + (tm.id === time ? " active" : "")} onClick={() => onTime(tm.id)}>
            {tm.live && <span className="emm-live-dot" />}
            {t(tm.key)}
          </button>
        ))}
        <button className={"emm-time-btn ghost" + (isCustom ? " active" : "")} title={t("custom")}
          onClick={() => setOpen((o) => !o)}>
          {isCustom ? dayLabel(cr.from) + "–" + dayLabel(cr.to) : t("custom") + "…"}
        </button>
        {open && (
          <div className="emm-time-pop">
            <div className="emm-time-pop-title mono">{t("customRange")}</div>
            <div className="emm-time-pop-row">
              <label className="mono">{t("from")}
                <select className="emm-uselect mono" value={from} onChange={(e) => setFrom(+e.target.value)}>
                  {dayOpts.map((i) => <option key={i} value={i} disabled={i > to}>{dayLabel(i)}</option>)}
                </select>
              </label>
              <label className="mono">{t("to")}
                <select className="emm-uselect mono" value={to} onChange={(e) => setTo(+e.target.value)}>
                  {dayOpts.map((i) => <option key={i} value={i} disabled={i < from}>{dayLabel(i)}</option>)}
                </select>
              </label>
            </div>
            <div className="emm-time-pop-actions">
              <button className="emm-btn ghost mono" onClick={() => setOpen(false)}>{t("cancel")}</button>
              <button className="emm-btn accent mono" onClick={apply}>{t("apply")}</button>
            </div>
          </div>
        )}
      </div>
    );
  }

  // ---------- Toast (transient confirmation) -----------------
  function Toast({ msg }) {
    if (!msg) return null;
    return <div className="emm-toast mono" role="status">{msg}</div>;
  }

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

  // ---------- Number field (with unit + step) ----------------
  function NumField({ value, onChange, min, max, step = 1, unit, width = 78 }) {
    return (
      <span className="emm-numfield">
        <input type="number" className="emm-numinput mono" value={value == null ? "" : value} min={min} max={max} step={step} style={{ width }}
          onChange={(e) => { const v = e.target.value === "" ? "" : Number(e.target.value); onChange(v); }} />
        {unit && <span className="emm-numunit mono">{unit}</span>}
      </span>
    );
  }

  // ---------- Filter chip bar --------------------------------
  function FilterChips({ filters, onClear, onClearAll, lang }) {
    const { t } = useT();
    const chips = [];
    if (filters.channel) chips.push({ k: "channel", label: t("channel"), val: L(E.channel(filters.channel), lang) || E.channel(filters.channel).name });
    if (filters.topic) chips.push({ k: "topic", label: t("topic"), val: L(E.topic(filters.topic), lang) || E.topic(filters.topic).name });
    if (filters.sentiment) chips.push({ k: "sentiment", label: t("sentiment"), val: t(SENT_LABEL[filters.sentiment]) });
    if (filters.entity) chips.push({ k: "entity", label: t("department"), val: L(E.entity(filters.entity), lang) });
    if (filters.region) chips.push({ k: "region", label: t("region"), val: L(E.region(filters.region), lang) });
    if (filters.category) chips.push({ k: "category", label: t("category"), val: L(E.category(filters.category), lang) });
    if (filters.anchor) { const j = E.journalist(filters.anchor); chips.push({ k: "anchor", label: t("anchor"), val: j ? L({ en: j.name, hi: j.hi }, lang) : filters.anchor }); }
    if (filters.medium) chips.push({ k: "medium", label: t("medium"), val: filters.medium });
    if (filters.authenticity) chips.push({ k: "authenticity", label: t("dimAuthenticity"), val: t("auth" + filters.authenticity.charAt(0).toUpperCase() + filters.authenticity.slice(1)) });
    if (filters.q) chips.push({ k: "q", label: t("keyword"), val: filters.q });
    if (!chips.length) return null;
    return (
      <div className="emm-chipbar">
        <span className="emm-chipbar-cap mono">{t("filtered")}:</span>
        {chips.map((c) => (
          <button key={c.k} className="emm-chip" onClick={() => onClear(c.k)}>
            <span className="emm-chip-key mono">{c.label}</span>
            <span className="emm-chip-val">{c.val}</span>
            <span className="emm-chip-x">×</span>
          </button>
        ))}
        <button className="emm-chip-clear mono" onClick={onClearAll}>{t("clearFilter")}</button>
      </div>
    );
  }

  // ---------- Universal controls (search + region + dept) ----
  function UniversalControls({ q, onQ, onSubmit, region, onRegion, dept, onDept, lang }) {
    const { t } = useT();
    return (
      <div className="emm-ucontrols">
        <form className="emm-usearch" onSubmit={(e) => { e.preventDefault(); onSubmit(); }} role="search">
          <span className="emm-usearch-ico" aria-hidden="true">⌕</span>
          <input className="emm-usearch-input" type="search" value={q} placeholder={t("searchPlaceholder")}
            aria-label={t("searchPlaceholder")} onChange={(e) => onQ(e.target.value)} />
        </form>
        <label className="emm-uselect-wrap">
          <span className="emm-uselect-cap mono">{t("region")}</span>
          <select className="emm-uselect mono" value={region || ""} onChange={(e) => onRegion(e.target.value)}>
            <option value="">{t("allRegions")}</option>
            {E.REGIONS.map((r) => <option key={r.id} value={r.id}>{L(r, lang)}</option>)}
          </select>
        </label>
        <label className="emm-uselect-wrap">
          <span className="emm-uselect-cap mono">{t("department")}</span>
          <select className="emm-uselect mono" value={dept || ""} onChange={(e) => onDept(e.target.value)}>
            <option value="">{t("allDepts")}</option>
            {E.ENTITIES.map((en) => <option key={en.id} value={en.id}>{L(en, lang)}</option>)}
          </select>
        </label>
      </div>
    );
  }

  // ---------- Channel monogram logo --------------------------
  function ChannelLogo({ ch, size = 30 }) {
    if (!ch) return null;
    const txt = ch.name.replace(/[^A-Za-z0-9]/g, "").slice(0, 3).toUpperCase();
    const hue = (ch.id.charCodeAt(0) * 23) % 360;
    return (
      <span className="emm-logo mono" style={{
        width: size, height: size, fontSize: size * 0.3,
        background: `oklch(0.92 0.03 ${hue})`, color: `oklch(0.4 0.08 ${hue})`,
      }}>{txt}</span>
    );
  }

  // ---------- Alert card (high-reach negative) ---------------
  function AlertCard({ story, onOpen, lang }) {
    const { t } = useT();
    const topCh = story.airings.slice().sort((a, b) => b.reach - a.reach)[0];
    const vel = E.alertVelocity ? E.alertVelocity(story) : 0;
    return (
      <div className="emm-alert clickable" onClick={() => onOpen(story)} role="button" tabIndex={0}
        onKeyDown={(e) => { if (e.key === "Enter") onOpen(story); }}>
        <span className="emm-alert-bar" />
        <div className="emm-alert-body">
          <div className="emm-alert-top">
            <SentChip s="neg" />
            <span className="emm-alert-velocity mono">▲ +{vel}% <span className="win">/2h</span></span>
          </div>
          <div className="emm-alert-head">{L(story.headline, lang)}</div>
          <div className="emm-alert-meta mono">
            {L(story.topicName, lang)} · {E.channel(topCh.ch).name} · {topCh.time}
          </div>
          <div className="emm-alert-foot">
            <span className="emm-alert-reach mono"><span className="emm-alert-reach-cap">{t("highReach")}</span> {C.compact(story.reach)}</span>
            <span className="emm-alert-cta mono">{t("investigate")} →</span>
          </div>
        </div>
      </div>
    );
  }

  // ---------- Story list / table -----------------------------
  function StoryList({ rows, onRow, lang, lens, compact, showChannelCol = true }) {
    const { t } = useT();
    if (!rows.length) return <EmptyState />;
    return (
      <div className="emm-storylist">
        <div className={"emm-story-row head mono" + (compact ? " compact" : "")}>
          <span className="c-head">{t("headline")}</span>
          {showChannelCol && <span className="c-ch">{t("channel")}</span>}
          <span className="c-time">{t("time")}</span>
          <span className="c-dur">{t("duration")} · {t("frequency")}</span>
          <span className="c-sent">{t("sentiment")}</span>
          <span className="c-reach">{t("reach")}</span>
        </div>
        {rows.map((s) => {
          const topCh = s.airings.slice().sort((a, b) => b.reach - a.reach)[0];
          const reps = s.airings.reduce((x, a) => x + a.repeats, 0);
          return (
            <button key={s.id} className={"emm-story-row" + (compact ? " compact" : "")} onClick={() => onRow(s)}>
              <span className="c-head">
                {s.hot && <span className="emm-hot mono">HOT</span>}
                <span className="emm-story-id mono">{s.id}</span>
                {L(s.headline, lang)}
              </span>
              {showChannelCol && (
                <span className="c-ch">
                  <ChannelLogo ch={E.channel(topCh.ch)} size={20} />
                  {s.airings.length > 1 && <span className="mono emm-more">+{s.airings.length - 1}</span>}
                </span>
              )}
              <span className="c-time mono">{topCh.time}</span>
              <span className="c-dur mono">{C.dur(topCh.dur)} <span className="emm-story-freq">· {reps}×</span></span>
              <span className="c-sent"><SentDot s={s.sentiment} /></span>
              <span className="c-reach mono">{C.compact(s.reach)}</span>
            </button>
          );
        })}
      </div>
    );
  }

  // ---------- Journalist card --------------------------------
  function JournalistCard({ j, lang, count, reach, onClick }) {
    const { t } = useT();
    const ch = E.channel(j.ch);
    const initials = j.name.split(" ").map((w) => w[0]).join("").slice(0, 2);
    return (
      <button className={"emm-jcard" + (onClick ? " clickable" : "")} onClick={onClick}>
        <span className="emm-javatar mono">{initials}</span>
        <div className="emm-jbody">
          <div className="emm-jname">{L({ en: j.name, hi: j.hi }, lang)}</div>
          <div className="emm-jmeta mono">{j.role} · {ch.name}</div>
          <div className="emm-jstats mono">
            <span>{j.handle}</span>
            <span>{C.compact(j.followers)} {t("followers")}</span>
          </div>
        </div>
        {count != null && <div className="emm-jcount mono"><b>{count}</b><span>{t("items")}</span></div>}
      </button>
    );
  }

  // ---------- Clip player (animated mock) --------------------
  function ClipPlayer({ story, airing, lang }) {
    const { t } = useT();
    const dur = airing.dur;
    const [playing, setPlaying] = useState(false);
    const [pos, setPos] = useState(0); // seconds
    const raf = useRef(null), last = useRef(0);
    const scriptRef = useRef(null);

    useEffect(() => {
      if (!playing) return;
      last.current = performance.now();
      const tick = (now) => {
        const dt = (now - last.current) / 1000;
        last.current = now;
        setPos((p) => {
          const np = p + dt * 4; // 4x speed for demo
          if (np >= dur) { setPlaying(false); return dur; }
          return np;
        });
        raf.current = requestAnimationFrame(tick);
      };
      raf.current = requestAnimationFrame(tick);
      return () => cancelAnimationFrame(raf.current);
    }, [playing, dur]);

    const lines = story.transcript;
    const lastVisible = lines[lines.length - 1].t;
    const activeIdx = lines.reduce((acc, l, i) => (pos >= (l.t / lastVisible) * dur ? i : acc), 0);

    useEffect(() => {
      if (scriptRef.current && playing) {
        const el = scriptRef.current.querySelector(".active");
        if (el) {
          const box = scriptRef.current;
          box.scrollTop = el.offsetTop - box.clientHeight / 2 + el.clientHeight / 2;
        }
      }
    }, [activeIdx, playing]);

    const pct = (pos / dur) * 100;
    const ch = E.channel(airing.ch);
    const fmtTime = (s) => `${String(Math.floor(s / 60)).padStart(2, "0")}:${String(Math.floor(s % 60)).padStart(2, "0")}`;

    return (
      <div className="emm-clip">
        <div className="emm-clip-video">
          <div className="emm-clip-ph" aria-hidden="true">
            <div className="emm-clip-stripes" />
            <span className="mono emm-clip-phlabel">captured clip · {ch.name}</span>
          </div>
          <div className="emm-clip-chrome">
            <span className="emm-clip-badge mono"><span className="emm-live-dot" />{ch.name}</span>
            <span className="emm-clip-badge mono lower">{airing.daypart} · {airing.time}</span>
          </div>
          <button className={"emm-clip-play" + (playing ? " playing" : "")} onClick={() => setPlaying((p) => !p)}>
            {playing ? "❚❚" : "▶"}
          </button>
        </div>
        <div className="emm-clip-scrub">
          <button className="emm-clip-mini" onClick={() => setPlaying((p) => !p)}>{playing ? "❚❚" : "▶"}</button>
          <div className="emm-clip-bar" onClick={(e) => {
            const r = e.currentTarget.getBoundingClientRect();
            setPos(((e.clientX - r.left) / r.width) * dur);
          }}>
            <div className="emm-clip-fill" style={{ width: pct + "%" }} />
            <div className="emm-clip-knob" style={{ left: pct + "%" }} />
          </div>
          <span className="mono emm-clip-time">{fmtTime(pos)} / {fmtTime(dur)}</span>
        </div>
        <div className="emm-clip-transcript" ref={scriptRef}>
          {lines.map((l, i) => (
            <p key={i} className={"emm-tline" + (i === activeIdx ? " active" : "") + (l.match ? " matched" : "")}>
              <span className="mono emm-tline-t">{fmtTime((l.t / lastVisible) * dur)}</span>
              <span className="emm-tline-txt">
                {L(l, lang)}
                {l.match && <span className="emm-matched-tag mono">{t("dprMatched")}</span>}
              </span>
            </p>
          ))}
        </div>
      </div>
    );
  }

  // ---------- Empty / coming states --------------------------
  function EmptyState({ title, sub }) {
    const { t } = useT();
    return (
      <div className="emm-empty">
        <div className="emm-empty-mark mono">∅</div>
        <div className="emm-empty-title">{title || t("noData")}</div>
        <div className="emm-empty-sub">{sub || t("noDataSub")}</div>
      </div>
    );
  }
  function ComingState({ title }) {
    const { t } = useT();
    return (
      <div className="emm-coming">
        <div className="emm-coming-grid" />
        <div className="emm-coming-tag mono">{t("coming")}</div>
        <div className="emm-coming-title">{title}</div>
        <div className="emm-coming-sub">{t("comingSub")}</div>
      </div>
    );
  }

  // ---------- Loading skeleton -------------------------------
  function Skeleton({ h = 16, w = "100%", r = 4 }) {
    return <div className="emm-skel" style={{ height: h, width: w, borderRadius: r }} />;
  }

  // ---------- Stat strip (label/value inline) ----------------
  function StatStrip({ items }) {
    return (
      <div className="emm-statstrip">
        {items.map((it, i) => (
          <div key={i} className="emm-statstrip-item">
            <div className="emm-statstrip-label mono">{it.label}</div>
            <div className="emm-statstrip-value mono">{it.value}</div>
          </div>
        ))}
      </div>
    );
  }

  Object.assign(window, {
    Panel, SentDot, SentChip, KPIStat, Breadcrumb, LensSwitch, TimeControl,
    FilterChips, UniversalControls, ChannelLogo, AlertCard, StoryList, JournalistCard, ClipPlayer,
    EmptyState, ComingState, Skeleton, StatStrip, Toast, Toggle, NumField, useEmmT: useT,
  });
})();
