// pro-lookup.jsx — PRO Lookup & cross-society conflict screen
// ─────────────────────────────────────────────────────────────────────
// Tabs:
//   Search       — single-work multi-society lookup with conflict drawer
//   Catalog scan — batch your catalog, see consolidated conflict report
//   Adapters     — society health, last query timing, simulated config
//   Watchlist    — works flagged for periodic re-check
//   How it works — explainer
// ─────────────────────────────────────────────────────────────────────

(function () {
  'use strict';
  if (typeof window === 'undefined' || !window.React) return;
  const { useState, useMemo, useEffect, useRef } = React;

  // ─── small UI primitives reused across this file ─────────────────
  const fmt = {
    pct: (n) => `${n}%`,
    sev: (s) => ({ critical:'#c2410c', high:'#b45309', medium:'#0369a1', info:'#475569' }[s] || '#475569'),
    sevBg: (s) => ({ critical:'#fef2f2', high:'#fffbeb', medium:'#f0f9ff', info:'#f8fafc' }[s] || '#f8fafc'),
  };

  function Pill({ children, color, bg, border, size=10 }) {
    return (
      <span className="ff-mono upper" style={{
        display:'inline-block', padding:'3px 8px', fontSize:size, letterSpacing:'.08em',
        background: bg || 'var(--bg-2)', color: color || 'var(--ink-2)',
        border: border ? `1px solid ${border}` : 'none', borderRadius:0,
      }}>{children}</span>
    );
  }

  function SocietyBadge({ code, country, kind }) {
    const map = {
      ASCAP: '#0c4a6e', BMI: '#9d174d', SESAC: '#1e3a8a', GMR: '#374151',
      MLC: '#065f46', PRS: '#7c2d12', SACEM: '#3730a3', GEMA: '#92400e',
      SIAE: '#831843', JASRAC: '#7e22ce', SOCAN: '#b91c1c',
      APRA: '#0e7490', ISWCNet: '#475569', MB: '#16a34a',
    };
    return (
      <span className="ff-mono" style={{
        display:'inline-flex', alignItems:'center', gap:6, fontSize:11, fontWeight:600,
        color: map[code] || 'var(--ink)',
      }}>
        <span style={{
          width:6, height:6, background: map[code] || 'var(--ink-3)', borderRadius:'50%'
        }}/>
        {code}
      </span>
    );
  }

  function SeverityChip({ sev, count }) {
    return (
      <span className="ff-mono upper" style={{
        display:'inline-flex', alignItems:'center', gap:6,
        padding:'3px 8px', fontSize:9, letterSpacing:'.1em',
        background: fmt.sevBg(sev), color: fmt.sev(sev),
        border:`1px solid ${fmt.sev(sev)}33`,
      }}>
        <span>{sev}</span>
        {count != null && <strong style={{fontSize:10}}>{count}</strong>}
      </span>
    );
  }

  // ═════════════════════════════════════════════════════════════════
  // SEARCH TAB
  // ═════════════════════════════════════════════════════════════════
  function SearchTab({ initialQuery, onAddWatch }) {
    const [title, setTitle] = useState(initialQuery?.title || '');
    const [artist, setArtist] = useState(initialQuery?.artist || '');
    const [iswc, setIswc] = useState(initialQuery?.iswc || '');
    const [societies, setSocieties] = useState(window.PROLookup.SOCIETIES.map(s => s.code));
    const [running, setRunning] = useState(false);
    const [bundle, setBundle] = useState(null);
    const [findings, setFindings] = useState([]);
    const [activeFinding, setActiveFinding] = useState(null);
    const [recentQueries, setRecentQueries] = useState(() => {
      try { return JSON.parse(localStorage.getItem('astro.prolookup.recent') || '[]'); }
      catch { return []; }
    });

    const run = async () => {
      if (!title.trim()) return;
      setRunning(true);
      setBundle(null);
      setFindings([]);
      const q = { title: title.trim(), artist: artist.trim(), iswc: iswc.trim() };
      const b = await window.PROLookup.queryAll(q, { societies });
      const f = window.PROLookup.detectConflicts(b, q);
      setBundle(b);
      setFindings(f);
      setRunning(false);
      // save to recent
      const next = [{ ...q, queriedAt: b.queriedAt }, ...recentQueries.filter(r => r.title !== q.title)].slice(0, 8);
      setRecentQueries(next);
      try { localStorage.setItem('astro.prolookup.recent', JSON.stringify(next)); } catch {}
    };

    useEffect(() => {
      if (initialQuery?.title && !bundle) run();
       // eslint-disable-next-line react-hooks/exhaustive-deps
    }, []);

    const consolidated = useMemo(() => bundle ? window.PROLookup.consolidate(bundle) : null, [bundle]);
    const sevCounts = useMemo(() => {
      const c = { critical:0, high:0, medium:0, info:0 };
      findings.forEach(f => c[f.severity]++);
      return c;
    }, [findings]);

    return (
      <div style={{display:'grid', gridTemplateColumns:'320px 1fr', gap:0, alignItems:'start'}}>
        {/* ── LEFT — query form + recent ─────────────────────────── */}
        <aside style={{borderRight:'1px solid var(--rule)', paddingRight:24, position:'sticky', top:0}}>
          <div className="ff-mono upper" style={{fontSize:10, letterSpacing:'.1em', color:'var(--ink-3)', marginBottom:12}}>
            QUERY
          </div>
          <Field label="Title" v={title} onChange={setTitle} placeholder="Levitating"/>
          <Field label="Artist (optional)" v={artist} onChange={setArtist} placeholder="Dua Lipa"/>
          <Field label="ISWC (optional)" v={iswc} onChange={setIswc} placeholder="T-123.456.789-0" mono/>

          <div style={{marginTop:18}}>
            <div className="ff-mono upper" style={{fontSize:10, letterSpacing:'.1em', color:'var(--ink-3)', marginBottom:8}}>
              SOCIETIES · {societies.length}/{window.PROLookup.SOCIETIES.length}
            </div>
            <div style={{display:'flex', flexWrap:'wrap', gap:6}}>
              {window.PROLookup.SOCIETIES.map(s => {
                const on = societies.includes(s.code);
                return (
                  <button key={s.code} onClick={() => setSocieties(on
                    ? societies.filter(c => c !== s.code)
                    : [...societies, s.code])}
                    className="ff-mono"
                    style={{
                      padding:'4px 9px', fontSize:11,
                      background: on ? 'var(--ink)' : 'transparent',
                      color: on ? 'var(--bg)' : 'var(--ink-2)',
                      border:'1px solid '+(on?'var(--ink)':'var(--rule)'),
                      cursor:'pointer',
                    }}>{s.code}</button>
                );
              })}
            </div>
            <div style={{display:'flex', gap:10, marginTop:8}}>
              <button onClick={() => setSocieties(window.PROLookup.SOCIETIES.map(s => s.code))}
                style={{background:'transparent', border:0, fontSize:11, color:'var(--ink-3)', cursor:'pointer', textDecoration:'underline'}}>
                All
              </button>
              <button onClick={() => setSocieties(window.PROLookup.SOCIETIES.filter(s => s.kind === 'PRO').map(s => s.code))}
                style={{background:'transparent', border:0, fontSize:11, color:'var(--ink-3)', cursor:'pointer', textDecoration:'underline'}}>
                PROs only
              </button>
              <button onClick={() => setSocieties([])}
                style={{background:'transparent', border:0, fontSize:11, color:'var(--ink-3)', cursor:'pointer', textDecoration:'underline'}}>
                None
              </button>
            </div>
          </div>

          <button onClick={run} disabled={running || !title.trim() || !societies.length}
            className="ff-mono upper"
            style={{
              width:'100%', marginTop:18, padding:'12px',
              background: running ? 'var(--bg-2)' : 'var(--ink)',
              color: running ? 'var(--ink-3)' : 'var(--bg)',
              border:0, fontSize:11, letterSpacing:'.1em', fontWeight:600,
              cursor: running ? 'wait' : 'pointer',
              opacity: !title.trim() || !societies.length ? 0.5 : 1,
            }}>
            {running ? 'QUERYING…' : 'QUERY ALL SOCIETIES'}
          </button>

          {bundle && onAddWatch && (
            <button onClick={() => onAddWatch({ title, artist, iswc })}
              className="ff-mono upper" style={{
                width:'100%', marginTop:8, padding:'10px',
                background:'transparent', color:'var(--ink-2)',
                border:'1px solid var(--rule)',
                fontSize:10, letterSpacing:'.1em', cursor:'pointer',
              }}>
              + ADD TO WATCHLIST
            </button>
          )}

          {recentQueries.length > 0 && (
            <div style={{marginTop:24, paddingTop:18, borderTop:'1px solid var(--rule)'}}>
              <div className="ff-mono upper" style={{fontSize:10, letterSpacing:'.1em', color:'var(--ink-3)', marginBottom:10}}>
                RECENT
              </div>
              {recentQueries.map((q, i) => (
                <button key={i} onClick={() => { setTitle(q.title); setArtist(q.artist || ''); setIswc(q.iswc || ''); }}
                  style={{
                    display:'block', width:'100%', textAlign:'left',
                    padding:'8px 0', background:'transparent', border:0, borderBottom:'1px solid var(--bg-2)',
                    cursor:'pointer',
                  }}>
                  <div style={{fontSize:13, color:'var(--ink)'}}>{q.title}</div>
                  {q.artist && <div style={{fontSize:11, color:'var(--ink-3)'}}>{q.artist}</div>}
                </button>
              ))}
            </div>
          )}
        </aside>

        {/* ── RIGHT — results ────────────────────────────────────── */}
        <section style={{paddingLeft:24, minWidth:0}}>
          {!bundle && !running && <EmptyState/>}
          {running && <RunningState societies={societies}/>}
          {bundle && (
            <ResultsView
              bundle={bundle}
              findings={findings}
              consolidated={consolidated}
              sevCounts={sevCounts}
              onPickFinding={setActiveFinding}
              activeFinding={activeFinding}
            />
          )}
        </section>
      </div>
    );
  }

  function Field({ label, v, onChange, placeholder, mono }) {
    return (
      <label style={{display:'block', marginBottom:14}}>
        <div className="ff-mono upper" style={{fontSize:10, letterSpacing:'.1em', color:'var(--ink-3)', marginBottom:6}}>
          {label}
        </div>
        <input value={v} onChange={(e) => onChange(e.target.value)} placeholder={placeholder}
          className={mono ? 'ff-mono' : ''}
          style={{
            width:'100%', padding:'8px 10px',
            border:'1px solid var(--rule)', background:'var(--bg)',
            fontSize:14, color:'var(--ink)', borderRadius:0,
          }}/>
      </label>
    );
  }

  function EmptyState() {
    return (
      <div style={{padding:'80px 0', textAlign:'center', color:'var(--ink-3)'}}>
        <div style={{fontSize:48, marginBottom:14, opacity:0.3}}>◯</div>
        <div style={{fontSize:14, marginBottom:6}}>Search a title to query 14 societies in parallel</div>
        <div style={{fontSize:12}}>Repertoire data + cross-society conflict detection</div>
      </div>
    );
  }

  function RunningState({ societies }) {
    return (
      <div style={{padding:'40px 0'}}>
        <div className="ff-mono upper" style={{fontSize:11, letterSpacing:'.1em', color:'var(--ink-2)', marginBottom:18}}>
          QUERYING {societies.length} SOCIETIES…
        </div>
        <div style={{display:'grid', gridTemplateColumns:'repeat(auto-fill, minmax(120px, 1fr))', gap:8}}>
          {societies.map(c => (
            <div key={c} style={{
              padding:'10px 12px', border:'1px solid var(--rule)',
              fontSize:12, fontFamily:'var(--ff-mono)', letterSpacing:'.05em',
              display:'flex', alignItems:'center', justifyContent:'space-between',
            }}>
              <SocietyBadge code={c}/>
              <span style={{fontSize:10, color:'var(--ink-3)'}}>···</span>
            </div>
          ))}
        </div>
      </div>
    );
  }

  // ═════════════════════════════════════════════════════════════════
  // RESULTS VIEW
  // ═════════════════════════════════════════════════════════════════
  function ResultsView({ bundle, findings, consolidated, sevCounts, onPickFinding, activeFinding }) {
    const totalHits = bundle.results.reduce((a, r) => a + r.hits.length, 0);
    const found = bundle.results.filter(r => r.hits.length > 0);
    const notFound = bundle.results.filter(r => r.hits.length === 0 && !r.error);

    return (
      <div>
        {/* HEADER STATS */}
        <div style={{
          display:'grid', gridTemplateColumns:'repeat(5, 1fr)', gap:0,
          border:'1px solid var(--rule)', marginBottom:24,
        }}>
          <Stat label="QUERIED" value={bundle.results.length}/>
          <Stat label="FOUND" value={found.length} sub={`${totalHits} hits`}/>
          <Stat label="NOT FOUND" value={notFound.length}/>
          <Stat label="CONFLICTS" value={findings.filter(f => f.severity !== 'info').length}
            color={findings.filter(f => f.severity === 'critical').length ? '#c2410c' : 'var(--ink)'}/>
          <Stat label="ELAPSED" value={`${bundle.totalMs}ms`}/>
        </div>

        {/* CONSOLIDATED CANONICAL VIEW */}
        {consolidated && <ConsolidatedCard c={consolidated}/>}

        {/* FINDINGS */}
        {findings.length > 0 && (
          <div style={{marginBottom:32}}>
            <SectionHeader title="Conflicts & findings" right={
              <div style={{display:'flex', gap:6}}>
                {Object.entries(sevCounts).filter(([,n]) => n > 0).map(([k,n]) =>
                  <SeverityChip key={k} sev={k} count={n}/>)}
              </div>
            }/>
            <div style={{border:'1px solid var(--rule)'}}>
              {findings.map((f, i) => (
                <FindingRow key={f.id + i} f={f} active={activeFinding?.id === f.id}
                  onClick={() => onPickFinding(activeFinding?.id === f.id ? null : f)}/>
              ))}
            </div>
            {activeFinding && <FindingDrawer f={activeFinding} onClose={() => onPickFinding(null)}/>}
          </div>
        )}

        {/* PER-SOCIETY GRID */}
        <SectionHeader title="By society"/>
        <div style={{display:'grid', gridTemplateColumns:'repeat(auto-fill, minmax(360px, 1fr))', gap:12}}>
          {bundle.results.map(r => <SocietyResultCard key={r.society} r={r}/>)}
        </div>
      </div>
    );
  }

  function Stat({ label, value, sub, color }) {
    return (
      <div style={{padding:'14px 16px', borderRight:'1px solid var(--rule)'}}>
        <div className="ff-mono upper" style={{fontSize:9, letterSpacing:'.1em', color:'var(--ink-3)', marginBottom:6}}>
          {label}
        </div>
        <div style={{fontSize:22, fontWeight:600, color: color || 'var(--ink)'}}>{value}</div>
        {sub && <div className="ff-mono" style={{fontSize:10, color:'var(--ink-3)', marginTop:2}}>{sub}</div>}
      </div>
    );
  }

  function SectionHeader({ title, right }) {
    return (
      <div style={{display:'flex', alignItems:'baseline', justifyContent:'space-between', marginBottom:10}}>
        <h3 style={{fontSize:13, fontWeight:600, margin:0, textTransform:'uppercase', letterSpacing:'.05em'}}>
          {title}
        </h3>
        {right}
      </div>
    );
  }

  function ConsolidatedCard({ c }) {
    return (
      <div style={{
        background:'var(--bg-2)', border:'1px solid var(--rule)', padding:18, marginBottom:24,
      }}>
        <div className="ff-mono upper" style={{fontSize:10, letterSpacing:'.1em', color:'var(--ink-3)', marginBottom:10}}>
          CONSENSUS · WHAT THE PROS COLLECTIVELY KNOW
        </div>
        <div style={{display:'grid', gridTemplateColumns:'2fr 1fr 2fr', gap:24, alignItems:'baseline'}}>
          <div>
            <div style={{fontSize:11, color:'var(--ink-3)', marginBottom:4}}>Title</div>
            <div style={{fontSize:18, fontWeight:600}}>{c.title}</div>
          </div>
          <div>
            <div style={{fontSize:11, color:'var(--ink-3)', marginBottom:4}}>ISWC</div>
            <div className="ff-mono" style={{fontSize:14}}>{c.iswc || '—'}</div>
          </div>
          <div>
            <div style={{fontSize:11, color:'var(--ink-3)', marginBottom:4}}>Writers</div>
            <div style={{fontSize:13}}>
              {c.writers.slice(0, 3).map(w => `${w.name} ${w.share}%`).join(' · ')}
              {c.writers.length > 3 && <span style={{color:'var(--ink-3)'}}> · +{c.writers.length - 3} more</span>}
            </div>
          </div>
        </div>
      </div>
    );
  }

  function FindingRow({ f, active, onClick }) {
    return (
      <button onClick={onClick} style={{
        width:'100%', display:'grid', gridTemplateColumns:'90px 1fr 200px 100px',
        gap:14, alignItems:'center', padding:'12px 14px', textAlign:'left',
        background: active ? 'var(--bg-2)' : 'transparent',
        border:0, borderBottom:'1px solid var(--rule-soft, var(--bg-2))',
        cursor:'pointer',
      }}>
        <SeverityChip sev={f.severity}/>
        <div>
          <div style={{fontSize:13, fontWeight:600, color:'var(--ink)'}}>{f.message}</div>
          <div style={{fontSize:11, color:'var(--ink-3)', marginTop:2,
            overflow:'hidden', textOverflow:'ellipsis', whiteSpace:'nowrap', maxWidth:'100%'}}>
            {f.details}
          </div>
        </div>
        <div style={{fontSize:11, color:'var(--ink-2)'}}>
          {f.societies.slice(0, 4).map((s, i) => <span key={i} style={{marginRight:8}}><SocietyBadge code={s}/></span>)}
          {f.societies.length > 4 && <span style={{color:'var(--ink-3)'}}>+{f.societies.length - 4}</span>}
        </div>
        <div className="ff-mono upper" style={{fontSize:10, color:'var(--ink-2)', textAlign:'right'}}>
          {f.suggested?.label || '—'} →
        </div>
      </button>
    );
  }

  function FindingDrawer({ f, onClose }) {
    return (
      <div style={{
        marginTop:14, border:'1px solid var(--ink)', background:'var(--bg)', padding:18,
      }}>
        <div style={{display:'flex', justifyContent:'space-between', alignItems:'baseline', marginBottom:10}}>
          <div style={{display:'flex', gap:10, alignItems:'baseline'}}>
            <SeverityChip sev={f.severity}/>
            <h4 style={{margin:0, fontSize:14}}>{f.message}</h4>
          </div>
          <button onClick={onClose} style={{background:'transparent', border:0, fontSize:18, cursor:'pointer', color:'var(--ink-3)'}}>✕</button>
        </div>
        <div style={{fontSize:12, color:'var(--ink-2)', marginBottom:14, lineHeight:1.55}}>
          {f.details}
        </div>
        <div style={{display:'flex', gap:8}}>
          <button className="ff-mono upper" style={{
            padding:'8px 14px', fontSize:10, letterSpacing:'.1em',
            background:'var(--ink)', color:'var(--bg)', border:0, cursor:'pointer',
          }}>
            {f.suggested?.label || 'Resolve'}
          </button>
          <button className="ff-mono upper" style={{
            padding:'8px 14px', fontSize:10, letterSpacing:'.1em',
            background:'transparent', color:'var(--ink-2)',
            border:'1px solid var(--rule)', cursor:'pointer',
          }}>
            ADD TO WATCHLIST
          </button>
          <button className="ff-mono upper" style={{
            padding:'8px 14px', fontSize:10, letterSpacing:'.1em',
            background:'transparent', color:'var(--ink-2)',
            border:'1px solid var(--rule)', cursor:'pointer',
          }}>
            DISMISS
          </button>
        </div>
      </div>
    );
  }

  function SocietyResultCard({ r }) {
    const isErr = !!r.error;
    const isEmpty = !isErr && r.hits.length === 0;
    return (
      <div style={{
        border:'1px solid var(--rule)', padding:14,
        background: isEmpty ? 'var(--bg-2)' : 'var(--bg)',
        opacity: isEmpty ? 0.7 : 1,
      }}>
        <div style={{display:'flex', justifyContent:'space-between', alignItems:'baseline', marginBottom:10}}>
          <div>
            <SocietyBadge code={r.society}/>
            <span style={{fontSize:11, color:'var(--ink-3)', marginLeft:8}}>{r.societyName}</span>
          </div>
          <span className="ff-mono" style={{fontSize:10, color:'var(--ink-3)'}}>{r.ms}ms</span>
        </div>
        {isErr && <div style={{fontSize:11, color:'#c2410c'}}>Error: {r.error}</div>}
        {isEmpty && <div style={{fontSize:12, color:'var(--ink-3)', fontStyle:'italic'}}>Not registered.</div>}
        {r.hits.map((h, i) => (
          <div key={i} style={{
            paddingTop: i > 0 ? 10 : 0, marginTop: i > 0 ? 10 : 0,
            borderTop: i > 0 ? '1px dashed var(--rule)' : 0,
          }}>
            <div style={{display:'flex', alignItems:'baseline', gap:10, marginBottom:6}}>
              <strong style={{fontSize:13}}>{h.title}</strong>
              <Pill bg={h.status === 'REGISTERED' ? '#dcfce7' : h.status === 'DISPUTED' ? '#fef2f2' : '#fef3c7'}
                color={h.status === 'REGISTERED' ? '#15803d' : h.status === 'DISPUTED' ? '#b91c1c' : '#92400e'}>
                {h.status}
              </Pill>
            </div>
            <div className="ff-mono" style={{fontSize:11, color:'var(--ink-3)', marginBottom:8, display:'flex', gap:14, flexWrap:'wrap'}}>
              <span>WORK · {h.societyWorkId}</span>
              {h.iswc && <span>ISWC · {h.iswc}</span>}
              <span>FILED · {h.registeredAt}</span>
            </div>
            <table style={{width:'100%', fontSize:11, borderCollapse:'collapse'}}>
              <thead>
                <tr style={{color:'var(--ink-3)', textAlign:'left'}}>
                  <th style={{fontWeight:400, padding:'4px 0'}}>WRITER</th>
                  <th style={{fontWeight:400, padding:'4px 0'}}>ROLE</th>
                  <th style={{fontWeight:400, padding:'4px 0'}}>IPI</th>
                  <th style={{fontWeight:400, padding:'4px 0', textAlign:'right'}}>%</th>
                </tr>
              </thead>
              <tbody>
                {h.writers.map((w, j) => (
                  <tr key={j} style={{borderTop:'1px solid var(--bg-2)'}}>
                    <td style={{padding:'4px 0'}}>{w.name}</td>
                    <td className="ff-mono" style={{padding:'4px 0', color:'var(--ink-3)'}}>{w.role}</td>
                    <td className="ff-mono" style={{padding:'4px 0', color:'var(--ink-3)'}}>{w.ipi}</td>
                    <td className="ff-mono num" style={{padding:'4px 0', textAlign:'right'}}>{w.share}%</td>
                  </tr>
                ))}
              </tbody>
            </table>
          </div>
        ))}
      </div>
    );
  }

  // ═════════════════════════════════════════════════════════════════
  // CATALOG SCAN TAB
  // ═════════════════════════════════════════════════════════════════
  function ScanTab() {
    const [running, setRunning] = useState(false);
    const [results, setResults] = useState([]);
    const [progress, setProgress] = useState(0);

    // pull a sample from the catalog
    const works = useMemo(() => {
      const w = (window.RS?.works || []).slice(0, 25);
      return w;
    }, []);

    const run = async () => {
      setRunning(true); setResults([]); setProgress(0);
      const out = [];
      for (let i = 0; i < works.length; i++) {
        const w = works[i];
        const q = { title: w.title, artist: w.primary_artist || '', iswc: w.iswc || '', internal: { title: w.title, iswc: w.iswc } };
        const bundle = await window.PROLookup.queryAll(q);
        const findings = window.PROLookup.detectConflicts(bundle, q.internal);
        out.push({ work: w, bundle, findings });
        setProgress(i + 1);
        setResults([...out]);
      }
      setRunning(false);
    };

    const summary = useMemo(() => {
      const c = { critical:0, high:0, medium:0, info:0 };
      results.forEach(r => r.findings.forEach(f => c[f.severity]++));
      return c;
    }, [results]);

    return (
      <div>
        <div style={{display:'flex', alignItems:'baseline', justifyContent:'space-between', marginBottom:18}}>
          <div>
            <h3 style={{margin:0, fontSize:15, fontWeight:600}}>Catalog scan</h3>
            <div style={{fontSize:12, color:'var(--ink-3)', marginTop:4}}>
              Query every PRO for the first {works.length} works in your catalog.
            </div>
          </div>
          <button onClick={run} disabled={running || !works.length}
            className="ff-mono upper"
            style={{
              padding:'10px 16px', fontSize:11, letterSpacing:'.1em',
              background: running ? 'var(--bg-2)' : 'var(--ink)',
              color: running ? 'var(--ink-3)' : 'var(--bg)',
              border:0, cursor: running ? 'wait' : 'pointer',
            }}>
            {running ? `SCANNING… ${progress}/${works.length}` : `SCAN ${works.length} WORKS`}
          </button>
        </div>

        {results.length > 0 && (
          <div style={{
            display:'grid', gridTemplateColumns:'repeat(4, 1fr)',
            border:'1px solid var(--rule)', marginBottom:18,
          }}>
            <Stat label="WORKS SCANNED" value={results.length}/>
            <Stat label="WITH CRITICAL" value={results.filter(r => r.findings.some(f => f.severity === 'critical')).length} color="#c2410c"/>
            <Stat label="WITH HIGH" value={results.filter(r => r.findings.some(f => f.severity === 'high')).length} color="#b45309"/>
            <Stat label="CLEAN" value={results.filter(r => !r.findings.some(f => f.severity === 'critical' || f.severity === 'high')).length} color="#15803d"/>
          </div>
        )}

        {results.length > 0 && (
          <div style={{border:'1px solid var(--rule)'}}>
            <div style={{
              display:'grid', gridTemplateColumns:'2fr 80px 80px 80px 80px 1fr',
              gap:14, padding:'10px 14px', background:'var(--bg-2)',
              fontSize:10, fontFamily:'var(--ff-mono)', textTransform:'uppercase', letterSpacing:'.1em',
              color:'var(--ink-3)',
            }}>
              <div>WORK</div><div>FOUND</div><div style={{color:'#c2410c'}}>CRIT</div>
              <div style={{color:'#b45309'}}>HIGH</div><div style={{color:'#0369a1'}}>MED</div>
              <div>TOP CONFLICT</div>
            </div>
            {results.map((r, i) => {
              const sev = { critical:0, high:0, medium:0, info:0 };
              r.findings.forEach(f => sev[f.severity]++);
              const found = r.bundle.results.filter(x => x.hits.length > 0).length;
              const top = r.findings[0];
              return (
                <div key={i} style={{
                  display:'grid', gridTemplateColumns:'2fr 80px 80px 80px 80px 1fr',
                  gap:14, padding:'10px 14px', borderTop:'1px solid var(--bg-2)', fontSize:12, alignItems:'center',
                }}>
                  <div style={{minWidth:0, overflow:'hidden', textOverflow:'ellipsis', whiteSpace:'nowrap'}}>
                    {r.work.title}
                  </div>
                  <div className="ff-mono num">{found}</div>
                  <div className="ff-mono num" style={{color: sev.critical ? '#c2410c' : 'var(--ink-3)'}}>{sev.critical || '—'}</div>
                  <div className="ff-mono num" style={{color: sev.high ? '#b45309' : 'var(--ink-3)'}}>{sev.high || '—'}</div>
                  <div className="ff-mono num" style={{color: sev.medium ? '#0369a1' : 'var(--ink-3)'}}>{sev.medium || '—'}</div>
                  <div style={{fontSize:11, color:'var(--ink-3)', overflow:'hidden', textOverflow:'ellipsis', whiteSpace:'nowrap'}}>
                    {top ? top.message : 'Clean ✓'}
                  </div>
                </div>
              );
            })}
          </div>
        )}

        {!results.length && !running && (
          <div style={{padding:'60px 0', textAlign:'center', color:'var(--ink-3)', fontSize:13}}>
            Run a scan to surface cross-society conflicts across your catalog.
          </div>
        )}
      </div>
    );
  }

  // ═════════════════════════════════════════════════════════════════
  // ADAPTERS TAB
  // ═════════════════════════════════════════════════════════════════
  function AdaptersTab() {
    return (
      <div>
        <div style={{
          padding:14, background:'#fffbeb', border:'1px solid #fde68a',
          fontSize:12, color:'#92400e', marginBottom:18,
        }}>
          <strong>DEMO MODE.</strong> Society endpoints are simulated with deterministic stubs.
          The adapter interface is wire-compatible — a backend integration can swap in real fetches without UI changes.
        </div>

        <div style={{border:'1px solid var(--rule)'}}>
          <div style={{
            display:'grid', gridTemplateColumns:'120px 1fr 80px 100px 120px 1fr',
            gap:14, padding:'10px 14px', background:'var(--bg-2)',
            fontSize:10, fontFamily:'var(--ff-mono)', textTransform:'uppercase', letterSpacing:'.1em', color:'var(--ink-3)',
          }}>
            <div>SOCIETY</div><div>NAME</div><div>COUNTRY</div><div>KIND</div><div>SCOPE</div><div>ENDPOINT</div>
          </div>
          {window.PROLookup.SOCIETIES.map(s => (
            <div key={s.code} style={{
              display:'grid', gridTemplateColumns:'120px 1fr 80px 100px 120px 1fr',
              gap:14, padding:'10px 14px', borderTop:'1px solid var(--bg-2)', fontSize:12, alignItems:'center',
            }}>
              <div><SocietyBadge code={s.code}/></div>
              <div>{s.name}</div>
              <div className="ff-mono">{s.country}</div>
              <div><Pill>{s.kind}</Pill></div>
              <div className="ff-mono" style={{fontSize:11}}>{s.scope}</div>
              <div className="ff-mono" style={{fontSize:10, color:'var(--ink-3)'}}>
                {{
                  ASCAP:'ascap.com/repertory',
                  BMI:'repertoire.bmi.com',
                  SESAC:'sesac.com/repertory',
                  GMR:'globalmusicrights.com',
                  MLC:'portal.themlc.com',
                  PRS:'prsformusic.com',
                  SACEM:'repertoire.sacem.fr',
                  GEMA:'online.gema.de',
                  SIAE:'siae.it',
                  JASRAC:'jasrac.or.jp',
                  SOCAN:'socan.com',
                  APRA:'apraamcos.com.au',
                  ISWCNet:'iswcnet.cisac.org',
                  MB:'musicbrainz.org',
                }[s.code]}
              </div>
            </div>
          ))}
        </div>
      </div>
    );
  }

  // ═════════════════════════════════════════════════════════════════
  // WATCHLIST
  // ═════════════════════════════════════════════════════════════════
  function WatchlistTab({ items, onRemove }) {
    return (
      <div>
        <div style={{display:'flex', alignItems:'baseline', justifyContent:'space-between', marginBottom:18}}>
          <div>
            <h3 style={{margin:0, fontSize:15}}>Watchlist</h3>
            <div style={{fontSize:12, color:'var(--ink-3)', marginTop:4}}>
              Works flagged for periodic re-check. Re-runs on a configurable cadence.
            </div>
          </div>
        </div>
        {items.length === 0 ? (
          <div style={{padding:'60px 0', textAlign:'center', color:'var(--ink-3)', fontSize:13}}>
            No works on watchlist. Add from a search result or finding.
          </div>
        ) : (
          <div style={{border:'1px solid var(--rule)'}}>
            <div style={{
              display:'grid', gridTemplateColumns:'2fr 1fr 1fr 100px 80px',
              gap:14, padding:'10px 14px', background:'var(--bg-2)',
              fontSize:10, fontFamily:'var(--ff-mono)', textTransform:'uppercase', letterSpacing:'.1em', color:'var(--ink-3)',
            }}>
              <div>WORK</div><div>ARTIST</div><div>ADDED</div><div>CADENCE</div><div></div>
            </div>
            {items.map((it, i) => (
              <div key={i} style={{
                display:'grid', gridTemplateColumns:'2fr 1fr 1fr 100px 80px',
                gap:14, padding:'10px 14px', borderTop:'1px solid var(--bg-2)', fontSize:12, alignItems:'center',
              }}>
                <div>{it.title}</div>
                <div style={{color:'var(--ink-3)'}}>{it.artist || '—'}</div>
                <div className="ff-mono" style={{fontSize:10, color:'var(--ink-3)'}}>
                  {new Date(it.addedAt).toLocaleDateString()}
                </div>
                <div><Pill>WEEKLY</Pill></div>
                <div>
                  <button onClick={() => onRemove(i)}
                    style={{background:'transparent', border:0, fontSize:11, color:'var(--ink-3)', cursor:'pointer', textDecoration:'underline'}}>
                    remove
                  </button>
                </div>
              </div>
            ))}
          </div>
        )}
      </div>
    );
  }

  // ═════════════════════════════════════════════════════════════════
  // HOW IT WORKS
  // ═════════════════════════════════════════════════════════════════
  function HowItWorksTab() {
    return (
      <div style={{maxWidth:760, fontSize:14, lineHeight:1.65, color:'var(--ink-2)'}}>
        <h3 style={{fontSize:16, marginTop:0}}>How PRO Lookup works</h3>
        <p>
          When you query a work, ASTRO fans out to 14 society repertoire endpoints in parallel —
          ASCAP, BMI, SESAC, GMR, MLC (US); PRS, SACEM, GEMA, SIAE (EU); JASRAC (JP); SOCAN, APRA AMCOS;
          plus ISWCNet (CISAC) and MusicBrainz as cross-society backstops.
          Each adapter normalizes the response into a single shape so we can compare across sources.
        </p>

        <h4 style={{fontSize:14, marginTop:24, marginBottom:8}}>Conflict detector</h4>
        <p>The detector runs eight rule families against every result bundle:</p>
        <ul style={{paddingLeft:20}}>
          <li><strong>ISWC mismatch</strong> — different ISWCs registered at different societies (critical)</li>
          <li><strong>ISWC missing</strong> — present elsewhere, missing here (high)</li>
          <li><strong>Title drift</strong> — same work, different titles (medium)</li>
          <li><strong>Writer missing</strong> — registered party absent at one or more societies (critical)</li>
          <li><strong>IPI mismatch</strong> — same writer, different IPI numbers (high)</li>
          <li><strong>Share drift</strong> — split percentages disagree across societies (high)</li>
          <li><strong>Share total ≠ 100%</strong> — at any single society (critical)</li>
          <li><strong>Duplicate registration</strong> — same society has multiple work IDs (critical)</li>
          <li><strong>Status</strong> — DISPUTED or PENDING surfaces inline</li>
          <li><strong>Internal mismatch</strong> — your catalog disagrees with PRO consensus (medium/high)</li>
        </ul>

        <h4 style={{fontSize:14, marginTop:24, marginBottom:8}}>Suggested actions</h4>
        <p>
          Each finding ships with a one-click action: <em>Generate REV</em> to push corrections via CWR,
          <em> Open dispute</em> to start a society-level claim, <em>Update catalog</em> to align internal records,
          or <em>Watchlist</em> to re-check on a schedule.
        </p>

        <h4 style={{fontSize:14, marginTop:24, marginBottom:8}}>Prototype scope</h4>
        <p style={{padding:14, background:'#fffbeb', border:'1px solid #fde68a', color:'#92400e'}}>
          The prototype runs adapters as <strong>deterministic offline stubs</strong> — same query always returns the
          same realistic, conflict-laden result. The adapter interface is wire-compatible with a real backend; in
          production each adapter would proxy to the corresponding society's public-search HTTP endpoint.
        </p>
      </div>
    );
  }

  // ═════════════════════════════════════════════════════════════════
  // MAIN SCREEN
  // ═════════════════════════════════════════════════════════════════
  function ScreenPROLookup({ go, payload }) {
    const PageHeader = window.PageHeader;
    const [tab, setTab] = useState(payload?.tab || 'search');
    const [watchlist, setWatchlist] = useState(() => {
      try { return JSON.parse(localStorage.getItem('astro.prolookup.watch') || '[]'); }
      catch { return []; }
    });
    const persistWatch = (next) => {
      setWatchlist(next);
      try { localStorage.setItem('astro.prolookup.watch', JSON.stringify(next)); } catch {}
    };
    const addWatch = (q) => persistWatch([{ ...q, addedAt: new Date().toISOString() }, ...watchlist]);
    const removeWatch = (i) => persistWatch(watchlist.filter((_, j) => j !== i));

    const TABS = [
      { k:'search',  l:'Search' },
      { k:'scan',    l:'Catalog scan' },
      { k:'watch',   l:'Watchlist', n: watchlist.length },
      { k:'adapters',l:'Adapters', n: window.PROLookup.SOCIETIES.length },
      { k:'how',     l:'How it works' },
    ];

    return (
      <div>
        {PageHeader && (
          <PageHeader
            eyebrow={['REGISTRATIONS', 'PRO LOOKUP', `${window.PROLookup.SOCIETIES.length} SOCIETIES`]}
            title="PRO Lookup"
            highlight="Lookup"
            sub="Query 14 societies in parallel to validate titles, writers, composers, and ISWCs against their public repertoire databases. Cross-PRO conflict detection surfaces share drift, IPI mismatches, missing writers, and duplicate registrations — each with a one-click reconciliation path."
          />
        )}

        <div style={{borderBottom:'1px solid var(--rule)', display:'flex', gap:0}}>
          {TABS.map(t => (
            <button key={t.k} onClick={() => setTab(t.k)} className="ff-mono upper" style={{
              padding:'14px 18px', fontSize:11, fontWeight:600, letterSpacing:'.08em',
              background:'transparent', border:0,
              borderBottom: tab === t.k ? '3px solid var(--ink)' : '3px solid transparent',
              marginBottom:-1, color: tab === t.k ? 'var(--ink)' : 'var(--ink-3)',
              cursor:'pointer', display:'flex', gap:8, alignItems:'baseline',
            }}>
              {t.l}
              {t.n != null && <span className="ff-mono num" style={{fontSize:10, color:'var(--ink-3)'}}>{t.n}</span>}
            </button>
          ))}
        </div>

        <div style={{paddingTop:24}}>
          {tab === 'search' && <SearchTab initialQuery={payload?.initialQuery} onAddWatch={addWatch}/>}
          {tab === 'scan' && <ScanTab/>}
          {tab === 'watch' && <WatchlistTab items={watchlist} onRemove={removeWatch}/>}
          {tab === 'adapters' && <AdaptersTab/>}
          {tab === 'how' && <HowItWorksTab/>}
        </div>
      </div>
    );
  }

  // ═════════════════════════════════════════════════════════════════
  // EMBEDDED PANEL — for work-detail / recording-detail surfaces
  // ═════════════════════════════════════════════════════════════════
  function PROLookupPanel({ title, artist, iswc, go }) {
    const [bundle, setBundle] = useState(null);
    const [findings, setFindings] = useState([]);
    const [loading, setLoading] = useState(false);

    const run = async () => {
      if (!title) return;
      setLoading(true);
      const b = await window.PROLookup.queryAll({ title, artist, iswc });
      const f = window.PROLookup.detectConflicts(b, { title, iswc });
      setBundle(b); setFindings(f); setLoading(false);
    };

    const sevCounts = useMemo(() => {
      const c = { critical:0, high:0, medium:0, info:0 };
      findings.forEach(f => c[f.severity]++);
      return c;
    }, [findings]);

    return (
      <div style={{border:'1px solid var(--rule)', padding:18}}>
        <div style={{display:'flex', alignItems:'baseline', justifyContent:'space-between', marginBottom:12}}>
          <div>
            <div className="ff-mono upper" style={{fontSize:10, letterSpacing:'.1em', color:'var(--ink-3)', marginBottom:4}}>
              PRO LOOKUP
            </div>
            <h4 style={{margin:0, fontSize:14}}>Repertoire validation across 14 societies</h4>
          </div>
          <div style={{display:'flex', gap:8}}>
            {!bundle && (
              <button onClick={run} disabled={loading} className="ff-mono upper" style={{
                padding:'8px 14px', fontSize:10, letterSpacing:'.1em',
                background: loading ? 'var(--bg-2)' : 'var(--ink)',
                color: loading ? 'var(--ink-3)' : 'var(--bg)', border:0, cursor:'pointer',
              }}>{loading ? 'QUERYING…' : 'QUERY ALL'}</button>
            )}
            <button onClick={() => go && go('pro-lookup', { initialQuery: { title, artist, iswc } })}
              className="ff-mono upper" style={{
                padding:'8px 14px', fontSize:10, letterSpacing:'.1em',
                background:'transparent', color:'var(--ink-2)',
                border:'1px solid var(--rule)', cursor:'pointer',
              }}>OPEN FULL →</button>
          </div>
        </div>

        {!bundle && !loading && (
          <div style={{fontSize:12, color:'var(--ink-3)'}}>
            Click <strong>Query all</strong> to validate this work's registration across ASCAP, BMI, SESAC, GMR, MLC, PRS, SACEM, GEMA, SIAE, JASRAC, SOCAN, APRA, ISWCNet & MusicBrainz.
          </div>
        )}

        {bundle && (
          <>
            <div style={{display:'flex', gap:8, marginBottom:14}}>
              <Pill>{bundle.results.filter(r => r.hits.length).length}/{bundle.results.length} FOUND</Pill>
              {Object.entries(sevCounts).filter(([,n]) => n > 0).map(([k, n]) =>
                <SeverityChip key={k} sev={k} count={n}/>)}
              <span className="ff-mono" style={{fontSize:10, color:'var(--ink-3)', marginLeft:'auto'}}>
                {bundle.totalMs}ms
              </span>
            </div>

            <div style={{display:'grid', gridTemplateColumns:'repeat(7, 1fr)', gap:4, marginBottom:14}}>
              {bundle.results.map(r => (
                <div key={r.society} style={{
                  padding:'8px 6px', textAlign:'center',
                  background: r.hits.length ? '#dcfce7' : '#fee2e2',
                  border:'1px solid '+(r.hits.length ? '#86efac' : '#fecaca'),
                  fontSize:10, fontFamily:'var(--ff-mono)', fontWeight:600,
                }}>
                  <div>{r.society}</div>
                  <div style={{fontSize:8, color: r.hits.length ? '#15803d' : '#b91c1c', marginTop:2}}>
                    {r.hits.length ? `${r.hits.length} HIT${r.hits.length > 1 ? 'S' : ''}` : 'NONE'}
                  </div>
                </div>
              ))}
            </div>

            {findings.slice(0, 4).map((f, i) => (
              <div key={i} style={{
                display:'flex', gap:10, alignItems:'center',
                padding:'8px 0', borderTop: i > 0 ? '1px solid var(--bg-2)' : 0, fontSize:12,
              }}>
                <SeverityChip sev={f.severity}/>
                <div style={{flex:1, minWidth:0}}>
                  <div style={{overflow:'hidden', textOverflow:'ellipsis', whiteSpace:'nowrap'}}>
                    {f.message}
                  </div>
                </div>
              </div>
            ))}
            {findings.length > 4 && (
              <div style={{paddingTop:8, fontSize:11, color:'var(--ink-3)'}}>
                +{findings.length - 4} more findings · open full screen to review
              </div>
            )}
          </>
        )}
      </div>
    );
  }

  Object.assign(window, { ScreenPROLookup, PROLookupPanel });
  console.log('[pro-lookup] loaded');
})();
