// Grid & List views

function Card({ file, idx, focused, selected, onSelect, onOpen, onPick, onReject, onRate, onColor, onTag, onRemoveTag, onSetTagFilter, setFocused, density }) {
  const [hover, setHover] = React.useState(false);
  const [showTag, setShowTag] = React.useState(false);
  const [tagVal, setTagVal] = React.useState('');
  // Default to 3:4 portrait if no dimensions provided
  const ratio = file.h && file.w ? file.h / file.w : 1.33;
  return (
    <div
      onMouseEnter={() => { setHover(true); setFocused(idx); }}
      onMouseLeave={() => setHover(false)}
      onClick={onOpen}
      style={{
        position: 'relative', cursor: 'zoom-in',
        background: 'var(--bg-1)', borderRadius: 6, overflow: 'hidden',
        border: `1px solid ${selected ? 'var(--accent)' : focused ? 'var(--line-3)' : 'var(--line-1)'}`,
        transition: 'border-color 140ms',
        animation: file.isNew ? 'fade-up 220ms ease' : 'none',
      }}>
      {/* Image */}
      <div style={{ position: 'relative', overflow: 'hidden', background: 'var(--bg-2)' }}>
        <div style={{ width: '100%', paddingBottom: `${ratio * 100}%`, position: 'relative' }}>
          <img src={file.thumb_url} alt={file.filename} loading="lazy" decoding="async"
            style={{
              position: 'absolute', inset: 0, width: '100%', height: '100%',
              objectFit: 'cover',
              opacity: file.reject ? 0.35 : 1,
              filter: file.reject ? 'saturate(0.3)' : 'none',
              transition: 'opacity 200ms, transform 400ms',
              transform: hover ? 'scale(1.02)' : 'scale(1)',
            }}/>
        </div>

        {/* Color strip — left edge */}
        {file.color && (
          <div style={{
            position: 'absolute', top: 0, bottom: 0, left: 0, width: 3,
            background: colorHex(file.color),
          }}/>
        )}

        {/* Top-left badges */}
        <div style={{ position: 'absolute', top: 7, left: file.color ? 10 : 7, display: 'flex', flexDirection: 'column', gap: 4, alignItems: 'flex-start' }}>
          {file.pick && (
            <div key="pick-badge" style={{
              display: 'flex', alignItems: 'center', gap: 4,
              padding: '2px 6px 2px 5px', borderRadius: 3,
              background: 'var(--accent)', color: 'var(--accent-text)',
              fontSize: 9.5, fontWeight: 700, letterSpacing: 0.08, textTransform: 'uppercase',
              boxShadow: '0 1px 3px rgba(0,0,0,0.2)',
              animation: 'badge-pop 280ms cubic-bezier(0.34,1.56,0.64,1)',
            }}>
              <IconCheck size={10} stroke="#1a1200"/> Pick
            </div>
          )}
          {file.reject && (
            <div key="reject-badge" style={{
              display: 'flex', alignItems: 'center', gap: 4,
              padding: '2px 6px 2px 5px', borderRadius: 3,
              background: 'var(--reject-badge-bg)', color: 'var(--reject)',
              border: '1px solid var(--reject)',
              fontSize: 9.5, fontWeight: 700, letterSpacing: 0.08, textTransform: 'uppercase',
              backdropFilter: 'blur(4px)',
              animation: 'reject-slide 200ms ease',
            }}>
              <IconX size={10}/> Reject
            </div>
          )}
          {file.blur && !file.pick && !file.reject && (
            <div style={{
              padding: '2px 6px', borderRadius: 3,
              background: 'rgba(20,20,24,0.75)', color: '#ffb27a',
              border: '1px solid rgba(255,178,122,0.3)',
              fontSize: 9, fontWeight: 500, letterSpacing: 0.08, textTransform: 'uppercase',
              fontFamily: 'var(--mono)', backdropFilter: 'blur(4px)',
            }}>
              ⚠ Soft
            </div>
          )}
        </div>

        {/* Top-right — file type pill + select */}
        <div style={{ position: 'absolute', top: 7, right: 7, display: 'flex', gap: 5, alignItems: 'center' }}>
          <span style={{
            fontFamily: 'var(--mono)', fontSize: 9, fontWeight: 600,
            padding: '1.5px 5px', borderRadius: 3,
            background: 'var(--glass-bg)', backdropFilter: 'blur(6px)',
            color: file.file_type === 'RAW' ? '#ffb27a' : 'var(--glass-ink)',
            border: `1px solid ${file.file_type === 'RAW' ? 'rgba(255,178,122,0.3)' : 'var(--line-2)'}`,
            letterSpacing: 0.08,
          }}>{file.file_type}</span>
          <label onClick={e => e.stopPropagation()}
            style={{
              display: 'flex', alignItems: 'center', justifyContent: 'center',
              width: 18, height: 18, borderRadius: 3,
              background: selected ? 'var(--accent)' : 'var(--glass-bg)',
              border: `1px solid ${selected ? 'var(--accent)' : 'var(--line-2)'}`,
              backdropFilter: 'blur(6px)', cursor: 'pointer',
              opacity: hover || selected ? 1 : 0, transition: 'opacity 150ms',
            }}>
            <input type="checkbox" checked={selected} onChange={e => onSelect(e.target.checked)} style={{ display: 'none' }}/>
            {selected && <IconCheck size={10} stroke="#1a1200" strokeWidth={2.5}/>}
          </label>
        </div>

        {/* Quick actions on hover — bottom right */}
        <div style={{
          position: 'absolute', right: 7, bottom: 7,
          display: 'flex', gap: 4,
          opacity: hover ? 1 : 0, transition: 'opacity 150ms',
        }} onClick={e => e.stopPropagation()}>
          <QuickBtn title="Pick (P)" active={file.pick} onClick={onPick} glyph="✓" accent/>
          <QuickBtn title="Reject (X)" active={file.reject} onClick={onReject} glyph="✕" reject/>
          <QuickBtn title="Download" onClick={() => { window.open(file.download_url || `/download/${encodeURIComponent(file.filename)}`, '_blank'); }} icon={<IconDownload size={11}/>}/>
        </div>

        {/* Gradient bottom */}
        <div style={{
          position: 'absolute', left: 0, right: 0, bottom: 0, height: 40,
          background: 'linear-gradient(to top, var(--card-gradient), transparent)',
          pointerEvents: 'none',
        }}/>

        {/* Filename bottom-left */}
        <div style={{
          position: 'absolute', left: 10, bottom: 7,
          fontFamily: 'var(--mono)', fontSize: 10, color: 'var(--ink-0)',
          textShadow: '0 1px 3px rgba(0,0,0,0.6)', letterSpacing: 0.04,
          opacity: 0.9,
        }}>
          {file.filename}
        </div>
      </div>

      {/* Meta row */}
      {density !== 'tight' && (
        <div style={{ padding: '8px 10px 10px', display: 'flex', alignItems: 'center', gap: 8, minHeight: 36 }}>
          <Stars rating={file.rating} onRate={onRate} size={12}/>
          <div style={{ flex: 1, display: 'flex', flexWrap: 'wrap', gap: 3, alignItems: 'center' }}>
            {(file.tags||[]).map(t => (
              <Chip key={t} onClick={e => { e.stopPropagation(); onSetTagFilter(t); }}
                onRemove={() => onRemoveTag(t)}>{t}</Chip>
            ))}
            {showTag ? (
              <input autoFocus value={tagVal}
                onClick={e => e.stopPropagation()}
                onChange={e => setTagVal(e.target.value)}
                onKeyDown={e => { if (e.key === 'Enter') { onTag(tagVal.trim().toLowerCase()); setTagVal(''); setShowTag(false); } if (e.key === 'Escape') { setShowTag(false); setTagVal(''); } }}
                onBlur={() => { if (tagVal.trim()) onTag(tagVal.trim().toLowerCase()); setShowTag(false); setTagVal(''); }}
                placeholder="tag…" style={{
                  background: 'var(--bg-3)', border: '1px solid var(--line-3)', borderRadius: 99,
                  padding: '1px 7px', fontSize: 10, color: 'var(--ink-0)', outline: 'none', width: 60,
                }}/>
            ) : (
              <button onClick={e => { e.stopPropagation(); setShowTag(true); }}
                style={{ background: 'transparent', border: '1px dashed var(--line-2)', color: 'var(--ink-3)',
                  padding: '1px 6px', borderRadius: 99, cursor: 'pointer', fontSize: 10 }}>
                +tag
              </button>
            )}
          </div>
          <span className="mono" style={{ fontSize: 9.5, color: 'var(--ink-3)' }}>{file.size}</span>
        </div>
      )}
    </div>
  );
}

function QuickBtn({ title, active, onClick, glyph, icon, accent, reject }) {
  const bg = active && accent ? 'var(--accent)' : active && reject ? 'var(--reject)' : 'var(--glass-bg)';
  const fg = active && accent ? '#1a1200' : active && reject ? '#fff' : 'var(--glass-ink)';
  const border = active && accent ? 'var(--accent)' : active && reject ? 'var(--reject)' : 'var(--line-2)';
  return (
    <button title={title} onClick={e => { e.stopPropagation(); onClick(); }}
      style={{
        width: 22, height: 22, borderRadius: 4,
        background: bg, color: fg, border: `1px solid ${border}`,
        backdropFilter: 'blur(6px)', cursor: 'pointer',
        display: 'flex', alignItems: 'center', justifyContent: 'center',
        fontSize: 11, fontWeight: 700, transition: 'all 120ms',
      }}>{icon || glyph}</button>
  );
}

function colorHex(c) {
  return { red: '#e5484d', orange: '#ff9b50', yellow: '#f4b942',
           green: '#52c878', blue: '#70a5ff', purple: '#ba80f0' }[c] || 'transparent';
}

function GridView({ items, focused, setFocused, selected, actions, density = 'normal' }) {
  const [screenW, setScreenW] = React.useState(window.innerWidth);
  React.useEffect(() => {
    const fn = () => setScreenW(window.innerWidth);
    window.addEventListener('resize', fn);
    return () => window.removeEventListener('resize', fn);
  }, []);
  let cols;
  if (screenW < 540) cols = 2;
  else if (screenW < 768) cols = 3;
  else cols = density === 'tight' ? 6 : density === 'loose' ? 3 : 4;
  return (
    <div style={{
      display: 'grid',
      gridTemplateColumns: `repeat(${cols}, 1fr)`,
      gap: density === 'tight' ? 6 : 10,
      padding: '14px 20px 40px',
      alignItems: 'start',
    }}>
      {items.map((f, idx) => (
        <Card key={f.filename} file={f} idx={idx}
          focused={focused === idx} selected={selected.has(f.filename)}
          setFocused={setFocused}
          density={density}
          onSelect={(v) => actions.toggleSelect(f.filename, v)}
          onOpen={() => actions.openLightbox(idx)}
          onPick={() => actions.pick(f.filename)}
          onReject={() => actions.reject(f.filename)}
          onRate={(r) => actions.rate(f.filename, r)}
          onColor={(c) => actions.color(f.filename, c)}
          onTag={(t) => t && actions.tag(f.filename, t)}
          onRemoveTag={(t) => actions.removeTag(f.filename, t)}
          onSetTagFilter={(t) => actions.setTagFilter(t)}
        />
      ))}
    </div>
  );
}

function ListView({ items, focused, setFocused, selected, actions }) {
  return (
    <div style={{ padding: '0 20px 40px' }}>
      <div style={{
        display: 'grid',
        gridTemplateColumns: '24px 56px 1.5fr 60px 80px 110px 1.2fr 110px 44px',
        gap: 10, padding: '10px 14px', borderBottom: '1px solid var(--line-1)',
        position: 'sticky', top: 44, background: 'var(--bg-0)', zIndex: 5,
      }}>
        {['', '', 'Filename', 'Type', 'Size', 'Rating', 'Tags', 'Captured', ''].map((h, i) => (
          <div key={i} className="mono" style={{ fontSize: 9.5, color: 'var(--ink-3)', letterSpacing: 0.1, textTransform: 'uppercase' }}>{h}</div>
        ))}
      </div>
      {items.map((f, idx) => (
        <div key={f.filename} onClick={() => actions.openLightbox(idx)}
          onMouseEnter={() => setFocused(idx)}
          style={{
            display: 'grid',
            gridTemplateColumns: '24px 56px 1.5fr 60px 80px 110px 1.2fr 110px 44px',
            gap: 10, padding: '8px 14px', alignItems: 'center',
            borderBottom: '1px solid var(--line-1)',
            background: selected.has(f.filename) ? 'var(--accent-soft)' : focused === idx ? 'var(--bg-2)' : 'transparent',
            cursor: 'pointer', transition: 'background 100ms',
            opacity: f.reject ? 0.55 : 1,
          }}>
          <label onClick={e => e.stopPropagation()} style={{ display: 'flex', cursor: 'pointer' }}>
            <input type="checkbox" checked={selected.has(f.filename)} onChange={e => actions.toggleSelect(f.filename, e.target.checked)} style={{ accentColor: 'var(--accent)' }}/>
          </label>
          <div style={{ position: 'relative', width: 48, height: 36, overflow: 'hidden', borderRadius: 3, background: 'var(--bg-2)' }}>
            <img src={f.thumb_url} alt="" loading="lazy" style={{ width: '100%', height: '100%', objectFit: 'cover' }}/>
            {f.pick && <div style={{ position: 'absolute', top: 2, left: 2, width: 10, height: 10, borderRadius: 2, background: 'var(--accent)' }}/>}
            {f.reject && <div style={{ position: 'absolute', top: 2, left: 2, width: 10, height: 10, borderRadius: 2, background: 'var(--reject)' }}/>}
          </div>
          <div style={{ display: 'flex', alignItems: 'center', gap: 6 }}>
            {f.color && <span style={{ width: 6, height: 6, borderRadius: '50%', background: colorHex(f.color), flexShrink: 0 }}/>}
            <span className="mono" style={{ fontSize: 11.5, color: 'var(--ink-0)' }}>{f.filename}</span>
          </div>
          <Pill color={f.file_type === 'RAW' ? 'raw' : 'jpg'}>{f.file_type}</Pill>
          <span className="mono" style={{ fontSize: 10.5, color: 'var(--ink-2)' }}>{f.size}</span>
          <Stars rating={f.rating} onRate={(r) => actions.rate(f.filename, r)} size={11}/>
          <div style={{ display: 'flex', gap: 3, flexWrap: 'wrap', alignItems: 'center' }} onClick={e => e.stopPropagation()}>
            {(f.tags||[]).slice(0,3).map(t => <Chip key={t} onClick={()=>actions.setTagFilter(t)}>{t}</Chip>)}
          </div>
          <span className="mono" style={{ fontSize: 10.5, color: 'var(--ink-3)' }}>
            {new Date(f.timestamp).toLocaleTimeString([], { hour: '2-digit', minute: '2-digit', second: '2-digit' })}
          </span>
          <div onClick={e => e.stopPropagation()} style={{ display: 'flex', gap: 2, justifyContent: 'flex-end' }}>
            <Btn size="sm" icon={<IconDownload size={12}/>} onClick={() => window.open(f.download_url || `/download/${encodeURIComponent(f.filename)}`, '_blank')}/>
          </div>
        </div>
      ))}
    </div>
  );
}

Object.assign(window, { GridView, ListView, colorHex });
