/* global React, ReactDOM, IcoArrowRight, IcoChevronDown, IcoChevronUp, IcoExternalLink, IcoShareUpRight, IcoNewspaper, IcoSuitcase, IcoClipboard, IcoBookOpen, IcoMoreHorizontal, IcoThumbsUp, IcoThumbsDown, IcoSun, IcoMoon, IcoSparkles, IcoSearch, NF_TYPES, NF_EVENTS, NF_FAVICON */

const { useState, useEffect, useRef } = React;

const TYPE_HUE = {
  news: "var(--dot-news)",
  career_change: "var(--dot-career)",
  job_listing: "var(--dot-job)",
};
const COMPANY = "Recorded Future";
const initialsOf = (name) => name.split(" ").map(s => s[0]).slice(0, 2).join("");

const SIG_STYLES = null;
const STAKE_STYLES = [
  { id: "v1", key: "Vivid" }, { id: "v2", key: "Strong" }, { id: "v3", key: "Mid" },
  { id: "v4", key: "Light" }, { id: "v5", key: "Pale" },
];
const CAREER_CTA_STYLES = [
  { id: "track", key: "Track" }, { id: "track2", key: "Track2" },
];
const SIG_FILTER = document.documentElement.hasAttribute("data-sig-filter");

function buildSignalIndex(events) {
  const map = new Map();
  for (const ev of events) {
    for (const name of ev.signals || []) {
      const entry = map.get(name) || { name, count: 0, types: new Set() };
      entry.count += 1;
      entry.types.add(ev.type);
      map.set(name, entry);
    }
  }
  return [...map.values()].sort((a, b) => b.count - a.count || a.name.localeCompare(b.name));
}

function signalPrimaryType(types) {
  if (types.has("news")) return "news";
  if (types.has("job_listing")) return "job_listing";
  if (types.has("career_change")) return "career_change";
  return null;
}

function signalTypeIcon(types, size = 16) {
  const type = signalPrimaryType(types);
  if (!type) return null;
  const icons = {
    news: <IcoNewspaper size={size} />,
    job_listing: <IcoClipboard size={size} />,
    career_change: <IcoSuitcase size={size} />,
  };
  return (
    <span className={"sig-filter-icon sig-filter-icon--" + type}>
      {icons[type]}
    </span>
  );
}

function SignalFilter({ events, selected, onToggle, onClear }) {
  const [open, setOpen] = useState(false);
  const [query, setQuery] = useState("");
  const ref = useRef(null);
  const signals = buildSignalIndex(events);
  const filtered = signals.filter(s => s.name.toLowerCase().includes(query.toLowerCase().trim()));

  useEffect(() => {
    const close = (e) => { if (ref.current && !ref.current.contains(e.target)) setOpen(false); };
    if (open) document.addEventListener("mousedown", close);
    return () => document.removeEventListener("mousedown", close);
  }, [open]);

  const label = selected.size === 0
    ? "All Signals"
    : selected.size === 1
      ? [...selected][0]
      : `${selected.size} signals`;

  const firstSelected = selected.size > 0 ? signals.find(s => selected.has(s.name)) : null;

  return (
    <div className="filter-bar">
      <div className="filter-popover-wrap" ref={ref}>
        <button
          type="button"
          className={"filter-dropdown" + (open ? " open" : "") + (selected.size > 0 ? " has-selection" : "")}
          onClick={() => setOpen(o => !o)}
          aria-expanded={open}
        >
          {firstSelected && signalTypeIcon(firstSelected.types, 14)}
          <span className="label">{label}</span>
          <span className="filter-chev" aria-hidden="true"><IcoChevronDown size={16} /></span>
        </button>
        {open && (
          <div className="acct-popover sig-popover open" role="dialog" aria-label="Filter by signals">
            <div className="acct-search-wrap">
              <IcoSearch size={16} />
              <input
                className="acct-search-input"
                type="text"
                placeholder="Search signals..."
                value={query}
                onChange={(e) => setQuery(e.target.value)}
                autoFocus
              />
            </div>
            <div className="acct-list">
              {filtered.map(s => {
                const checked = selected.has(s.name);
                return (
                  <div
                    key={s.name}
                    className={"acct-item" + (checked ? " checked" : "")}
                    onClick={() => onToggle(s.name)}
                    role="option"
                    aria-selected={checked}
                  >
                    <div className="acct-cb">
                      <svg xmlns="http://www.w3.org/2000/svg" width="10" height="10" viewBox="0 0 24 24" fill="none" stroke="white" strokeWidth="3" strokeLinecap="round" strokeLinejoin="round"><path d="M20 6 9 17l-5-5" /></svg>
                    </div>
                    {signalTypeIcon(s.types)}
                    <span className="acct-name">{s.name}</span>
                    <span className="acct-count">{s.count}</span>
                  </div>
                );
              })}
            </div>
          </div>
        )}
      </div>
      {selected.size > 0 && (
        <button type="button" className="filter-clear" onClick={onClear}>
          Clear filters
        </button>
      )}
    </div>
  );
}

function Av({ person }) {
  const [broken, setBroken] = useState(false);
  const cls = "opt-av" + (person.big ? " big" : "");
  const fbCls = "opt-av-fb" + (person.big ? " big" : "") + " " + (person.tone || "");
  if (person.photo && !broken) {
    return <img className={cls} src={person.photo} alt="" loading="lazy" decoding="async" onError={() => setBroken(true)} />;
  }
  return <span className={fbCls}>{person.initials || initialsOf(person.name)}</span>;
}

function Overflow({ event }) {
  const [open, setOpen] = useState(false);
  const ref = useRef(null);
  useEffect(() => {
    const f = (e) => { if (ref.current && !ref.current.contains(e.target)) setOpen(false); };
    if (open) document.addEventListener("mousedown", f);
    return () => document.removeEventListener("mousedown", f);
  }, [open]);
  return (
    <div className="of" ref={ref}>
      <button className="btn" onClick={() => setOpen(o => !o)} aria-label="More"><IcoMoreHorizontal /></button>
      {open && (
        <div className="pop">
          {event.case_studies && <button onClick={() => setOpen(false)}><IcoBookOpen /> Related case studies</button>}
          <a href={event.sourceUrl} onClick={() => setOpen(false)}><IcoShareUpRight /> View source</a>
          <hr />
          <button onClick={() => setOpen(false)}><IcoThumbsUp /> Useful</button>
          <button onClick={() => setOpen(false)}><IcoThumbsDown /> Not relevant</button>
        </div>
      )}
    </div>
  );
}

function Actor({ event }) {
  const [broken, setBroken] = useState(false);
  return (
    <div className="actor">
      {!broken ? (
        <img className="actor-logo" src={NF_FAVICON(event.account.host)} alt="" loading="lazy" decoding="async" onError={() => setBroken(true)} />
      ) : (
        <span className="actor-logo-fb">{event.account.initials}</span>
      )}
      <div className="actor-main">
        <div className="actor-line">
          <a href="#" className="actor-name">{event.account.name}</a>
          <div className="actor-sigs">
            <span className="sig sig-type">{event.type === "news" && <IcoNewspaper size={12} />}{event.type === "career_change" && <IcoSuitcase size={12} />}{event.type === "job_listing" && <IcoClipboard size={12} />}{NF_TYPES[event.type].short}</span>
            {(event.signals || []).map((s, i) => <span className="sig" key={i}>{s}</span>)}
          </div>
        </div>
        <div className="actor-sub">
          <a href={event.sourceUrl}>{event.publication}</a>
          <span className="dot-sep">·</span>Discovered {event.discovered} ago
        </div>
      </div>
      <Overflow event={event} />
    </div>
  );
}

function Anchor({ event }) {
  const a = event.anchor;
  if (event.type === "career_change") {
    return (
      <div className="cstory">
        <Av person={a.person} />
        <div className="cstory-main">
          <div className="cstory-name">{a.person.name}</div>
          <div className="cstory-move">
            <span className="mv">{a.moveVerb} {a.moveDate}</span>
            <IcoArrowRight className="mv-arrow" size={14} />
            <span className="to">{a.to}</span>
          </div>
          <div className="cstory-prev">{a.prev}</div>
        </div>
      </div>
    );
  }
  if (event.type === "job_listing") {
    return (
      <div className="jv spotlight">
        <h2 className="title">{a.summary || a.title}</h2>
        {a.date && <div className="anchor-meta">{a.date}</div>}
      </div>
    );
  }
  return (
    <div className="nv spotlight">
      <h2 className="headline">{a.headline || a.title}</h2>
      {a.date && <div className="anchor-meta">{a.date}</div>}
    </div>
  );
}

function SectionLabel({ children }) {
  return (
    <div className="angle-label">
      <span className="wl-bar" />
      <span className="wl-dot" />
      <IcoSparkles className="wl-ico" size={13} />
      <span className="wl-txt">{children}</span>
    </div>
  );
}

function Angle({ angle }) {
  if (!angle) return null;
  return (
    <div className="angle">
      <SectionLabel>Why it matters</SectionLabel>
      <p dangerouslySetInnerHTML={{ __html: angle.why }} />
    </div>
  );
}

/* (2) Stakeholders — own section. `variant` controls how the per-person
   Reach out + Deep research actions are presented (10 options). */
function PersonBits({ p }) {
  return (
    <>
      <Av person={p} />
      <div className="stake-info">
        <div className="stake-name">{p.name}</div>
        <div className="stake-role">{p.title}</div>
      </div>
    </>
  );
}

function RowKebab() {
  const [open, setOpen] = useState(false);
  const ref = useRef(null);
  useEffect(() => {
    const f = (e) => { if (ref.current && !ref.current.contains(e.target)) setOpen(false); };
    if (open) document.addEventListener("mousedown", f);
    return () => document.removeEventListener("mousedown", f);
  }, [open]);
  return (
    <div className="of" ref={ref}>
      <button className="btn" onClick={() => setOpen(o => !o)} aria-label="More"><IcoMoreHorizontal /></button>
      {open && (
        <div className="pop">
          <button onClick={() => setOpen(false)}><IcoResearch /> Deep research</button>
          <button onClick={() => setOpen(false)}><IcoBookOpen /> Add to sequence</button>
        </div>
      )}
    </div>
  );
}

function Stakeholders({ people, variant }) {
  if (!people || people.length === 0) return null;
  const count = people.length === 1 ? "Stakeholder" : people.length + " stakeholders";
  // All variants are the "filled" layout; only the Reach out button's color
  // intensity changes (v1 most vibrant → v5 faintest). Deep research is constant.
  const rv = ({ v1: "rv1", v2: "rv2", v3: "rv3", v4: "rv4", v5: "rv5" })[variant] || "rv1";
  return (
    <div className="stakes">
      <SectionLabel>{count}</SectionLabel>
      <div className="stake-list">
        {people.map(p => (
          <div className="stake" key={p.id}>
            <PersonBits p={p} />
            <div className="stake-cta">
              <a className="cta sm dr" href="#"><IcoResearch /> Deep research</a>
              <a className={"cta sm " + rv} href="#">Reach out <IcoArrowRight /></a>
            </div>
          </div>
        ))}
      </div>
    </div>
  );
}

/* Career: the person IS the single stakeholder. Every variant renders the
   exact same stakeholder row (avatar + name + new role on the left, Deep
   research + Reach out on the right, identical to multi-stakeholder cards),
   and adds the detected career-transition info above it — or grows the row's
   left side — in different ways. CTAs never move. */
function CareerBody({ event }) {
  const a = event.anchor;
  const sp = { name: a.person.name, photo: a.person.photo, initials: a.person.initials, tone: a.person.tone, title: a.to };
  const ctas = (
    <div className="stake-cta">
      <a className="cta sm dr" href="#"><IcoResearch /> Deep research</a>
      <a className="cta sm rv2" href="#">Reach out <IcoArrowRight /></a>
    </div>
  );
  const angle = <Angle angle={event.angle} />;
  const row = (
    <div className="stake career-row">
      <PersonBits p={sp} />
      {ctas}
    </div>
  );
  // Career body is locked to Track2 (narrative + smaller previously line).
  const narrative = (
    <>
      <div className="cn-narrative">
        <span className="cn-move">{a.moveVerb} {a.moveDate}</span>
        <IcoArrowRight className="cn-arrow" size={15} />
        <span className="cn-role">{a.to}</span>
      </div>
      {a.prev && <div className="cn-prevline">{a.prev}</div>}
    </>
  );
  return (<><div className="cn-spot">{narrative}</div>{row}{angle}</>);
}

/* (1)(3) Collapsible "Where {company} fits", placed under stakeholders. */
function WhereFits({ fits }) {
  const [open, setOpen] = useState(false);
  return (
    <div className="fits-sec">
      <div className="fits-toggle" onClick={() => setOpen(o => !o)}>
        <SectionLabel>Where {COMPANY} fits</SectionLabel>
        <IcoChevronDown className={"fits-chev" + (open ? " open" : "")} size={14} />
      </div>
      {open && (
        <p className="fit-body"><strong className="fit-name">{fits.name}</strong> {fits.body}</p>
      )}
    </div>
  );
}

function Card({ event, stake }) {
  const isCareer = event.type === "career_change";
  const fits = event.angle && event.angle.fits;
  return (
    <article className="card" data-type={event.type} style={{ "--sig-hue": TYPE_HUE[event.type] }}>
      <Actor event={event} />
      {isCareer ? (
        <CareerBody event={event} />
      ) : (
        <>
          <Anchor event={event} />
          <Angle angle={event.angle} />
          <Stakeholders people={event.stakeholders} variant={stake} />
          {fits && <WhereFits fits={fits} />}
        </>
      )}
    </article>
  );
}

function App() {
  const [stake, setStake] = useState("v2");
  const [careerCta, setCareerCta] = useState("track2");
  const [theme, setTheme] = useState("light");
  const [font, setFont] = useState(document.documentElement.getAttribute("data-font") || "polymath");
  const [sigFilter, setSigFilter] = useState(() => new Set());

  useEffect(() => {
    const r = document.documentElement;
    r.setAttribute("data-theme", theme);
    r.setAttribute("data-density", "cozy");
    r.setAttribute("data-sigstyle", "3"); // locked: outline signal pills
    r.setAttribute("data-wlstyle", "1");   // locked: medium label shade
    r.setAttribute("data-font", font);
    r.setAttribute("data-palette", "new");
  }, [theme, font]);

  const order = [
    "ev-scaleai", "ev-zoominfo", "ev-ramp", "ev-snyk", "ev-datadog",
    "ev-rippling", "ev-anthropic", "ev-cresta", "ev-personio", "ev-salesforce", "ev-figma", "ev-otter",
  ];
  const byId = Object.fromEntries(NF_EVENTS.map(e => [e.id, e]));
  const feed = order.map(id => byId[id]).filter(Boolean);
  const visibleFeed = !SIG_FILTER || sigFilter.size === 0
    ? feed
    : feed.filter(e => (e.signals || []).some(s => sigFilter.has(s)));

  const toggleSigFilter = (name) => {
    setSigFilter(prev => {
      const next = new Set(prev);
      if (next.has(name)) next.delete(name);
      else next.add(name);
      return next;
    });
  };

  const clearSigFilter = () => setSigFilter(new Set());

  const Switch = ({ options, value, set }) => (
    <div className="opt-switch">
      {options.map(o => o.href
        ? <a key={o.id} className="sw-link" href={o.href}>{o.key}</a>
        : <button key={o.id} className={value === o.id ? "on" : ""} onClick={() => set(o.id)}>{o.key}</button>
      )}
    </div>
  );

  return (
    <div className="app" style={{ gridTemplateColumns: "1fr" }}>
      <main className="main">
        <div className="feed-controls">
          <div className="ctl-row">
            <span className="rowlbl">Theme</span>
            <Switch options={[
              { id: "light", key: <span className="sw-lbl"><IcoSun size={13} />Light</span> },
              { id: "dark",  key: <span className="sw-lbl"><IcoMoon size={13} />Dark</span> },
            ]} value={theme} set={setTheme} />
          </div>
          <div className="ctl-row">
            <span className="rowlbl">Font</span>
            <Switch options={[{ id: "polymath", key: "Polymath" }, { id: "system", key: "System" }]} value={font} set={setFont} />
          </div>
          <div className="ctl-row">
            <span className="rowlbl">View</span>
            <Switch value="newsfeed" set={() => {}} options={[
              { id: "newsfeed", key: "Newsfeed" },
              { id: "people",   key: "People",   href: "table.html?tab=people" },
              { id: "accounts", key: "Accounts", href: "table.html?tab=accounts" },
            ]} />
          </div>
        </div>

        <div className="feed" style={{ maxWidth: 680, margin: "0 auto", width: "100%", padding: "16px 24px 56px" }}>
          {SIG_FILTER && (
            <SignalFilter events={feed} selected={sigFilter} onToggle={toggleSigFilter} onClear={clearSigFilter} />
          )}
          <div className="cards">
            {visibleFeed.map(e => <Card key={e.id} event={e} stake={stake} />)}
          </div>
        </div>
      </main>
    </div>
  );
}

ReactDOM.createRoot(document.getElementById("root")).render(<App />);
