/* ============================================================
   Shared primitives — filters, KPI strip, badges, controls,
   the reusable Deal table. Globals via window.
   ============================================================ */
const { useState, useRef, useEffect } = React;

/* ---------- global filter logic ---------- */
function applyGlobalFilters(deals, f) {
  const q = (f.search || '').trim().toLowerCase();
  return deals.filter((d) => {
    if (f.quarters.length && !f.quarters.includes(d.quarter)) return false;
    if (f.tier !== 'all' && !d.tiers.includes(f.tier)) return false;
    if (f.sectors.length && !f.sectors.includes(d.sector)) return false;
    if (f.countries.length && !f.countries.includes(d.country)) return false;
    if (q) {
      const hay = (d.name + ' ' + d.buyer + ' ' + d.seller + ' ' + d.sector + ' ' +
        d.country + ' ' + d.advisorsSell.join(' ') + ' ' + d.advisorsBuy.join(' ')).toLowerCase();
      if (!hay.includes(q)) return false;
    }
    return true;
  });
}

/* ---------- small controls ---------- */
function Segmented({ value, onChange, options }) {
  return (
    <div style={{ display: 'inline-flex', background: 'var(--surface-deep)', borderRadius: 7, padding: 2, gap: 2 }}>
      {options.map((o) => {
        const active = value === o.value;
        return (
          <button key={o.value} onClick={() => onChange(o.value)}
            style={{
              border: 'none', background: active ? 'var(--surface-card)' : 'transparent',
              color: active ? 'var(--ink)' : 'var(--ink-soft)', fontWeight: 600, fontSize: 12,
              padding: '5px 11px', borderRadius: 5, cursor: 'pointer',
              boxShadow: active ? '0 1px 2px rgba(0,0,0,.08)' : 'none', transition: 'all .12s',
            }}>{o.label}</button>
        );
      })}
    </div>
  );
}

function useOutside(ref, onClose) {
  useEffect(() => {
    const h = (e) => { if (ref.current && !ref.current.contains(e.target)) onClose(); };
    document.addEventListener('mousedown', h);
    return () => document.removeEventListener('mousedown', h);
  }, []);
}

function MultiSelect({ label, options, value, onChange, allLabel = 'All', width = 'auto', icon }) {
  const [open, setOpen] = useState(false);
  const ref = useRef();
  useOutside(ref, () => setOpen(false));
  const toggle = (o) => onChange(value.includes(o) ? value.filter((x) => x !== o) : [...value, o]);
  const summary = value.length === 0 ? allLabel : value.length === 1 ? value[0] : `${value.length} selected`;
  return (
    <div ref={ref} style={{ position: 'relative' }}>
      <button className="btn sm" onClick={() => setOpen((o) => !o)}
        style={{ height: 32, gap: 6, borderColor: value.length ? 'var(--accent)' : 'var(--line)', color: value.length ? 'var(--accent)' : 'var(--ink-muted)' }}>
        {icon && <Icon name={icon} size={14} />}
        <span style={{ fontWeight: 600 }}>{label}{value.length ? ':' : ''}</span>
        <span style={{ fontWeight: 600, color: 'var(--ink)' }}>{value.length ? summary : ''}</span>
        <Icon name="chevronDown" size={13} style={{ opacity: .6 }} />
      </button>
      {open && (
        <div className="card" style={{ position: 'absolute', top: 38, left: 0, zIndex: 40, minWidth: 190, maxHeight: 280, overflow: 'auto', padding: 5, boxShadow: 'var(--shadow-pop)' }}>
          <button onClick={() => onChange([])} style={menuItemStyle(value.length === 0)}>
            <span style={{ width: 14 }}>{value.length === 0 && <Icon name="check" size={13} />}</span>{allLabel}
          </button>
          <div style={{ height: 1, background: 'var(--line-soft)', margin: '4px 0' }}></div>
          {options.map((o) => (
            <button key={o} onClick={() => toggle(o)} style={menuItemStyle(value.includes(o))}>
              <span style={{ width: 14 }}>{value.includes(o) && <Icon name="check" size={13} />}</span>{o}
            </button>
          ))}
        </div>
      )}
    </div>
  );
}
function menuItemStyle(active) {
  return {
    display: 'flex', alignItems: 'center', gap: 7, width: '100%', textAlign: 'left',
    border: 'none', background: active ? 'var(--accent-soft)' : 'transparent',
    color: active ? 'var(--accent)' : 'var(--ink-muted)', fontWeight: active ? 600 : 500,
    fontSize: 12.5, padding: '6px 8px', borderRadius: 5, cursor: 'pointer',
  };
}

/* ---------- KPI strip ---------- */
function KpiCell({ label, value, sub, delta, accent, onClick, active, hint, invert }) {
  const good = invert ? delta <= 0 : delta >= 0;
  return (
    <button onClick={onClick} disabled={!onClick}
      className="card"
      style={{
        flex: 1, minWidth: 0, textAlign: 'left', padding: '13px 15px 14px', cursor: onClick ? 'pointer' : 'default',
        background: active ? 'var(--accent-soft)' : 'var(--surface-card)',
        borderColor: active ? 'var(--accent)' : 'var(--line)', position: 'relative', transition: 'all .12s',
      }}
      onMouseEnter={(e) => { if (onClick && !active) e.currentTarget.style.borderColor = '#c4c6c8'; }}
      onMouseLeave={(e) => { if (onClick && !active) e.currentTarget.style.borderColor = 'var(--line)'; }}>
      <div className="micro" style={{ marginBottom: 7 }}>{label}</div>
      <div style={{ display: 'flex', alignItems: 'baseline', gap: 8 }}>
        <span className="tabular" style={{ fontSize: 27, fontWeight: 700, lineHeight: 1, color: accent ? 'var(--accent)' : 'var(--ink)' }}>{value}</span>
        {delta != null && (
          delta === 0
            ? <span style={{ fontSize: 11.5, fontWeight: 700, color: 'var(--ink-faint)' }}>±0{hint === 'pp' ? 'pp' : hint === 'pct' ? '%' : ''}</span>
            : <span style={{ display: 'inline-flex', alignItems: 'center', gap: 2, fontSize: 11.5, fontWeight: 700, color: good ? 'var(--positive)' : 'var(--danger)' }}>
                <Icon name={delta >= 0 ? 'arrowUp' : 'arrowDown'} size={12} stroke={2.2} />{Math.abs(delta)}{hint === 'pp' ? 'pp' : hint === 'pct' ? '%' : ''}
              </span>
        )}
      </div>
      {sub && <div style={{ fontSize: 11.5, color: 'var(--ink-soft)', marginTop: 6, fontWeight: 500 }}>{sub}</div>}
      {onClick && <div style={{ position: 'absolute', right: 11, top: 12, color: 'var(--ink-faint)' }}><Icon name="chevronRight" size={14} /></div>}
    </button>
  );
}

/* ---------- badges ---------- */
function FitBadge({ fit }) {
  return <span className="fit" style={fitBadgeStyle(fit)}>{fit}/5</span>;
}
function fitBadgeStyle(fit) {
  const c = DATA.fitClass(fit);
  const map = {
    positive: ['var(--positive-soft)', 'var(--positive)'],
    warn: ['var(--warn-soft)', 'var(--warn)'],
    orange: ['var(--orange-soft)', 'var(--orange)'],
    danger: ['var(--danger-soft)', 'var(--danger)'],
  }[c];
  return { background: map[0], color: map[1] };
}
function SeenMark({ seen }) {
  return seen
    ? <span title="Seen before going public" style={{ display: 'inline-flex', color: 'var(--positive)' }}><Icon name="check" size={15} stroke={2.4} /></span>
    : <span title="Not on our radar" style={{ display: 'inline-flex', color: 'var(--danger)', opacity: .85 }}><Icon name="x" size={14} stroke={2.2} /></span>;
}
function TierTag({ tier }) {
  if (!tier) return <span style={{ color: 'var(--ink-faint)' }}>n/a</span>;
  const cls = tier === 'core' ? 'accent' : tier === 'buyout' ? '' : 'warn';
  return <span className={'badge ' + cls}>{DATA.tierLabel(tier)}</span>;
}

/* ---------- the reusable Deal table ---------- */
function dealColumns(opts = {}) {
  const cols = [
    { key: 'seenBefore', label: 'Seen', w: 46, align: 'center', sortable: true, render: (d) => <SeenMark seen={d.seenBefore} /> },
    { key: 'name', label: 'Deal', w: 188, render: (d) => (
        <div style={{ minWidth: 0 }}>
          <div style={{ fontWeight: 600, color: 'var(--ink)', whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>{d.name}</div>
          <div style={{ fontSize: 11, color: 'var(--ink-soft)', whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>{d.sector} · {d.country}</div>
        </div>) },
    { key: 'fit', label: 'Fit', w: 56, align: 'center', sortable: true, render: (d) => <FitBadge fit={d.fit} /> },
    { key: 'fte', label: 'FTE', w: 56, align: 'right', sortable: true, cls: 'tabular', render: (d) => d.fte },
    { key: 'date', label: 'Date', w: 86, sortable: true, cls: 'tabular', render: (d) => d.date },
  ];
  if (opts.winner) {
    cols.push({ key: 'winner', label: 'Winner', w: 150, render: (d) => (
      <span style={{ display: 'inline-flex', alignItems: 'center', gap: 6 }}>
        {d.winnerTier === 'core' && <span style={{ width: 6, height: 6, borderRadius: 9, background: 'var(--danger)' }}></span>}
        <span style={{ fontWeight: 600, color: d.winnerTier === 'core' ? 'var(--danger)' : 'var(--ink)' }}>{d.winner || 'None'}</span>
      </span>) });
  } else {
    cols.push({ key: 'buyer', label: 'Buyer', w: 150, render: (d) => <CompCell name={d.buyer} compId={d.buyerCompId} /> });
    cols.push({ key: 'seller', label: 'Seller', w: 132, render: (d) => <span style={{ color: 'var(--ink-muted)', whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis', display: 'block', maxWidth: 132 }}>{d.seller}</span> });
  }
  cols.push({ key: 'dealSize', label: 'Size', w: 92, align: 'right', sortable: true, cls: 'tabular',
    render: (d) => <span style={{ color: d.dealSize == null ? 'var(--ink-faint)' : 'var(--ink)' }}>{DATA.fmtSize(d.dealSize)}</span> });
  cols.push({ key: 'advisors', label: 'Advisors', w: 150, render: (d) => {
    const a = [...d.advisorsSell, ...d.advisorsBuy];
    if (!a.length) return <span style={{ color: 'var(--ink-faint)' }}>None</span>;
    return <span style={{ color: 'var(--ink-muted)', whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis', display: 'block', maxWidth: 150 }}>{a[0]}{a.length > 1 ? ` +${a.length - 1}` : ''}</span>;
  } });
  return opts.filter ? cols.filter(opts.filter) : cols;
}

function CompCell({ name, compId }) {
  return (
    <span style={{ display: 'inline-flex', alignItems: 'center', gap: 6, maxWidth: 150 }}>
      {compId && <span title="Tracked competitor" style={{ width: 5, height: 5, borderRadius: 9, background: 'var(--accent)', flexShrink: 0 }}></span>}
      <span style={{ fontWeight: compId ? 600 : 500, color: compId ? 'var(--ink)' : 'var(--ink-muted)', whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>{name}</span>
    </span>
  );
}

function sortDeals(deals, sort) {
  const { key, dir } = sort;
  const m = dir === 'asc' ? 1 : -1;
  const val = (d) => {
    if (key === 'dealSize') return d.dealSize == null ? -1 : d.dealSize;
    if (key === 'name' || key === 'winner' || key === 'buyer' || key === 'seller') return (d[key] || '').toLowerCase();
    if (key === 'advisors') return d.advisorsSell.length + d.advisorsBuy.length;
    if (key === 'seenBefore') return d.seenBefore ? 1 : 0;
    return d[key];
  };
  return [...deals].sort((a, b) => {
    const x = val(a), y = val(b);
    if (x < y) return -1 * m; if (x > y) return 1 * m;
    return b.fit - a.fit;
  });
}

function DealTable({ deals, columns, sort, onSort, onRowClick, expandedId, renderExpanded, dense }) {
  return (
    <table className="tbl">
      <thead>
        <tr>
          {columns.map((c) => {
            const isSorted = sort && sort.key === c.key;
            return (
              <th key={c.key} className={(c.align === 'right' ? 'num ' : '') + (c.sortable ? 'sortable' : '')}
                style={{ width: c.w, textAlign: c.align === 'center' ? 'center' : c.align === 'right' ? 'right' : 'left' }}
                onClick={() => c.sortable && onSort && onSort(c.key)}>
                <span style={{ display: 'inline-flex', alignItems: 'center', gap: 3, justifyContent: c.align === 'right' ? 'flex-end' : 'flex-start' }}>
                  {c.label}
                  {isSorted && <Icon name={sort.dir === 'asc' ? 'chevronUp' : 'chevronDown'} size={12} style={{ color: 'var(--accent)' }} />}
                </span>
              </th>
            );
          })}
        </tr>
      </thead>
      <tbody>
        {deals.map((d) => (
          <React.Fragment key={d.id}>
            <tr className={onRowClick ? 'clickable' : ''} onClick={() => onRowClick && onRowClick(d)}
              style={expandedId === d.id ? { background: 'var(--accent-soft)' } : null}>
              {columns.map((c) => (
                <td key={c.key} className={(c.align === 'right' ? 'num ' : '') + (c.cls || '')}
                  style={{ textAlign: c.align === 'center' ? 'center' : c.align === 'right' ? 'right' : 'left', padding: dense ? '7px 12px' : '9px 12px' }}>
                  {c.render(d)}
                </td>
              ))}
            </tr>
            {expandedId === d.id && renderExpanded && (
              <tr>
                <td colSpan={columns.length} style={{ padding: 0, background: 'var(--surface)' }}>{renderExpanded(d)}</td>
              </tr>
            )}
          </React.Fragment>
        ))}
        {deals.length === 0 && (
          <tr><td colSpan={columns.length} style={{ textAlign: 'center', padding: '34px 0', color: 'var(--ink-faint)' }}>No deals match these filters.</td></tr>
        )}
      </tbody>
    </table>
  );
}

/* ---------- section header ---------- */
function SectionHead({ title, sub, right, accentRule }) {
  return (
    <div style={{ display: 'flex', alignItems: 'flex-end', justifyContent: 'space-between', marginBottom: 12, gap: 16 }}>
      <div style={{ borderLeft: accentRule ? '3px solid var(--accent-line)' : 'none', paddingLeft: accentRule ? 11 : 0 }}>
        <h3 style={{ fontSize: 15, fontWeight: 700 }}>{title}</h3>
        {sub && <div style={{ fontSize: 12, color: 'var(--ink-soft)', marginTop: 3, fontWeight: 500 }}>{sub}</div>}
      </div>
      {right}
    </div>
  );
}

Object.assign(window, {
  applyGlobalFilters, Segmented, MultiSelect, KpiCell, FitBadge, fitBadgeStyle,
  SeenMark, TierTag, dealColumns, CompCell, sortDeals, DealTable, SectionHead, useOutside,
});
