// ───────────────────────────────────────────────────────────── BULK SELECT
// Cross-component multi-select for catalog tabs.
// Selection state lives on window.__bulkSelect[scope] (a Set of ids) so
// SongsView (songs.jsx), RecordingsView (screens3.jsx), and the action bar
// in screens.jsx can all touch the same store across Babel scopes.

(function(){
  const Bus = (window.__bulkSelect ||= { scopes: {} });

  function getStore(scope) {
    if (!Bus.scopes[scope]) Bus.scopes[scope] = { ids: new Set(), order: [] };
    return Bus.scopes[scope];
  }
  function emit(scope) {
    window.dispatchEvent(new CustomEvent('astro-bulk-changed', { detail: { scope } }));
  }

  window.bulkSelect = {
    has: (scope, id) => getStore(scope).ids.has(id),
    size: (scope) => getStore(scope).ids.size,
    list: (scope) => Array.from(getStore(scope).ids),
    order: (scope) => getStore(scope).order.slice(),
    toggle: (scope, id) => {
      const s = getStore(scope);
      if (s.ids.has(id)) s.ids.delete(id); else s.ids.add(id);
      emit(scope);
    },
    add: (scope, id) => { getStore(scope).ids.add(id); emit(scope); },
    set: (scope, ids) => {
      const s = getStore(scope);
      s.ids = new Set(ids);
      emit(scope);
    },
    setOrder: (scope, ids) => { getStore(scope).order = ids.slice(); },
    clear: (scope) => {
      const s = getStore(scope);
      if (s.ids.size === 0) return;
      s.ids = new Set();
      emit(scope);
    },
    selectRange: (scope, ids, fromId, toId) => {
      const s = getStore(scope);
      const i = ids.indexOf(fromId), j = ids.indexOf(toId);
      if (i < 0 || j < 0) return;
      const [a,b] = i < j ? [i,j] : [j,i];
      for (let k = a; k <= b; k++) s.ids.add(ids[k]);
      emit(scope);
    },
  };
})();

const { useBulkSel: __useBulkSel_ } = (() => {
  function _useBulkSel(scope) {
    const [, force] = React.useReducer(x=>x+1, 0);
    React.useEffect(() => {
      const onChange = (e) => { if (!e.detail || e.detail.scope === scope) force(); };
      window.addEventListener('astro-bulk-changed', onChange);
      return () => window.removeEventListener('astro-bulk-changed', onChange);
    }, [scope]);
    const api = window.bulkSelect;
    return {
      selected: api.list(scope),
      count: api.size(scope),
      has: (id) => api.has(scope, id),
      toggle: (id) => api.toggle(scope, id),
      clear: () => api.clear(scope),
      set: (ids) => api.set(scope, ids),
      add: (id) => api.add(scope, id),
      selectRange: (ids, from, to) => api.selectRange(scope, ids, from, to),
    };
  }
  return { useBulkSel: _useBulkSel };
})();

// React hook wrapper
function useBulkSel(scope) { return __useBulkSel_(scope); }

// Last-clicked id per scope, for shift-click range select.
const __bulkLast = {};

// ── Row checkbox ──────────────────────────────────────────────────────────
function BulkCheckbox({ scope, id, allIds, size = 14, style }) {
  const sel = useBulkSel(scope);
  const checked = sel.has(id);
  return (
    <span
      role="checkbox"
      aria-checked={checked}
      tabIndex={0}
      onClick={(e) => {
        e.stopPropagation();
        if (e.shiftKey && __bulkLast[scope] && Array.isArray(allIds)) {
          sel.selectRange(allIds, __bulkLast[scope], id);
        } else {
          sel.toggle(id);
        }
        __bulkLast[scope] = id;
      }}
      onKeyDown={(e) => {
        if (e.key === ' ' || e.key === 'Enter') { e.preventDefault(); sel.toggle(id); __bulkLast[scope] = id; }
      }}
      style={{
        width: size, height: size, display: 'inline-flex', alignItems: 'center', justifyContent: 'center',
        border: `1.5px solid ${checked ? 'var(--ink)' : 'var(--rule)'}`,
        background: checked ? 'var(--ink)' : 'var(--bg)',
        color: 'var(--bg)', cursor: 'pointer', flex: '0 0 auto',
        transition: 'border-color .1s, background .1s',
        ...style,
      }}>
      {checked && <svg width={size-4} height={size-4} viewBox="0 0 12 12" fill="none" stroke="currentColor" strokeWidth="2"><path d="M2.5 6.5 5 9l4.5-5"/></svg>}
    </span>
  );
}

// Header "select all" checkbox (tri-state)
function BulkHeaderCheckbox({ scope, allIds, size = 14, style }) {
  const sel = useBulkSel(scope);
  const total = (allIds || []).length;
  const selectedInList = (allIds || []).filter(id => sel.has(id)).length;
  const all = total > 0 && selectedInList === total;
  const some = selectedInList > 0 && !all;
  return (
    <span
      role="checkbox"
      aria-checked={all ? 'true' : some ? 'mixed' : 'false'}
      tabIndex={0}
      title={all ? 'Deselect all' : 'Select all'}
      onClick={(e) => {
        e.stopPropagation();
        if (all || some) sel.clear();
        else sel.set(allIds || []);
      }}
      onKeyDown={(e) => {
        if (e.key === ' ' || e.key === 'Enter') { e.preventDefault(); (all || some) ? sel.clear() : sel.set(allIds || []); }
      }}
      style={{
        width: size, height: size, display: 'inline-flex', alignItems: 'center', justifyContent: 'center',
        border: `1.5px solid ${(all || some) ? 'var(--ink)' : 'var(--rule)'}`,
        background: all ? 'var(--ink)' : 'var(--bg)',
        color: 'var(--bg)', cursor: 'pointer', flex: '0 0 auto',
        ...style,
      }}>
      {all && <svg width={size-4} height={size-4} viewBox="0 0 12 12" fill="none" stroke="currentColor" strokeWidth="2"><path d="M2.5 6.5 5 9l4.5-5"/></svg>}
      {some && <span style={{width: size-6, height: 2, background: 'var(--ink)'}}/>}
    </span>
  );
}

// ── Action bar (sticky, appears when count > 0) ───────────────────────────
function BulkActionBar({ scope, kind /* 'songs' | 'recordings' */, onAction }) {
  const sel = useBulkSel(scope);
  if (sel.count === 0) return null;
  const noun = kind === 'recordings' ? 'recording' : 'work';
  const plural = sel.count === 1 ? noun : noun + 's';
  const Btn = window.Btn, Ic = window.Ic;

  // Action set varies a touch by kind
  const TrashIc = (p) => <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5" {...p}><path d="M4 7h16M9 7V4h6v3M6 7l1 14h10l1-14M10 11v6M14 11v6"/></svg>;
  const actions = kind === 'recordings'
    ? [
        { id: 'register-cwr', label: 'Register CWR', icon: <Ic.Send/>, primary: true, hint: 'Submit selected to societies' },
        { id: 'tag', label: 'Add tag', icon: <Ic.Tag/> },
        { id: 'change-label', label: 'Change label', icon: <Ic.Build/> },
        { id: 'export', label: 'Export CSV', icon: <Ic.File/> },
        { id: 'delete', label: 'Delete', icon: <TrashIc/>, danger: true },
      ]
    : [
        { id: 'register-cwr', label: 'Register CWR', icon: <Ic.Send/>, primary: true, hint: 'Generate CWR registration' },
        { id: 'change-publisher', label: 'Change publisher', icon: <Ic.Build/> },
        { id: 'tag', label: 'Add tag', icon: <Ic.Tag/> },
        { id: 'export', label: 'Export CSV', icon: <Ic.File/> },
        { id: 'delete', label: 'Delete', icon: <TrashIc/>, danger: true },
      ];

  return (
    <div role="toolbar" aria-label={`${sel.count} ${plural} selected`}
      style={{
        position: 'sticky', top: 0, zIndex: 20,
        display: 'flex', alignItems: 'center', gap: 12, flexWrap: 'wrap',
        padding: '10px 14px',
        background: 'var(--ink)', color: 'var(--bg)',
        borderBottom: '1px solid var(--ink)',
        boxShadow: '0 6px 0 rgba(0,0,0,.08)',
      }}>
      <button onClick={() => sel.clear()} aria-label="Clear selection"
        className="ff-mono"
        style={{
          width: 22, height: 22, border: '1px solid rgba(255,255,255,.4)',
          background: 'transparent', color: 'var(--bg)', cursor: 'pointer',
          fontSize: 14, lineHeight: 1, padding: 0,
        }}>×</button>
      <span className="ff-mono num" style={{fontSize: 18, fontWeight: 700, letterSpacing: '-0.01em'}}>
        {sel.count}
      </span>
      <span className="ff-mono upper" style={{fontSize: 10, letterSpacing: '.12em', opacity: .75}}>
        {plural} selected
      </span>
      <span style={{flex: 1}}/>
      {actions.map(a => (
        <button key={a.id} onClick={() => onAction(a.id, sel.selected)}
          className="ff-mono upper"
          title={a.hint || a.label}
          style={{
            display: 'inline-flex', alignItems: 'center', gap: 6,
            padding: '7px 12px', fontSize: 10, letterSpacing: '.1em',
            background: a.primary ? 'var(--bg)' : 'transparent',
            color: a.primary ? 'var(--ink)' : (a.danger ? '#ff8a7a' : 'var(--bg)'),
            border: a.primary ? 0 : `1px solid ${a.danger ? 'rgba(255,138,122,.5)' : 'rgba(255,255,255,.4)'}`,
            cursor: 'pointer', fontWeight: a.primary ? 700 : 600,
          }}>
          {React.cloneElement(a.icon, { width: 12, height: 12 })}
          {a.label}
        </button>
      ))}
    </div>
  );
}

// ── Bulk action confirm modal ─────────────────────────────────────────────
function BulkActionModal({ action, scope, kind, ids, onClose }) {
  const Btn = window.Btn, Ic = window.Ic;
  const sel = useBulkSel(scope);
  const noun = kind === 'recordings' ? 'recording' : 'work';
  const plural = ids.length === 1 ? noun : noun + 's';
  const [tagText, setTagText] = React.useState('');
  const [pubText, setPubText] = React.useState('');
  const [labelText, setLabelText] = React.useState('');
  const [societies, setSocieties] = React.useState(['ASCAP','BMI','PRS']);
  const [confirmText, setConfirmText] = React.useState('');

  const titleMap = {
    'register-cwr':     `Register CWR · ${ids.length} ${plural}`,
    'change-publisher': `Change publisher · ${ids.length} ${plural}`,
    'change-label':     `Change label · ${ids.length} ${plural}`,
    'tag':              `Add tag · ${ids.length} ${plural}`,
    'export':           `Export ${ids.length} ${plural}`,
    'delete':           `Delete ${ids.length} ${plural}`,
  };
  const kindLabel = {
    'register-cwr':     'BULK ACTION · CWR REGISTRATION',
    'change-publisher': 'BULK ACTION · PUBLISHER',
    'change-label':     'BULK ACTION · LABEL',
    'tag':              'BULK ACTION · TAG',
    'export':           'BULK ACTION · EXPORT',
    'delete':           'BULK ACTION · DESTRUCTIVE',
  };
  const danger = action === 'delete';
  const requiresConfirm = action === 'delete';
  const confirmDisabled =
    (action === 'tag' && !tagText.trim()) ||
    (action === 'change-publisher' && !pubText.trim()) ||
    (action === 'change-label' && !labelText.trim()) ||
    (action === 'register-cwr' && societies.length === 0) ||
    (requiresConfirm && confirmText.trim().toUpperCase() !== 'DELETE');

  const toast = (msg, tone='ok') => window.dispatchEvent(new CustomEvent('astro-toast', { detail: { msg, tone }}));

  const run = () => {
    let msg = '';
    switch (action) {
      case 'register-cwr':
        msg = `Queued CWR for ${ids.length} ${plural} → ${societies.join(', ')}`;
        break;
      case 'change-publisher':
        msg = `Reassigned ${ids.length} ${plural} to ${pubText.trim()}`;
        break;
      case 'change-label':
        msg = `Reassigned ${ids.length} ${plural} to label ${labelText.trim()}`;
        break;
      case 'tag':
        msg = `Tagged ${ids.length} ${plural} with "${tagText.trim()}"`;
        break;
      case 'export': {
        // Build a simple CSV from whatever metadata we can scrape via window
        const rows = [];
        if (kind === 'recordings' && Array.isArray(window.RECORDING_GRAPH)) {
          rows.push(['id','title','artist','isrc','album','year','label','plays_m']);
          for (const id of ids) {
            const r = window.RECORDING_GRAPH.find(x => x.id === id);
            if (!r) continue;
            rows.push([r.id, r.title, r.artist, r.isrc, r.album, r.year, r.label, r.plays]);
          }
        } else if (Array.isArray(window.ALL_WORKS)) {
          rows.push(['id','title','iswc','writers','shares','status']);
          for (const id of ids) {
            const w = window.ALL_WORKS.find(x => x.id === id);
            if (!w) continue;
            rows.push([w.id, w.title, w.iswc, (w.writers||[]).join('; '), w.shares, w.status]);
          }
        }
        const csv = rows.map(r => r.map(c => {
          const v = c == null ? '' : String(c);
          return /[,"\n]/.test(v) ? `"${v.replace(/"/g,'""')}"` : v;
        }).join(',')).join('\n');
        try {
          const blob = new Blob([csv], { type: 'text/csv;charset=utf-8' });
          const url = URL.createObjectURL(blob);
          const a = document.createElement('a');
          a.href = url; a.download = `astro-${kind}-${Date.now()}.csv`;
          document.body.appendChild(a); a.click(); a.remove();
          setTimeout(()=>URL.revokeObjectURL(url), 4000);
        } catch {}
        msg = `Exported ${ids.length} ${plural} as CSV`;
        break;
      }
      case 'delete':
        msg = `Deleted ${ids.length} ${plural}`;
        break;
    }
    if (msg) toast(msg, danger ? 'warn' : 'ok');
    sel.clear();
    onClose();
  };

  const Soc = (s) => (
    <button key={s} onClick={() => setSocieties(prev => prev.includes(s) ? prev.filter(x=>x!==s) : [...prev, s])}
      className="ff-mono upper" style={{
        padding: '5px 10px', fontSize: 10, letterSpacing: '.1em',
        background: societies.includes(s) ? 'var(--ink)' : 'transparent',
        color: societies.includes(s) ? 'var(--bg)' : 'var(--ink-2)',
        border: '1px solid var(--rule)', cursor: 'pointer',
      }}>{s}</button>
  );

  // Collect a tiny preview of what's selected
  const preview = ids.slice(0, 5).map(id => {
    if (kind === 'recordings' && Array.isArray(window.RECORDING_GRAPH)) {
      const r = window.RECORDING_GRAPH.find(x => x.id === id);
      return r ? `${r.title} — ${r.artist}` : id;
    }
    if (Array.isArray(window.ALL_WORKS)) {
      const w = window.ALL_WORKS.find(x => x.id === id);
      return w ? `${w.title}` : id;
    }
    return id;
  });

  return (
    <>
      <div onClick={onClose} style={{position:'fixed',inset:0,background:'rgba(0,0,0,.42)',zIndex:80}}/>
      <div style={{
        position:'fixed', top:'50%', left:'50%', transform:'translate(-50%, -50%)',
        width:'min(560px, 92vw)', maxHeight:'86vh', overflow:'auto',
        background:'var(--bg)', border:'1px solid var(--ink)', boxShadow:'8px 8px 0 rgba(0,0,0,.18)',
        zIndex:81, color:'var(--ink)'
      }}>
        <div style={{padding:'16px 20px',borderBottom:'1px solid var(--rule)'}}>
          <div className="ff-mono upper" style={{fontSize:9,letterSpacing:'.14em',color: danger ? '#c0392b' : 'var(--ink-3)',marginBottom:6}}>{kindLabel[action]}</div>
          <div className="ff-display" style={{fontSize:22,fontWeight:700,letterSpacing:'-0.01em'}}>{titleMap[action]}</div>
        </div>
        <div style={{padding:'18px 20px', display:'flex', flexDirection:'column', gap: 16}}>
          {/* Preview list */}
          <div>
            <div className="ff-mono upper" style={{fontSize:9,letterSpacing:'.12em',color:'var(--ink-3)',marginBottom:8}}>SELECTED · {ids.length}</div>
            <div style={{
              border:'1px solid var(--rule)', background:'var(--bg-2)',
              padding:'10px 12px', fontSize:12, lineHeight:1.7, maxHeight: 140, overflow:'auto',
            }}>
              {preview.map((p, i) => <div key={i} style={{whiteSpace:'nowrap',overflow:'hidden',textOverflow:'ellipsis'}}>{p}</div>)}
              {ids.length > preview.length && (
                <div className="ff-mono" style={{fontSize:10,color:'var(--ink-3)',marginTop:4}}>+ {ids.length - preview.length} more</div>
              )}
            </div>
          </div>

          {/* Per-action body */}
          {action === 'register-cwr' && (
            <div>
              <div className="ff-mono upper" style={{fontSize:9,letterSpacing:'.12em',color:'var(--ink-3)',marginBottom:8}}>SUBMIT TO SOCIETIES</div>
              <div style={{display:'flex', flexWrap:'wrap', gap:6}}>
                {['ASCAP','BMI','SESAC','PRS','GEMA','SACEM','SOCAN','MLC'].map(Soc)}
              </div>
              <div className="ff-mono" style={{fontSize:11,color:'var(--ink-3)',marginTop:10,lineHeight:1.5}}>
                Generates one CWR transmission per society. Failures appear in the CWR queue with retry.
              </div>
            </div>
          )}

          {action === 'change-publisher' && (
            <div>
              <div className="ff-mono upper" style={{fontSize:9,letterSpacing:'.12em',color:'var(--ink-3)',marginBottom:8}}>NEW PUBLISHER</div>
              <input value={pubText} onChange={e=>setPubText(e.target.value)} autoFocus
                placeholder="e.g. Kobalt Music Publishing"
                style={{width:'100%',padding:'10px 12px',fontSize:13,background:'transparent',color:'var(--ink)',border:'1px solid var(--rule)'}}/>
              <div className="ff-mono" style={{fontSize:11,color:'var(--ink-3)',marginTop:10,lineHeight:1.5}}>
                Replaces the publisher line on every selected work. Existing share splits remain; CWR will be regenerated for downstream societies.
              </div>
            </div>
          )}

          {action === 'change-label' && (
            <div>
              <div className="ff-mono upper" style={{fontSize:9,letterSpacing:'.12em',color:'var(--ink-3)',marginBottom:8}}>NEW LABEL</div>
              <input value={labelText} onChange={e=>setLabelText(e.target.value)} autoFocus
                placeholder="e.g. Saddle Creek"
                style={{width:'100%',padding:'10px 12px',fontSize:13,background:'transparent',color:'var(--ink)',border:'1px solid var(--rule)'}}/>
              <div className="ff-mono" style={{fontSize:11,color:'var(--ink-3)',marginTop:10,lineHeight:1.5}}>
                Reassigns label code for the selected recordings. DDEX delivery metadata refreshes on next batch.
              </div>
            </div>
          )}

          {action === 'tag' && (
            <div>
              <div className="ff-mono upper" style={{fontSize:9,letterSpacing:'.12em',color:'var(--ink-3)',marginBottom:8}}>TAG</div>
              <input value={tagText} onChange={e=>setTagText(e.target.value)} autoFocus
                placeholder="e.g. sync-pitch, holiday-2026, claim-review"
                style={{width:'100%',padding:'10px 12px',fontSize:13,background:'transparent',color:'var(--ink)',border:'1px solid var(--rule)'}}/>
              <div style={{display:'flex',gap:6,flexWrap:'wrap',marginTop:8}}>
                {['sync-pitch','claim-review','royalty-hold','priority','holiday-2026'].map(t => (
                  <button key={t} onClick={()=>setTagText(t)} className="ff-mono"
                    style={{fontSize:10,padding:'3px 8px',background:'var(--bg-2)',border:'1px solid var(--rule)',cursor:'pointer',color:'var(--ink-2)'}}>
                    {t}
                  </button>
                ))}
              </div>
            </div>
          )}

          {action === 'export' && (
            <div className="ff-mono" style={{fontSize:12,color:'var(--ink-2)',lineHeight:1.6}}>
              Downloads a CSV containing IDs, titles, identifiers, and key metadata for the {ids.length} selected {plural}.
            </div>
          )}

          {action === 'delete' && (
            <div>
              <div className="ff-mono" style={{fontSize:12,color:'#c0392b',lineHeight:1.6,marginBottom:12}}>
                <b>Destructive.</b> Selected {plural} will be removed from the catalog. Linked recordings,
                releases, and existing CWR submissions are preserved but will be flagged as orphaned.
              </div>
              <div className="ff-mono upper" style={{fontSize:9,letterSpacing:'.12em',color:'var(--ink-3)',marginBottom:8}}>TYPE "DELETE" TO CONFIRM</div>
              <input value={confirmText} onChange={e=>setConfirmText(e.target.value)} autoFocus
                placeholder="DELETE"
                style={{width:'100%',padding:'10px 12px',fontSize:13,background:'transparent',color:'var(--ink)',border:'1px solid var(--rule)',letterSpacing:'.1em'}}/>
            </div>
          )}
        </div>
        <div style={{display:'flex',gap:8,justifyContent:'flex-end',padding:'12px 16px',borderTop:'1px solid var(--rule)',background:'var(--bg-2)'}}>
          <button onClick={onClose}
            style={{padding:'8px 14px',background:'transparent',color:'var(--ink)',border:'1px solid var(--rule)',fontSize:12,fontWeight:500,cursor:'pointer'}}>Cancel</button>
          <button onClick={run} disabled={confirmDisabled}
            style={{padding:'8px 14px',background: danger ? '#c0392b' : 'var(--ink)',color: danger ? '#fff' : 'var(--bg)',border:0,fontSize:12,fontWeight:600,cursor: confirmDisabled ? 'not-allowed' : 'pointer',letterSpacing:'.02em',opacity: confirmDisabled ? .4 : 1}}>
            {action === 'delete' ? `Delete ${ids.length}` :
             action === 'export' ? 'Download CSV' :
             action === 'register-cwr' ? `Queue ${ids.length} CWR${ids.length===1?'':'s'}` :
             'Apply'}
          </button>
        </div>
      </div>
    </>
  );
}

Object.assign(window, { useBulkSel, BulkCheckbox, BulkHeaderCheckbox, BulkActionBar, BulkActionModal });
