// cwr-acks.jsx — Wave 3: CWR Ack-handling default view
//
// Per the audit (Section 8): "acks come back from societies. Right now there's
// no clear 'this batch was accepted, this batch had errors, here's what to fix'
// view. That should be the primary view of the CWR screen."
//
// This file replaces ScreenCwr at the route level. Default tab is ACKS — the
// queue of returned society acknowledgements with rejection codes, the works
// inside, and one-click "fix and resubmit" actions. Original tabs (in-flight
// transmissions, society health) are preserved as secondary tabs.
//
// CWR ack codes are standardized (CISAC CWR 2.1 / 3.0). The big ones:
//   AS — Accepted (success)
//   AC — Accepted with Changes (society modified the registration)
//   RJ — Rejected (work-level)
//   NP — No Participation (society won't register; usually wrong PRO)
//   CO — Conflict (another publisher claims same work)
//   DU — Duplicate (already on file)
//   IR — Incomplete Registration (missing fields)
//   IE — Invalid Element (bad data in a field)
//   AR — Accepted (no further info)
//
// Exports: window.ScreenCwrAcks

(function () {
  const { useState, useMemo, useEffect } = React;

  // ─────────── ack code dictionary
  const ACK_CODES = {
    AS: { label: 'Accepted',           tone: 'ok',     short: 'ACCEPTED',         desc: 'Society accepted the registration as-is. Work ID assigned.' },
    AC: { label: 'Accepted w/ Changes', tone: 'ok',    short: 'ACK · CHANGED',     desc: 'Accepted but the society modified one or more fields. Review their changes.' },
    RJ: { label: 'Rejected',           tone: 'danger', short: 'REJECTED',         desc: 'Society rejected the work. See specific reason code.' },
    NP: { label: 'No Participation',   tone: 'warn',   short: 'NO PARTICIPATION', desc: 'Society does not represent this writer. Wrong PRO assignment.' },
    CO: { label: 'Conflict',           tone: 'danger', short: 'CONFLICT',         desc: 'Another publisher has filed conflicting splits. Manual resolution required.' },
    DU: { label: 'Duplicate',          tone: 'warn',   short: 'DUPLICATE',        desc: 'Society already has this work. Likely re-registration; safe to ignore if intentional.' },
    IR: { label: 'Incomplete Reg',     tone: 'danger', short: 'INCOMPLETE',       desc: 'Required field missing. Most common: writer IPI, ISWC, or society work ID.' },
    IE: { label: 'Invalid Element',    tone: 'danger', short: 'INVALID',          desc: 'Field present but malformed (bad IPI, invalid duration format, etc).' },
    AR: { label: 'Accepted',           tone: 'ok',     short: 'ACK',              desc: 'Acknowledged. No further detail provided.' },
  };

  const TONE_BG = { ok: '#1e6b3f', warn: '#9b6a18', danger: '#a04432' };
  const TONE_BG_SOFT = { ok: 'rgba(45,106,63,.08)', warn: 'rgba(155,106,24,.08)', danger: 'rgba(160,68,50,.08)' };
  const TONE_FG = { ok: '#1e6b3f', warn: '#9b6a18', danger: '#a04432' };

  // ─────────── seeded RNG so the queue is stable
  const seedR = (s) => {
    let h = 2166136261 >>> 0;
    for (let i = 0; i < s.length; i++) { h = Math.imul(h ^ s.charCodeAt(i), 16777619); }
    return () => { h = Math.imul(h ^ (h >>> 13), 16777619); return ((h >>> 0) % 100000) / 100000; };
  };

  // ─────────── synthesize an ack queue from real societies + works
  function buildAckQueue() {
    const societies = (window.SOCIETIES || []).filter(s => s.kind === 'PRO' || s.kind === 'MRO' || s.kind === 'CMO' || s.kind === 'HUB');
    const works = (window.WORKS || []);
    if (!societies.length || !works.length) return [];

    const codes = ['AS','AS','AS','AS','AS','AS','AC','AR','RJ','NP','CO','DU','IR','IE'];
    const today = new Date();
    const out = [];
    let aid = 1;

    societies.slice(0, 14).forEach((soc, sIdx) => {
      const r = seedR(soc.acronym + ':acks');
      const batchCount = 2 + Math.floor(r() * 3); // 2–4 batches per society in-window
      for (let b = 0; b < batchCount; b++) {
        const sentDays = 2 + Math.floor(r() * 18);
        const sentDate = new Date(today); sentDate.setDate(sentDate.getDate() - sentDays);
        const ackDate = new Date(sentDate); ackDate.setDate(sentDate.getDate() + 1 + Math.floor(r() * 6));
        const totalWorks = 12 + Math.floor(r() * 80);
        const filenameSeq = String.fromCharCode(65 + b);
        const file = `CW${ackDate.getFullYear().toString().slice(2)}${String(ackDate.getMonth()+1).padStart(2,'0')}${String(ackDate.getDate()).padStart(2,'0')}${soc.acronym}.V21${filenameSeq}`;
        const transmissionId = `CWR-${ackDate.getFullYear()}-${String(ackDate.getMonth()+1).padStart(2,'0')}${String(ackDate.getDate()).padStart(2,'0')}-${soc.acronym}${filenameSeq}`;

        // distribute outcomes
        const items = [];
        let counts = { AS:0, AC:0, AR:0, RJ:0, NP:0, CO:0, DU:0, IR:0, IE:0 };
        for (let i = 0; i < totalWorks; i++) {
          const code = codes[Math.floor(r() * codes.length)];
          counts[code] = (counts[code] || 0) + 1;
          const work = works[Math.floor(r() * works.length)];
          if (!work) continue;
          items.push({
            id: 'AK' + (aid++),
            code,
            workId: work.id,
            workTitle: work.title || work.name || `Work ${work.id}`,
            iswc: work.iswc || null,
            societyWorkId: code === 'AS' || code === 'AC' || code === 'AR' ? `${soc.acronym}-${100000 + Math.floor(r() * 900000)}` : null,
            field: code === 'IE' ? ['SWR.IPI','NWR.ISWC','SWR.SHARE','NWR.DURATION','SPU.IPI'][Math.floor(r()*5)] : null,
            note: code === 'AC' ? ['Title shortened to 60 chars','Writer role coerced to CA','Performer name normalized'][Math.floor(r()*3)]
                : code === 'CO' ? `Conflicting publisher claim from ${['Sony','Warner Chappell','Concord','Reservoir'][Math.floor(r()*4)]}`
                : code === 'NP' ? `Writer not registered with ${soc.acronym}`
                : code === 'IR' ? ['Missing writer IPI','Missing ISWC','Missing duration','Missing performer'][Math.floor(r()*4)]
                : code === 'IE' ? 'Field format error'
                : null,
          });
        }
        const accepted = (counts.AS||0) + (counts.AC||0) + (counts.AR||0);
        const rejected = (counts.RJ||0) + (counts.IR||0) + (counts.IE||0);
        const flagged  = (counts.CO||0) + (counts.NP||0);
        const dupes    = counts.DU||0;
        const status = rejected > 0 ? 'has-rejections' : flagged > 0 ? 'needs-review' : 'clean';
        out.push({
          id: transmissionId,
          file,
          society: { acronym: soc.acronym, name: soc.name, kind: soc.kind, country: soc.country, territory: soc.territory },
          sent: sentDate.toISOString().slice(0,10),
          ack:  ackDate.toISOString().slice(0,10),
          turnaroundHours: Math.max(1, Math.round((ackDate - sentDate) / 36e5)),
          totalWorks,
          counts,
          accepted,
          rejected,
          flagged,
          dupes,
          status,
          items,
        });
      }
    });
    return out.sort((a, b) => b.ack.localeCompare(a.ack));
  }

  // ─────────── batch row
  function BatchRow({ batch, expanded, onToggle, onOpenWork, onResubmit }) {
    const tone = batch.status === 'has-rejections' ? 'danger' : batch.status === 'needs-review' ? 'warn' : 'ok';
    const dot = TONE_FG[tone];
    return (
      <div style={{ borderBottom:'1px solid var(--rule)' }}>
        <button onClick={onToggle} style={{ width:'100%', textAlign:'left', background:'transparent', border:0, cursor:'pointer', padding:'14px 18px', display:'grid', gridTemplateColumns:'24px 80px 1fr 220px 90px 110px 100px', gap:14, alignItems:'center' }}>
          <span style={{ width:8, height:8, borderRadius:'50%', background:dot, justifySelf:'center' }}/>
          <span className="ff-display" style={{ fontSize:18, fontWeight:600, letterSpacing:'-0.02em' }}>{batch.society.acronym}</span>
          <div style={{ minWidth:0 }}>
            <div className="ff-mono" style={{ fontSize:12, fontWeight:500, overflow:'hidden', textOverflow:'ellipsis', whiteSpace:'nowrap' }}>{batch.file}</div>
            <div className="ff-mono" style={{ fontSize:10, color:'var(--ink-3)', marginTop:2 }}>
              {batch.society.country} · ack {batch.ack} · turnaround {batch.turnaroundHours}h
            </div>
          </div>
          {/* outcome bar */}
          <div style={{ display:'flex', height:8, border:'1px solid var(--rule)', overflow:'hidden' }}>
            <div title={`${batch.accepted} accepted`} style={{ width: (batch.accepted / batch.totalWorks * 100) + '%', background:'#2d6a3f' }}/>
            <div title={`${batch.flagged} flagged`}  style={{ width: (batch.flagged  / batch.totalWorks * 100) + '%', background:'#9b6a18' }}/>
            <div title={`${batch.rejected} rejected`} style={{ width: (batch.rejected / batch.totalWorks * 100) + '%', background:'#a04432' }}/>
            <div title={`${batch.dupes} duplicates`}  style={{ width: (batch.dupes    / batch.totalWorks * 100) + '%', background:'#bbb' }}/>
          </div>
          <span className="ff-mono num" style={{ fontSize:13, fontWeight:600, textAlign:'right' }}>{batch.totalWorks}</span>
          <span className="ff-mono" style={{ fontSize:11, textAlign:'right' }}>
            <span style={{ color:'#2d6a3f', fontWeight:600 }}>{batch.accepted}</span>
            {batch.flagged > 0  && <> · <span style={{ color:'#9b6a18', fontWeight:600 }}>{batch.flagged}</span></>}
            {batch.rejected > 0 && <> · <span style={{ color:'#a04432', fontWeight:600 }}>{batch.rejected}</span></>}
          </span>
          <span className="ff-mono upper" style={{ fontSize:10, color:'var(--ink-3)', textAlign:'right', letterSpacing:'.06em' }}>
            {expanded ? '▾ HIDE' : '▸ DETAIL'}
          </span>
        </button>

        {expanded && (
          <div style={{ padding:'4px 18px 18px 32px', background:'var(--bg-2)', borderTop:'1px solid var(--rule-soft)' }}>
            {/* outcome strip */}
            <div style={{ display:'flex', gap:18, padding:'14px 0', borderBottom:'1px solid var(--rule-soft)', flexWrap:'wrap' }}>
              {Object.entries(batch.counts).filter(([_, n]) => n > 0).map(([code, n]) => {
                const meta = ACK_CODES[code] || { tone:'neutral', short: code, desc:'' };
                return (
                  <div key={code} style={{ display:'flex', alignItems:'center', gap:8 }}>
                    <span className="ff-mono" style={{ fontSize:9, padding:'2px 6px', background:TONE_BG[meta.tone] || 'var(--ink)', color:'#fff', letterSpacing:'.08em', fontWeight:600 }}>{code}</span>
                    <span className="ff-mono" style={{ fontSize:11, color:'var(--ink-2)' }}>{meta.short.toLowerCase()}</span>
                    <span className="ff-mono num" style={{ fontSize:13, fontWeight:600 }}>{n}</span>
                  </div>
                );
              })}
            </div>

            {/* items table — only NON-accepted by default */}
            <ItemList items={batch.items} onOpenWork={onOpenWork} onResubmit={onResubmit} />
          </div>
        )}
      </div>
    );
  }

  function ItemList({ items, onOpenWork, onResubmit }) {
    const [showAll, setShowAll] = useState(false);
    const visible = showAll ? items : items.filter(it => !['AS','AC','AR'].includes(it.code));
    if (visible.length === 0 && !showAll) {
      return (
        <div style={{ padding:'14px 0', fontSize:12, color:'var(--ink-3)' }}>
          All {items.length} works accepted clean. <button onClick={() => setShowAll(true)} className="ff-mono upper" style={{ fontSize:10, letterSpacing:'.08em', background:'transparent', border:0, color:'var(--ink)', cursor:'pointer', padding:0, marginLeft:6, textDecoration:'underline' }}>SHOW ALL →</button>
        </div>
      );
    }
    return (
      <>
        <div style={{ display:'flex', justifyContent:'space-between', alignItems:'baseline', padding:'12px 0 8px' }}>
          <div className="ff-mono upper" style={{ fontSize:9, letterSpacing:'.12em', color:'var(--ink-3)' }}>
            {showAll ? 'ALL WORKS' : 'NEEDS ATTENTION'} · {visible.length}
          </div>
          <button onClick={() => setShowAll(!showAll)} className="ff-mono upper" style={{ fontSize:9, letterSpacing:'.08em', padding:'4px 8px', background:'transparent', border:'1px solid var(--rule)', color:'var(--ink-2)', cursor:'pointer' }}>
            {showAll ? 'HIDE ACCEPTED' : 'SHOW ACCEPTED'}
          </button>
        </div>
        <div>
          {visible.slice(0, 50).map(it => (
            <div key={it.id} style={{ display:'grid', gridTemplateColumns:'74px 1fr 130px 130px 1fr auto', gap:14, alignItems:'center', padding:'9px 12px', background:'var(--paper)', borderBottom:'1px solid var(--rule-soft)' }}>
              <CodePill code={it.code}/>
              <div style={{ minWidth:0 }}>
                <button onClick={() => onOpenWork(it.workId)} style={{ background:'transparent', border:0, padding:0, cursor:'pointer', textAlign:'left', color:'var(--ink)' }}>
                  <div style={{ fontSize:12, fontWeight:600, overflow:'hidden', textOverflow:'ellipsis', whiteSpace:'nowrap' }}>{it.workTitle}</div>
                </button>
                <div className="ff-mono" style={{ fontSize:9.5, color:'var(--ink-3)', marginTop:2 }}>
                  {it.iswc ? `ISWC ${it.iswc}` : <span style={{ color: '#a04432' }}>NO ISWC</span>}
                  {it.societyWorkId && <> · {it.societyWorkId}</>}
                </div>
              </div>
              <span className="ff-mono" style={{ fontSize:10, color:'var(--ink-3)' }}>{it.field || '—'}</span>
              <span className="ff-mono" style={{ fontSize:10, color:'var(--ink-3)' }}>{ACK_CODES[it.code]?.short || it.code}</span>
              <span className="ff-mono" style={{ fontSize:10.5, color:'var(--ink-2)', overflow:'hidden', textOverflow:'ellipsis', whiteSpace:'nowrap' }}>
                {it.note || ACK_CODES[it.code]?.desc || ''}
              </span>
              <ItemActions item={it} onOpenWork={onOpenWork} onResubmit={onResubmit}/>
            </div>
          ))}
          {visible.length > 50 && (
            <div className="ff-mono" style={{ fontSize:10, color:'var(--ink-3)', padding:'10px 12px', background:'var(--paper)' }}>
              + {visible.length - 50} more — open in transmissions log
            </div>
          )}
        </div>
      </>
    );
  }

  function ItemActions({ item, onOpenWork, onResubmit }) {
    if (['AS','AC','AR','DU'].includes(item.code)) return <span/>;
    return (
      <div style={{ display:'flex', gap:4 }}>
        <button onClick={() => onOpenWork(item.workId)} className="ff-mono upper" style={{ fontSize:9, letterSpacing:'.06em', padding:'5px 8px', background:'transparent', border:'1px solid var(--rule)', color:'var(--ink-2)', cursor:'pointer' }}>FIX</button>
        <button onClick={() => onResubmit(item)} className="ff-mono upper" style={{ fontSize:9, letterSpacing:'.06em', padding:'5px 8px', background:'var(--ink)', border:'1px solid var(--ink)', color:'var(--bg)', cursor:'pointer' }}>RESUBMIT</button>
      </div>
    );
  }

  function CodePill({ code }) {
    const meta = ACK_CODES[code] || { tone:'neutral', short:code };
    const bg = meta.tone === 'ok' ? '#e8f0e9' : meta.tone === 'warn' ? '#f4ecd9' : meta.tone === 'danger' ? '#f4e3df' : '#eee';
    const fg = meta.tone === 'ok' ? '#1e6b3f' : meta.tone === 'warn' ? '#9b6a18' : meta.tone === 'danger' ? '#a04432' : 'var(--ink-2)';
    return <span className="ff-mono" style={{ fontSize:10, padding:'4px 8px', background:bg, color:fg, fontWeight:700, letterSpacing:'.04em', textAlign:'center' }}>{code} · {meta.short.split(' ')[0]}</span>;
  }

  // ═══════════════════════════════════════════════════════ MAIN SCREEN
  function ScreenCwrAcks({ go, payload }) {
    const [tab, setTab] = useState(payload?.tab || (payload?.workIds || payload?.generate ? 'gen' : 'acks'));

    return (
      <div>
        {/* Hero */}
        <div className="ff-mono upper" style={{ fontSize:10, color:'var(--ink-3)', letterSpacing:'.12em', marginBottom:8 }}>REGISTRATIONS · CWR · DDEX</div>
        <div style={{ display:'flex', justifyContent:'space-between', alignItems:'flex-start', gap:24, flexWrap:'wrap', marginBottom:24 }}>
          <h1 className="heading-swap ff-display" style={{ fontSize:'clamp(36px,4.5vw,64px)', fontWeight:700, letterSpacing:'-0.04em', lineHeight:.95, margin:0 }}>
            CWR Acknowledgements
          </h1>
          <div style={{ display:'flex', gap:8, alignItems:'center' }}>
            <span className="ff-mono upper" style={{ fontSize:10, color:'var(--ink-3)' }}>NEXT BATCH IN</span>
            <span className="ff-display num" style={{ fontSize:24, fontWeight:600, letterSpacing:'-0.02em' }}>02:14:33</span>
            <button className="ff-mono upper" onClick={() => window.toast && window.toast('Manual batch generation queued')} style={{ marginLeft:8, padding:'10px 14px', fontSize:11, fontWeight:600, letterSpacing:'.08em', border:0, background:'var(--ink)', color:'var(--bg)', cursor:'pointer' }}>SEND CWR ↗</button>
          </div>
        </div>

        {/* Tabs */}
        <div style={{ display:'flex', borderBottom:'1px solid var(--rule)', marginBottom:24 }}>
          {[
            { k:'gen',      l:'Generate',            hint:'build a CWR file' },
            { k:'acks',     l:'Acks',                hint:'returned from societies' },
            { k:'import',   l:'Import ACK',          hint:'parse + apply status' },
            { k:'flight',   l:'In flight',           hint:'awaiting ack' },
            { k:'caf',      l:'CAF · agreements',    hint:'society-to-society wire' },
            { k:'formats',  l:'Formats',             hint:'JSON / XML' },
            { k:'ftp',      l:'FTP',                 hint:'FTP / FTPS legacy' },
            { k:'compl',    l:'Compliance',          hint:'spec conformance' },
            { k:'health',   l:'Society health',      hint:'90-day rolling' },
            { k:'ddex',     l:'DDEX · DSPs',         hint:'release deliveries' },
          ].map(t => (
            <button key={t.k} onClick={() => setTab(t.k)} className="ff-mono upper" style={{
              padding:'14px 18px', fontSize:11, fontWeight:600, letterSpacing:'.08em',
              borderBottom: tab === t.k ? '3px solid var(--ink)' : '3px solid transparent', marginBottom:-1,
              color: tab === t.k ? 'var(--ink)' : 'var(--ink-3)', background:'transparent', border:0, cursor:'pointer',
              display:'flex', flexDirection:'column', alignItems:'flex-start', gap:2,
            }}>
              <span>{t.l}</span>
              <span className="ff-mono" style={{ fontSize:9, color:'var(--ink-4)', fontWeight:400, letterSpacing:'.04em', textTransform:'none' }}>{t.hint}</span>
            </button>
          ))}
        </div>

        {tab === 'gen'    && (window.CwrGenTab ? <window.CwrGenTab go={go} payload={payload}/> : null)}
        {tab === 'acks'   && <AcksTab go={go}/>}
        {tab === 'import' && (window.CwrAckImportTab ? <window.CwrAckImportTab/> : <div className="ff-mono" style={{padding:24,color:'var(--ink-3)'}}>ACK importer unavailable.</div>)}
        {tab === 'flight' && <FlightTab go={go}/>}
        {tab === 'caf'    && (window.CafGenTab ? <window.CafGenTab go={go} payload={payload}/> : <div className="ff-mono" style={{padding:24,color:'var(--ink-3)'}}>CAF screen unavailable.</div>)}
        {tab === 'formats'&& (window.FormatsTab ? <window.FormatsTab kind="cwr"/> : null)}
        {tab === 'ftp'    && (window.FtpTab ? <window.FtpTab/> : <div className="ff-mono" style={{padding:24,color:'var(--ink-3)'}}>FTP screen unavailable.</div>)}
        {tab === 'compl'  && (window.CwrComplianceTab ? <window.CwrComplianceTab/> : null)}
        {tab === 'health' && <HealthTab go={go}/>}
        {tab === 'ddex'   && <DdexTab go={go}/>}
      </div>
    );
  }

  // ═══════════════════════════════════════════════════════ TAB: ACKS
  function AcksTab({ go }) {
    const queue = useMemo(buildAckQueue, []);

    const totals = useMemo(() => {
      const t = { works:0, accepted:0, rejected:0, flagged:0, dupes:0, batches: queue.length, societies: new Set() };
      queue.forEach(b => {
        t.works += b.totalWorks;
        t.accepted += b.accepted;
        t.rejected += b.rejected;
        t.flagged  += b.flagged;
        t.dupes    += b.dupes;
        t.societies.add(b.society.acronym);
      });
      t.societies = t.societies.size;
      return t;
    }, [queue]);

    const [filter, setFilter] = useState('attention'); // attention | rejected | flagged | clean | all
    const [society, setSociety] = useState('all');
    const [search, setSearch] = useState('');
    const [expanded, setExpanded] = useState(() => new Set(queue.filter(b => b.status !== 'clean').slice(0, 1).map(b => b.id)));

    const societyOptions = useMemo(() => ['all', ...new Set(queue.map(b => b.society.acronym))], [queue]);

    const filtered = useMemo(() => queue.filter(b => {
      if (filter === 'attention' && b.status === 'clean') return false;
      if (filter === 'rejected' && b.rejected === 0) return false;
      if (filter === 'flagged'  && b.flagged === 0) return false;
      if (filter === 'clean'    && b.status !== 'clean') return false;
      if (society !== 'all' && b.society.acronym !== society) return false;
      if (search) {
        const q = search.toLowerCase();
        if (!b.society.acronym.toLowerCase().includes(q) && !b.file.toLowerCase().includes(q) && !b.id.toLowerCase().includes(q)) return false;
      }
      return true;
    }), [queue, filter, society, search]);

    const onOpenWork = (workId) => {
      const work = (window.WORKS || []).find(w => w.id === workId);
      if (work && go) go('work', work);
      else window.toast && window.toast('Work not found in catalog');
    };
    const onResubmit = (item) => {
      window.toast && window.toast(`Queued ${item.workTitle} for resubmission to next CWR batch`);
    };

    const acceptedPct = totals.works ? Math.round(totals.accepted / totals.works * 100) : 0;

    return (
      <div>
        {/* KPI strip */}
        <div style={{ display:'grid', gridTemplateColumns:'repeat(5, 1fr)', borderTop:'1px solid var(--rule)', borderBottom:'1px solid var(--rule)', marginBottom:24 }}>
          <Kpi label="Open batches"          value={totals.batches}    sub={`${totals.societies} societies`}/>
          <Kpi label="Works processed · 14d" value={totals.works.toLocaleString()} sub={`${acceptedPct}% accepted clean`}/>
          <Kpi label="Rejected"              value={totals.rejected} tone={totals.rejected > 0 ? '#a04432' : 'var(--ink)'} sub="needs fix + resubmit"/>
          <Kpi label="Flagged"               value={totals.flagged}  tone={totals.flagged > 0 ? '#9b6a18' : 'var(--ink)'} sub="conflicts · NPs"/>
          <Kpi label="Duplicates"            value={totals.dupes}    sub="usually safe to ignore"/>
        </div>

        {/* Filter toolbar */}
        <div style={{ display:'flex', gap:10, alignItems:'center', flexWrap:'wrap', marginBottom:16 }}>
          {[
            { k:'attention', l:`NEEDS ATTENTION · ${queue.filter(b => b.status !== 'clean').length}`, tone:'#a04432' },
            { k:'rejected',  l:`REJECTED · ${queue.filter(b => b.rejected > 0).length}`,              tone:'#a04432' },
            { k:'flagged',   l:`FLAGGED · ${queue.filter(b => b.flagged > 0).length}`,                tone:'#9b6a18' },
            { k:'clean',     l:`CLEAN · ${queue.filter(b => b.status === 'clean').length}`,           tone:'#2d6a3f' },
            { k:'all',       l:`ALL · ${queue.length}`,                                                tone:'var(--ink)' },
          ].map(f => (
            <button key={f.k} onClick={() => setFilter(f.k)} className="ff-mono upper" style={{
              padding:'8px 12px', fontSize:10, letterSpacing:'.08em', fontWeight:600,
              border:'1px solid ' + (filter === f.k ? 'var(--ink)' : 'var(--rule)'),
              background: filter === f.k ? 'var(--ink)' : 'transparent',
              color:    filter === f.k ? 'var(--bg)' : 'var(--ink-2)',
              cursor:'pointer',
            }}>
              {f.l}
            </button>
          ))}
          <span style={{ width:1, height:24, background:'var(--rule)' }}/>
          <select value={society} onChange={e => setSociety(e.target.value)} className="ff-mono"
            style={{ padding:'8px 10px', fontSize:11, border:'1px solid var(--rule)', background:'var(--paper)', cursor:'pointer' }}>
            {societyOptions.map(s => <option key={s} value={s}>{s === 'all' ? 'ALL SOCIETIES' : s}</option>)}
          </select>
          <input value={search} onChange={e => setSearch(e.target.value)} placeholder="Search batch ID, file, society…" className="ff-mono"
            style={{ flex:1, minWidth:200, padding:'8px 12px', fontSize:11, border:'1px solid var(--rule)', background:'var(--paper)' }}/>
          <button onClick={() => {
            const allIds = filtered.map(b => b.id);
            setExpanded(new Set(expanded.size ? [] : allIds));
          }} className="ff-mono upper" style={{ padding:'8px 12px', fontSize:10, letterSpacing:'.08em', border:'1px solid var(--rule)', background:'transparent', cursor:'pointer' }}>
            {expanded.size > 0 ? 'COLLAPSE ALL' : 'EXPAND ALL'}
          </button>
        </div>

        {/* Column headers */}
        <div style={{ display:'grid', gridTemplateColumns:'24px 80px 1fr 220px 90px 110px 100px', gap:14, padding:'10px 18px', borderBottom:'1px solid var(--ink)', background:'var(--bg-2)', alignItems:'center' }}>
          <span/>
          <span className="ff-mono upper" style={{ fontSize:9, letterSpacing:'.1em', color:'var(--ink-3)', fontWeight:500 }}>SOC</span>
          <span className="ff-mono upper" style={{ fontSize:9, letterSpacing:'.1em', color:'var(--ink-3)', fontWeight:500 }}>BATCH FILE</span>
          <span className="ff-mono upper" style={{ fontSize:9, letterSpacing:'.1em', color:'var(--ink-3)', fontWeight:500 }}>OUTCOME DISTRIBUTION</span>
          <span className="ff-mono upper" style={{ fontSize:9, letterSpacing:'.1em', color:'var(--ink-3)', fontWeight:500, textAlign:'right' }}>WORKS</span>
          <span className="ff-mono upper" style={{ fontSize:9, letterSpacing:'.1em', color:'var(--ink-3)', fontWeight:500, textAlign:'right' }}>ACK · FLAG · REJ</span>
          <span/>
        </div>

        {/* Batches */}
        {filtered.length === 0 ? (
          <div style={{ padding:'80px 20px', textAlign:'center', color:'var(--ink-3)' }}>
            <div className="ff-display" style={{ fontSize:22, fontWeight:600, marginBottom:6 }}>Nothing in this view</div>
            <div className="ff-mono" style={{ fontSize:12 }}>Try a different filter, or wait for the next ack window.</div>
          </div>
        ) : filtered.map(batch => (
          <BatchRow
            key={batch.id}
            batch={batch}
            expanded={expanded.has(batch.id)}
            onToggle={() => {
              const n = new Set(expanded);
              if (n.has(batch.id)) n.delete(batch.id); else n.add(batch.id);
              setExpanded(n);
            }}
            onOpenWork={onOpenWork}
            onResubmit={onResubmit}
          />
        ))}

        {/* Code dictionary */}
        <div style={{ marginTop:48, paddingTop:24, borderTop:'1px solid var(--rule)' }}>
          <div className="ff-mono upper" style={{ fontSize:10, letterSpacing:'.12em', color:'var(--ink-3)', marginBottom:14 }}>CWR ACK CODES · CISAC 2.1 / 3.0</div>
          <div style={{ display:'grid', gridTemplateColumns:'repeat(auto-fit, minmax(260px, 1fr))', gap:12 }}>
            {Object.entries(ACK_CODES).map(([code, meta]) => (
              <div key={code} style={{ padding:'12px 14px', border:'1px solid var(--rule)', background:'var(--paper)' }}>
                <div style={{ display:'flex', alignItems:'center', gap:10, marginBottom:4 }}>
                  <CodePill code={code}/>
                  <span className="ff-display" style={{ fontSize:13, fontWeight:600 }}>{meta.label}</span>
                </div>
                <div className="ff-mono" style={{ fontSize:10.5, color:'var(--ink-3)', lineHeight:1.5 }}>{meta.desc}</div>
              </div>
            ))}
          </div>
        </div>
      </div>
    );
  }

  // ═══════════════════════════════════════════════════════ TAB: IN FLIGHT
  function FlightTab({ go }) {
    // Borrow from existing TXN if it exists, otherwise synth
    const txns = (typeof window.TXN !== 'undefined' ? window.TXN : null) || [
      { id:'CWR-2026-0501-ASCAPa', file:'CW260501ASCAP.V21A', count:142, recv:'ASCAP', status:'submitted', sent:'14:22', ack:'pending' },
      { id:'CWR-2026-0501-BMIb',   file:'CW260501BMI.V21B',   count:118, recv:'BMI',   status:'submitted', sent:'14:25', ack:'pending' },
      { id:'CWR-2026-0501-PRSa',   file:'CW260501PRS.V21A',   count:88,  recv:'PRS',   status:'submitted', sent:'14:28', ack:'pending' },
    ];
    return (
      <>
        <div style={{ display:'grid', gridTemplateColumns:'repeat(3,1fr)', borderTop:'1px solid var(--rule)' }}>
          {txns.map((t, i, arr) => (
            <div key={t.id} style={{ padding:'18px', borderRight:(i+1)%3===0?'none':'1px solid var(--rule)', borderBottom:i<arr.length-3?'1px solid var(--rule)':'none' }}>
              <div style={{ display:'flex', justifyContent:'space-between', alignItems:'flex-start', marginBottom:14 }}>
                <div>
                  <div className="ff-mono num" style={{ fontSize:10, color:'var(--ink-4)' }}>SEQ {String(i+1).padStart(3,'0')}</div>
                  <div className="ff-display" style={{ fontSize:28, fontWeight:600, letterSpacing:'-0.03em', marginTop:4 }}>{t.recv}</div>
                </div>
                <span className="ff-mono upper" style={{ fontSize:9, padding:'3px 7px', background:'rgba(31,78,216,.07)', color:'#1f4ed8', letterSpacing:'.1em', fontWeight:600 }}>SUBMITTED</span>
              </div>
              <div style={{ padding:'12px 0', borderTop:'1px solid var(--rule-soft)', borderBottom:'1px solid var(--rule-soft)', display:'flex', justifyContent:'space-between', alignItems:'center' }}>
                <span className="ff-mono num" style={{ fontSize:24, fontWeight:600 }}>{t.count}</span>
                <span className="ff-mono upper" style={{ fontSize:10, color:'var(--ink-3)' }}>WORKS</span>
              </div>
              <div style={{ marginTop:12, fontSize:11, color:'var(--ink-3)' }} className="ff-mono">{t.file}</div>
              <div className="ff-mono" style={{ fontSize:10, color:'var(--ink-4)', marginTop:6 }}>SENT {t.sent} · ACK {t.ack}</div>
            </div>
          ))}
        </div>
      </>
    );
  }

  // ═══════════════════════════════════════════════════════ TAB: HEALTH
  function HealthTab({ go }) {
    const societies = (window.SOCIETIES || []).filter(s => s.kind === 'PRO' || s.kind === 'MRO' || s.kind === 'CMO' || s.kind === 'HUB');
    return (
      <div style={{ borderTop:'1px solid var(--rule)' }}>
        <div className="ff-mono upper" style={{ display:'grid', gridTemplateColumns:'80px 1fr 200px 120px 100px 110px', gap:14, fontSize:9, letterSpacing:'.1em', color:'var(--ink-3)', padding:'10px 0', borderBottom:'1px solid var(--ink)', background:'var(--bg-2)', fontWeight:500 }}>
          <span style={{ paddingLeft:14 }}>SOC</span>
          <span>NAME · TERRITORY</span>
          <span>ACK RATE · 90D</span>
          <span style={{ textAlign:'right' }}>RATE</span>
          <span style={{ textAlign:'right' }}>BATCHES</span>
          <span style={{ textAlign:'right', paddingRight:14 }}>LAST SENT</span>
        </div>
        {societies.slice(0, 24).map(s => {
          const r = seedR(s.acronym + ':health');
          const rate = Math.max(72, Math.min(99.5, (s.ackRate || (88 + r() * 11))));
          const batches = Math.round(8 + r() * 30);
          const last = `2026-${String(4 + Math.floor(r() * 2)).padStart(2,'0')}-${String(1 + Math.floor(r() * 28)).padStart(2,'0')}`;
          const tone = rate >= 95 ? '#2d6a3f' : rate >= 90 ? '#9b6a18' : '#a04432';
          return (
            <button key={s.acronym} onClick={() => go && go('society', { acronym: s.acronym })}
              style={{ width:'100%', textAlign:'left', display:'grid', gridTemplateColumns:'80px 1fr 200px 120px 100px 110px', gap:14, padding:'14px 0', borderBottom:'1px solid var(--rule-soft)', background:'transparent', border:0, borderBottomWidth:1, borderBottomStyle:'solid', borderBottomColor:'var(--rule-soft)', cursor:'pointer', alignItems:'center' }}>
              <span className="ff-display" style={{ fontSize:18, fontWeight:600, paddingLeft:14, letterSpacing:'-0.02em' }}>{s.acronym}</span>
              <div style={{ minWidth:0 }}>
                <div style={{ fontSize:13, fontWeight:500, overflow:'hidden', textOverflow:'ellipsis', whiteSpace:'nowrap' }}>{s.name}</div>
                <div className="ff-mono" style={{ fontSize:10, color:'var(--ink-3)', marginTop:2 }}>{s.country} · {s.territory}</div>
              </div>
              <div style={{ display:'flex', height:6, background:'var(--rule-soft)' }}>
                <div style={{ width: rate + '%', background: tone }}/>
              </div>
              <span className="ff-mono num" style={{ fontSize:14, fontWeight:600, color: tone, textAlign:'right' }}>{rate.toFixed(1)}%</span>
              <span className="ff-mono num" style={{ fontSize:11, color:'var(--ink-2)', textAlign:'right' }}>{batches}</span>
              <span className="ff-mono" style={{ fontSize:11, color:'var(--ink-3)', textAlign:'right', paddingRight:14 }}>{last}</span>
            </button>
          );
        })}
      </div>
    );
  }

  // ═══════════════════════════════════════════════════════ TAB: DDEX
  function DdexTab({ go }) {
    return (
      <div style={{ padding:'40px 0', textAlign:'center', color:'var(--ink-3)' }}>
        <div className="ff-mono upper" style={{ fontSize:10, letterSpacing:'.12em', marginBottom:8 }}>DDEX · DSP DELIVERIES</div>
        <div className="ff-display" style={{ fontSize:22, fontWeight:600, color:'var(--ink-2)', marginBottom:8 }}>Pending integration</div>
        <p style={{ fontSize:13, maxWidth:480, margin:'0 auto', lineHeight:1.6 }}>
          DDEX-out flows through the distributor (Symphonic). Outbound XML is generated server-side and shows up here as receipts once the connector is live.
        </p>
      </div>
    );
  }

  function Kpi({ label, value, sub, tone = 'var(--ink)' }) {
    return (
      <div style={{ padding:'20px 18px', borderRight:'1px solid var(--rule)' }}>
        <div className="ff-mono upper" style={{ fontSize:9, letterSpacing:'.14em', color:'var(--ink-3)', fontWeight:500, marginBottom:6 }}>{label}</div>
        <div className="ff-display num" style={{ fontSize:28, fontWeight:600, letterSpacing:'-0.02em', color:tone, lineHeight:1 }}>{value}</div>
        {sub && <div className="ff-mono" style={{ fontSize:10, color:'var(--ink-3)', marginTop:6 }}>{sub}</div>}
      </div>
    );
  }

  Object.assign(window, { ScreenCwrAcks });
})();
