// ============================================================
// components.jsx — shared UI for the AI Asset Registry
// ============================================================

// ---- Small helpers ----------------------------------------
function hashStr(s) { let h = 0; for (let i = 0; i < s.length; i++) h = (h * 31 + s.charCodeAt(i)) | 0; return Math.abs(h); }

const GLYPHS = {
  'QuaverMusic':     ['mdi-music-note', 'mdi-music-clef-treble', 'mdi-piano', 'mdi-guitar-acoustic', 'mdi-trumpet'],
  'QuaverSEL':       ['mdi-heart-outline', 'mdi-emoticon-happy-outline', 'mdi-hand-heart-outline', 'mdi-account-group-outline', 'mdi-head-heart-outline'],
  'QuaverHealth·PE': ['mdi-run', 'mdi-heart-pulse', 'mdi-food-apple-outline', 'mdi-jump-rope', 'mdi-soccer'],
};

// ---- Asset thumbnail --------------------------------------
// Renders the real image (asset.src, e.g. an R2 URL) when present; otherwise
// falls back to a subject-color block + icon. Also falls back if the image 404s.
function Thumb({ asset, size = 'md' }) {
  const h = hashStr(asset.id);
  const angle = 105 + (h % 60);
  const glyphs = GLYPHS[asset.product] || ['mdi-image-outline'];
  const glyph = glyphs[h % glyphs.length];
  const c = asset.color;
  const dims = { sm: 44, md: 88, lg: 100 }[size] || 88;
  const glyphSize = { sm: 22, md: 40, lg: 46 }[size] || 40;
  const [imgOk, setImgOk] = React.useState(true);
  const showImg = !!asset.src && imgOk && asset.type === 'image';
  return (
    <div style={{
      position: 'relative', width: size === 'fill' ? '100%' : dims, height: size === 'fill' ? '100%' : dims,
      borderRadius: 6, overflow: 'hidden', flexShrink: 0,
      background: `linear-gradient(${angle}deg, ${c} 0%, ${shade(c, -18)} 100%)`,
      display: 'flex', alignItems: 'center', justifyContent: 'center',
    }}>
      {showImg ? (
        <img src={asset.src} alt={asset.title || ''} loading="lazy" onError={() => setImgOk(false)}
          style={{ position: 'absolute', inset: 0, width: '100%', height: '100%', objectFit: 'cover' }}/>
      ) : (
        <React.Fragment>
          <div style={{ position: 'absolute', inset: 0, opacity: 0.16,
            backgroundImage: `radial-gradient(circle at 78% 22%, #fff 0 1.5px, transparent 2px)`,
            backgroundSize: '14px 14px' }}/>
          <i className={`mdi ${glyph}`} style={{ fontSize: size === 'fill' ? 56 : glyphSize, color: 'rgba(255,255,255,0.92)' }}/>
        </React.Fragment>
      )}
      {asset.type === 'video' && (
        <div style={{
          position: 'absolute', width: size === 'sm' ? 18 : 30, height: size === 'sm' ? 18 : 30,
          borderRadius: '50%', background: 'rgba(0,0,0,0.42)', backdropFilter: 'blur(2px)',
          display: 'flex', alignItems: 'center', justifyContent: 'center',
        }}>
          <i className="mdi mdi-play" style={{ fontSize: size === 'sm' ? 12 : 18, color: '#fff', marginLeft: 1 }}/>
        </div>
      )}
    </div>
  );
}

function shade(hex, pct) {
  const n = parseInt(hex.slice(1), 16);
  let r = (n >> 16) & 255, g = (n >> 8) & 255, b = n & 255;
  r = Math.max(0, Math.min(255, r + Math.round(255 * pct / 100)));
  g = Math.max(0, Math.min(255, g + Math.round(255 * pct / 100)));
  b = Math.max(0, Math.min(255, b + Math.round(255 * pct / 100)));
  return '#' + ((1 << 24) + (r << 16) + (g << 8) + b).toString(16).slice(1);
}

// ---- Status pill ------------------------------------------
function StatusPill({ status, size = 'md' }) {
  const meta = window.REGISTRY.STATUSES[status];
  const colors = {
    success: { bg: '#E8F5E9', fg: '#2E7D32' },
    warning: { bg: '#FFF3E0', fg: '#E65100' },
    error:   { bg: '#FCE4EC', fg: '#B00020' },
    default: { bg: '#ECEFF1', fg: '#546E7A' },
  };
  const c = colors[meta.color];
  const sm = size === 'sm';
  return (
    <span style={{
      display: 'inline-flex', alignItems: 'center', gap: 5, height: sm ? 22 : 26,
      padding: sm ? '0 8px' : '0 10px', borderRadius: 9999, background: c.bg, color: c.fg,
      fontFamily: 'Roboto', fontWeight: 500, fontSize: sm ? 11.5 : 12.5, whiteSpace: 'nowrap',
    }}>
      <i className={`mdi ${meta.icon}`} style={{ fontSize: sm ? 13 : 15 }}/>
      {meta.label}
    </span>
  );
}

// ---- Type tag ---------------------------------------------
function TypeTag({ type }) {
  return (
    <span style={{
      display: 'inline-flex', alignItems: 'center', gap: 5, height: 24, padding: '0 9px',
      borderRadius: 4, background: 'rgba(0,0,0,0.05)', color: 'rgba(0,0,0,0.7)',
      fontFamily: 'Roboto', fontWeight: 500, fontSize: 12,
    }}>
      <i className={`mdi ${type === 'video' ? 'mdi-play-box-outline' : 'mdi-image-outline'}`} style={{ fontSize: 15 }}/>
      {type === 'video' ? 'Video' : 'Image'}
    </span>
  );
}

// ---- Product dot ------------------------------------------
function ProductTag({ asset, withIcon = true }) {
  return (
    <span style={{ display: 'inline-flex', alignItems: 'center', gap: 7, fontFamily: 'Roboto', fontSize: 13.5, color: 'rgba(0,0,0,0.8)' }}>
      <span style={{ width: 9, height: 9, borderRadius: '50%', background: asset.color, flexShrink: 0 }}/>
      {withIcon && <i className={`mdi ${asset.productIcon}`} style={{ fontSize: 16, color: asset.color }}/>}
      {asset.productShort}
    </span>
  );
}

// ---- Top app bar ------------------------------------------
function AppBar({ query, onQuery, onExport, resultCount }) {
  return (
    <header style={cmpStyles.bar}>
      <div style={{ display: 'flex', alignItems: 'center', gap: 12 }}>
        <div style={cmpStyles.mark}><i className="mdi mdi-robot-outline" style={{ fontSize: 22 }}/></div>
        <div>
          <div style={{ fontWeight: 500, fontSize: 16, lineHeight: 1.1, letterSpacing: '.01em' }}>AI Asset Registry</div>
          <div style={{ fontSize: 11.5, color: 'rgba(255,255,255,0.72)', fontWeight: 400 }}>QuaverEd curriculum · compliance inventory</div>
        </div>
      </div>

      <div style={cmpStyles.search}>
        <i className="mdi mdi-magnify" style={{ fontSize: 20, color: 'rgba(255,255,255,0.8)' }}/>
        <input
          value={query}
          onChange={(e) => onQuery(e.target.value)}
          style={cmpStyles.searchInput}
          placeholder="Search by ID, title, prompt, tool, creator…"/>
        {query && (
          <button onClick={() => onQuery('')} style={cmpStyles.clearBtn} aria-label="Clear search">
            <i className="mdi mdi-close" style={{ fontSize: 17 }}/>
          </button>
        )}
      </div>

      <div style={{ flex: 1 }}/>
      <button style={cmpStyles.exportBtn} onClick={onExport}>
        <i className="mdi mdi-download-outline" style={{ fontSize: 18 }}/>
        Export CSV
        <span style={cmpStyles.exportCount}>{resultCount}</span>
      </button>
      <div style={cmpStyles.avatar}>JR</div>
    </header>
  );
}

// ---- Summary stat strip -----------------------------------
function StatStrip({ all, filtered }) {
  const count = (arr, fn) => arr.filter(fn).length;
  const flagged = count(all, a => a.status === 'flagged');
  const review = count(all, a => a.status === 'needs-review');
  const edited = count(all, a => a.humanEdited);
  const pctEdited = Math.round((edited / all.length) * 100);
  const cells = [
    { label: 'Total AI assets', value: all.length, icon: 'mdi-database-outline', tint: '#1867C0' },
    { label: 'Images', value: count(all, a => a.type === 'image'), icon: 'mdi-image-outline', tint: '#5E35B1' },
    { label: 'Video', value: count(all, a => a.type === 'video'), icon: 'mdi-play-box-outline', tint: '#00838F' },
    { label: 'Human-edited', value: pctEdited + '%', icon: 'mdi-account-edit-outline', tint: '#2E7D32' },
    { label: 'Needs review', value: review, icon: 'mdi-clock-alert-outline', tint: '#E65100' },
    { label: 'Client-flagged', value: flagged, icon: 'mdi-flag-outline', tint: '#B00020' },
  ];
  return (
    <div style={cmpStyles.statStrip}>
      {cells.map((c) => (
        <div key={c.label} style={cmpStyles.statCell}>
          <div style={{ ...cmpStyles.statIcon, background: c.tint + '18', color: c.tint }}>
            <i className={`mdi ${c.icon}`} style={{ fontSize: 20 }}/>
          </div>
          <div>
            <div style={{ fontSize: 22, fontWeight: 500, lineHeight: 1.1, color: 'rgba(0,0,0,0.87)' }}>{c.value}</div>
            <div style={{ fontSize: 12, color: 'rgba(0,0,0,0.6)' }}>{c.label}</div>
          </div>
        </div>
      ))}
    </div>
  );
}

const cmpStyles = {
  bar: {
    height: 60, background: '#1867C0', color: '#fff', display: 'flex', alignItems: 'center',
    padding: '0 20px', gap: 16, boxShadow: 'var(--qv-elev-4)', position: 'relative', zIndex: 30, flexShrink: 0,
  },
  mark: {
    width: 38, height: 38, borderRadius: 9, background: 'rgba(255,255,255,0.16)',
    display: 'flex', alignItems: 'center', justifyContent: 'center', color: '#fff',
  },
  search: {
    display: 'flex', alignItems: 'center', gap: 8, marginLeft: 18,
    background: 'rgba(255,255,255,0.15)', borderRadius: 6, padding: '0 12px', height: 38, width: 420,
  },
  searchInput: { flex: 1, background: 'transparent', border: 0, outline: 'none', color: '#fff', fontFamily: 'Roboto', fontSize: 14 },
  clearBtn: { background: 'transparent', border: 0, color: 'rgba(255,255,255,0.8)', cursor: 'pointer', display: 'flex', padding: 2 },
  exportBtn: {
    display: 'inline-flex', alignItems: 'center', gap: 8, height: 38, padding: '0 16px',
    background: '#FFC107', color: 'rgba(0,0,0,0.87)', border: 0, borderRadius: 6, cursor: 'pointer',
    fontFamily: 'Roboto', fontWeight: 500, fontSize: 13.5, letterSpacing: '.04em', textTransform: 'uppercase',
    boxShadow: 'var(--qv-elev-2)',
  },
  exportCount: {
    minWidth: 20, height: 20, padding: '0 6px', borderRadius: 10, background: 'rgba(0,0,0,0.18)',
    fontSize: 11.5, fontWeight: 700, display: 'flex', alignItems: 'center', justifyContent: 'center',
  },
  avatar: {
    width: 36, height: 36, borderRadius: '50%', background: 'rgba(255,255,255,0.92)', color: '#1867C0',
    fontWeight: 700, fontSize: 13, display: 'flex', alignItems: 'center', justifyContent: 'center', marginLeft: 4,
  },
  statStrip: {
    display: 'grid', gridTemplateColumns: 'repeat(6, 1fr)', gap: 1, background: 'var(--qv-border)',
    border: '1px solid var(--qv-border)', borderRadius: 8, overflow: 'hidden', flexShrink: 0,
  },
  statCell: { background: '#fff', padding: '14px 16px', display: 'flex', alignItems: 'center', gap: 12 },
  statIcon: { width: 36, height: 36, borderRadius: 8, display: 'flex', alignItems: 'center', justifyContent: 'center', flexShrink: 0 },
};

Object.assign(window, { Thumb, StatusPill, TypeTag, ProductTag, AppBar, StatStrip, hashStr, shade });
