/* ============================================================
   asset-library.jsx — shared selector/manager for logos and models.
   The selector is intentionally thumbnail-first: workers can recognize assets
   faster than reading a long dropdown, while owners and admins get CRUD in the same flow.
   ============================================================ */
(function () {
  'use strict';
  const { useState, useEffect, useMemo, useRef } = React;
  const A = () => window.__assetLibrary;
  const KIND_LABEL = { logo: '로고', model: '셀럽 모델' };
  const btn = (primary) => ({ border: primary ? '1px solid #4E4CDB' : '1px solid #e7e7ee', background: primary ? '#4E4CDB' : '#fff', color: primary ? '#fff' : '#4b4b58', borderRadius: '7px', padding: '7px 10px', font: 'inherit', fontSize: '11.5px', fontWeight: 700, cursor: 'pointer' });

  async function recolorLogo(src, tone) {
    if (tone === 'original') return src;
    const response = await fetch(src);
    if (!response.ok) throw new Error('로고 원본을 불러오지 못했습니다.');
    const blob = await response.blob();
    let image;
    let objectUrl = '';
    if (window.createImageBitmap) image = await window.createImageBitmap(blob);
    else {
      objectUrl = URL.createObjectURL(blob);
      image = await new Promise((resolve, reject) => {
        const element = new Image();
        element.onload = () => resolve(element);
        element.onerror = () => reject(new Error('로고 이미지를 해석하지 못했습니다.'));
        element.src = objectUrl;
      });
    }
    const width = image.naturalWidth || image.width;
    const height = image.naturalHeight || image.height;
    const canvas = document.createElement('canvas');
    canvas.width = width;
    canvas.height = height;
    const context = canvas.getContext('2d');
    context.drawImage(image, 0, 0, width, height);
    context.globalCompositeOperation = 'source-in';
    context.fillStyle = tone === 'black' ? '#000000' : '#ffffff';
    context.fillRect(0, 0, width, height);
    if (image.close) image.close();
    if (objectUrl) URL.revokeObjectURL(objectUrl);
    return canvas.toDataURL('image/png');
  }

  function AssetLibraryField({ kind, max = 1, onApply, compact = false }) {
    const [open, setOpen] = useState(false);
    return <>
      <button type="button" onClick={() => setOpen(true)} style={{ ...btn(false), width: compact ? 'auto' : '100%', display: 'inline-flex', alignItems: 'center', justifyContent: 'center', gap: '6px' }}>
        <span aria-hidden="true">▦</span>공용 {KIND_LABEL[kind]} 라이브러리
      </button>
      {open && <AssetLibraryModal kind={kind} max={max} onApply={onApply} onClose={() => setOpen(false)} />}
    </>;
  }

  function AssetLibraryModal({ kind, max, onApply, onClose }) {
    const [tab, setTab] = useState('select');
    const [items, setItems] = useState([]);
    const [query, setQuery] = useState('');
    const [selected, setSelected] = useState([]);
    const [editing, setEditing] = useState(null);
    const [busy, setBusy] = useState(false);
    const [error, setError] = useState('');
    const [logoTone, setLogoTone] = useState('original');
    const [roleTick, setRoleTick] = useState(0);
    const manage = roleTick >= 0 && A() && A().canManage(kind);
    const admin = roleTick >= 0 && window.__bannerlyRole === 'admin';
    const reload = async () => {
      const next = manage && tab === 'manage' ? await A().listAll(kind) : await A().list(kind);
      setItems(next || []);
    };
    useEffect(() => { reload(); const off = A() && A().subscribe(() => { setRoleTick((x) => x + 1); reload(); }); return () => off && off(); }, [kind, tab, manage]);
    useEffect(() => { const fn = (e) => { if (e.key === 'Escape') onClose(); }; window.addEventListener('keydown', fn); return () => window.removeEventListener('keydown', fn); }, []);
    const filtered = useMemo(() => { const q = query.trim().toLowerCase(); return items.filter((x) => !q || [x.name, x.description, ...(x.tags || [])].join(' ').toLowerCase().includes(q)); }, [items, query]);
    const toggle = (item) => setSelected((prev) => { const has = prev.some((x) => x.id === item.id); if (has) return prev.filter((x) => x.id !== item.id); return max > 1 ? prev.concat([item]).slice(-max) : [item]; });
    const apply = async () => {
      if (!selected.length || busy) return;
      if (kind !== 'logo' || logoTone === 'original') {
        onApply(selected.slice());
        onClose();
        return;
      }
      setError('');
      setBusy(true);
      try {
        const assets = await Promise.all(selected.map(async (item) => ({ ...item, originalSrc: item.src, src: await recolorLogo(item.src, logoTone), logoTone })));
        setBusy(false);
        onApply(assets);
        onClose();
      } catch (e) {
        setBusy(false);
        setError(e && e.message ? e.message : '로고 색상 변환에 실패했습니다.');
      }
    };
    return <div role="dialog" aria-modal="true" aria-label={KIND_LABEL[kind] + ' 라이브러리'} onMouseDown={(e) => { if (e.target === e.currentTarget) onClose(); }} style={{ position: 'fixed', inset: 0, zIndex: 100000, background: 'rgba(15,15,24,.42)', display: 'flex', alignItems: 'center', justifyContent: 'center', padding: '20px', boxSizing: 'border-box' }}>
      <div style={{ width: 'min(760px, 100%)', maxHeight: 'min(720px, 92vh)', background: '#fff', borderRadius: '12px', boxShadow: '0 20px 60px rgba(0,0,0,.2)', display: 'flex', flexDirection: 'column', overflow: 'hidden', fontFamily: 'Pretendard, system-ui, sans-serif' }}>
        <header style={{ display: 'flex', alignItems: 'center', gap: '12px', padding: '18px 20px 14px', borderBottom: '1px solid #eeeef3' }}>
          <div style={{ flex: 1 }}><div style={{ fontSize: '17px', fontWeight: 800, color: '#1e1e26' }}>공용 {KIND_LABEL[kind]} 라이브러리</div><div style={{ fontSize: '11.5px', color: '#8a8a96', marginTop: '3px' }}>{tab === 'select' ? '필요한 공용 자산을 선택해 작업 화면에 바로 적용하세요.' : !admin ? '내가 등록한 자산을 관리할 수 있습니다.' : '관리자는 모든 자산을 등록·수정·삭제하고 삭제된 자산을 복구할 수 있습니다.'}</div></div>
          <button type="button" onClick={onClose} aria-label="닫기" title="닫기" style={{ border: 0, background: 'transparent', fontSize: '22px', lineHeight: 1, color: '#8a8a96', cursor: 'pointer' }}>×</button>
        </header>
        <div style={{ display: 'flex', gap: '6px', padding: '12px 20px 0' }}><button type="button" onClick={() => setTab('select')} style={{ ...btn(tab === 'select'), padding: '6px 12px' }}>선택</button>{manage && <button type="button" onClick={() => setTab('manage')} style={{ ...btn(tab === 'manage'), padding: '6px 12px' }}>등록·관리</button>}</div>
        <div style={{ padding: '12px 20px', display: 'flex', gap: '8px' }}><input value={query} onChange={(e) => setQuery(e.target.value)} placeholder={KIND_LABEL[kind] + ' 이름·태그 검색'} style={{ flex: 1, minWidth: 0, border: '1px solid #e5e5ec', borderRadius: '7px', padding: '9px 11px', font: 'inherit', fontSize: '12px', outline: 'none' }} />{manage && tab === 'manage' && <button type="button" onClick={() => setEditing({ kind, name: '', description: '', tags: [], src: '' })} style={btn(true)}>+ 새로 등록</button>}</div>
        {kind === 'logo' && tab === 'select' && <div role="group" aria-label="로고 색상" style={{ display: 'flex', alignItems: 'center', gap: '6px', padding: '0 20px 12px' }}>
          <span style={{ color: '#6b6b78', fontSize: '11.5px', fontWeight: 800, marginRight: '2px' }}>적용 색상</span>
          {[['original', '원본', 'linear-gradient(135deg,#fff 50%,#1f1f24 50%)'], ['black', '블랙', '#111'], ['white', '화이트', '#fff']].map(([value, label, swatch]) => <button key={value} type="button" aria-pressed={logoTone === value} onClick={() => setLogoTone(value)} style={{ ...btn(logoTone === value), display: 'inline-flex', alignItems: 'center', gap: '6px', padding: '6px 9px' }}><span aria-hidden="true" style={{ width: '13px', height: '13px', borderRadius: '50%', background: swatch, border: value === 'white' ? '1px solid #b8b8c2' : '1px solid transparent', boxSizing: 'border-box' }} />{label}</button>)}
        </div>}
        {error && <div style={{ margin: '0 20px 10px', color: '#b42318', background: '#fff1f0', border: '1px solid #ffd5d2', padding: '8px 10px', borderRadius: '7px', fontSize: '11.5px' }}>{error}</div>}
        <div style={{ overflow: 'auto', padding: '0 20px 18px', minHeight: '230px' }}>
          {editing && <AssetEditor kind={kind} item={editing} busy={busy} onCancel={() => setEditing(null)} onError={setError} onSaved={async () => { setEditing(null); await reload(); }} setBusy={setBusy} />}
          {!editing && <div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fill, minmax(140px, 1fr))', gap: '10px' }}>
            {filtered.map((item) => { const on = selected.some((x) => x.id === item.id); const modelCard = kind === 'model'; const logoCard = kind === 'logo'; const titleOnlyCard = logoCard || modelCard; const previewTone = tab === 'select' ? logoTone : 'original'; const previewFilter = logoCard && previewTone !== 'original' ? (previewTone === 'black' ? 'brightness(0)' : 'brightness(0) invert(1)') : 'none'; return <div key={item.id} style={{ border: on ? '1.5px solid #4E4CDB' : '1px solid #e7e7ee', borderRadius: '8px', background: '#fff', overflow: 'hidden', position: 'relative' }}>
              <button type="button" onClick={() => tab === 'select' && toggle(item)} style={{ display: 'block', width: '100%', border: 0, background: 'transparent', padding: 0, cursor: tab === 'select' ? 'pointer' : 'default', textAlign: titleOnlyCard ? 'center' : 'left' }}>
                <div style={{ height: modelCard ? '132px' : logoCard ? '104px' : '88px', display: 'grid', placeItems: 'center', background: logoCard && previewTone === 'black' ? '#f5f5f7' : logoCard ? '#292934' : '#fafafb', padding: modelCard ? '4px 8px 0' : '10px', boxSizing: 'border-box' }}><img src={item.src} alt={item.name} style={{ maxWidth: '100%', maxHeight: '100%', objectFit: 'contain', filter: previewFilter }} /></div>
                <div style={{ padding: titleOnlyCard ? '9px 9px 10px' : '8px 9px' }}><div title={item.name} style={{ fontSize: '12px', fontWeight: 800, color: '#292934', overflow: 'hidden', whiteSpace: 'nowrap', textOverflow: 'ellipsis' }}>{item.name}</div>{!titleOnlyCard && <div style={{ fontSize: '10.5px', color: '#9696a2', marginTop: '3px', minHeight: '14px', overflow: 'hidden', whiteSpace: 'nowrap', textOverflow: 'ellipsis' }}>{(item.tags || []).join(' · ') || '태그 없음'}</div>}</div>
              </button>
              {(tab === 'manage' || tab === 'select') && manage && A().canEdit(item) && item.active !== false && <div style={{ display: 'flex', gap: '5px', padding: '0 8px 8px' }}><button type="button" onClick={() => setEditing(item)} style={{ ...btn(false), flex: 1, padding: '5px 4px', fontSize: '10.5px' }}>수정</button><button type="button" onClick={async () => { if (!window.confirm(item.name + ' 자산을 삭제할까요?')) return; setBusy(true); const r = await A().remove(item.id); setBusy(false); if (!r.ok) setError(r.error); else reload(); }} style={{ ...btn(false), color: '#b42318', padding: '5px 7px', fontSize: '10.5px' }}>삭제</button></div>}
              {tab === 'manage' && manage && item.active === false && admin && <div style={{ display: 'flex', gap: '5px', padding: '0 8px 8px' }}><span style={{ flex: 1, alignSelf: 'center', color: '#b42318', fontSize: '10px', fontWeight: 700 }}>삭제됨</span><button type="button" onClick={async () => { setBusy(true); const r = await A().restore(item.id); setBusy(false); if (!r.ok) setError(r.error); else reload(); }} style={{ ...btn(false), color: '#1f7a4d', padding: '5px 7px', fontSize: '10.5px' }}>복구</button></div>}
              {tab === 'manage' && item.builtIn && <div style={{ padding: '0 8px 8px', color: '#9a9aa6', fontSize: '10px' }}>기본 샘플</div>}
              {on && <span style={{ position: 'absolute', top: '7px', right: '7px', width: '18px', height: '18px', borderRadius: '50%', background: '#4E4CDB', color: '#fff', display: 'grid', placeItems: 'center', fontSize: '12px', fontWeight: 800 }}>✓</span>}
            </div>; })}
          </div>}
          {!editing && !filtered.length && <div style={{ textAlign: 'center', color: '#9a9aa6', fontSize: '12px', padding: '52px 10px' }}>{query ? '검색 결과가 없습니다.' : '등록된 자산이 없습니다.'}</div>}
        </div>
        {tab === 'select' && <footer style={{ display: 'flex', justifyContent: 'flex-end', gap: '8px', padding: '12px 20px', borderTop: '1px solid #eeeef3' }}><span style={{ marginRight: 'auto', alignSelf: 'center', color: '#8a8a96', fontSize: '11.5px' }}>{selected.length ? selected.length + '개 선택됨' : '자산을 선택하세요'}</span><button type="button" disabled={busy} onClick={onClose} style={btn(false)}>취소</button><button type="button" disabled={!selected.length || busy} onClick={apply} style={{ ...btn(true), opacity: selected.length && !busy ? 1 : .45 }}>{busy ? '변환 중…' : '적용'}</button></footer>}
      </div>
    </div>;
  }

  function AssetEditor({ kind, item, busy, setBusy, onCancel, onSaved, onError }) {
    const [name, setName] = useState(item.name || '');
    const [description, setDescription] = useState(item.description || '');
    const [tags, setTags] = useState((item.tags || []).join(', '));
    const [src, setSrc] = useState(item.src || '');
    const admin = window.__bannerlyRole === 'admin';
    const [publicVisible, setPublicVisible] = useState(item.publicVisible === true);
    const input = useRef(null);
    const save = async () => { if (!name.trim()) { onError('자산 이름을 입력해 주세요'); return; } if (!src) { onError('이미지를 선택해 주세요'); return; } setBusy(true); const r = await A().upsert({ ...item, kind, name, description, tags: tags.split(',').map((x) => x.trim()).filter(Boolean), src, publicVisible: admin ? publicVisible : item.publicVisible === true }); setBusy(false); if (!r.ok) onError(r.error); else onSaved(); };
    return <div style={{ border: '1px solid #e7e7ee', borderRadius: '9px', padding: '14px', marginBottom: '14px', background: '#fafafb' }}><div style={{ fontSize: '12.5px', fontWeight: 800, marginBottom: '10px' }}>{item.id ? '자산 수정' : '새 자산 등록'}</div><div style={{ display: 'grid', gridTemplateColumns: '112px 1fr', gap: '12px' }}><button type="button" onClick={() => input.current.click()} style={{ height: '90px', border: '1px dashed #cfcfda', borderRadius: '8px', background: '#fff', cursor: 'pointer', padding: '8px' }}>{src ? <img src={src} alt="미리보기" style={{ width: '100%', height: '100%', objectFit: 'contain' }} /> : <span style={{ color: '#8a8a96', fontSize: '11px' }}>이미지 선택</span>}</button><input ref={input} type="file" accept="image/*" style={{ display: 'none' }} onChange={(e) => { const f = e.target.files && e.target.files[0]; if (!f) return; const r = new FileReader(); r.onload = () => setSrc(r.result); r.readAsDataURL(f); e.target.value = ''; }} /><div style={{ display: 'grid', gap: '7px' }}><input value={name} onChange={(e) => setName(e.target.value)} placeholder={KIND_LABEL[kind] + ' 이름'} style={{ border: '1px solid #e5e5ec', borderRadius: '7px', padding: '8px 10px', font: 'inherit', fontSize: '12px' }} /><input value={tags} onChange={(e) => setTags(e.target.value)} placeholder="태그 (쉼표로 구분)" style={{ border: '1px solid #e5e5ec', borderRadius: '7px', padding: '8px 10px', font: 'inherit', fontSize: '12px' }} /><input value={description} onChange={(e) => setDescription(e.target.value)} placeholder="설명 (선택)" style={{ border: '1px solid #e5e5ec', borderRadius: '7px', padding: '8px 10px', font: 'inherit', fontSize: '12px' }} /></div></div>{admin && <label style={{ display: 'flex', alignItems: 'center', gap: '7px', marginTop: '12px', color: '#4b4b58', fontSize: '11.5px', fontWeight: 700 }}><input type="checkbox" checked={publicVisible} onChange={(e) => setPublicVisible(e.target.checked)} />공용 노출 <span style={{ color: '#9696a2', fontWeight: 500 }}>체크한 자산만 모든 작업자에게 표시</span></label>}<div style={{ display: 'flex', justifyContent: 'flex-end', gap: '7px', marginTop: '12px' }}><button type="button" onClick={onCancel} style={btn(false)}>취소</button><button type="button" disabled={busy} onClick={save} style={{ ...btn(true), opacity: busy ? .55 : 1 }}>{busy ? '저장 중…' : '저장'}</button></div></div>;
  }

  window.AssetLibraryField = AssetLibraryField;
})();
