// components.jsx — SaveContext + reusable building blocks for the Field Guide.

const SaveContext = React.createContext(null);

function SaveProvider({ children }) {
  const load = (k) => {
    try {
      const v = localStorage.getItem(k);
      return v ? new Set(JSON.parse(v)) : new Set();
    } catch { return new Set(); }
  };
  const [saved,  setSaved]  = React.useState(() => load('school.saved'));
  const [caught, setCaught] = React.useState(() => load('school.caught'));

  React.useEffect(() => {
    try { localStorage.setItem('school.saved',  JSON.stringify([...saved])); } catch {}
  }, [saved]);
  React.useEffect(() => {
    try { localStorage.setItem('school.caught', JSON.stringify([...caught])); } catch {}
  }, [caught]);

  const toggle = (set, setter, id) => {
    const next = new Set(set);
    if (next.has(id)) next.delete(id); else next.add(id);
    setter(next);
  };

  const value = {
    saved, caught,
    isSaved:  (id) => saved.has(id),
    isCaught: (id) => caught.has(id),
    toggleSaved:  (id) => toggle(saved,  setSaved,  id),
    toggleCaught: (id) => toggle(caught, setCaught, id),
  };
  return <SaveContext.Provider value={value}>{children}</SaveContext.Provider>;
}
const useSave = () => React.useContext(SaveContext);

// Circular pill button used on cards + detail hero.
function ASaveButton({ active, onClick, icon, ariaLabel, size = 30, dark = false }) {
  return (
    <button
      className="ctx-btn"
      onClick={(e) => { e.stopPropagation(); e.preventDefault(); onClick(); }}
      aria-label={ariaLabel}
      aria-pressed={active}
      style={{
        width: size, height: size, borderRadius: 999,
        background: active ? VI.accent : (dark ? 'rgba(8,8,10,0.55)' : 'rgba(8,8,10,0.40)'),
        backdropFilter: 'blur(10px)',
        border: `0.5px solid ${active ? VI.accent : VI.borderHi}`,
        display: 'flex', alignItems: 'center', justifyContent: 'center',
        color: active ? VI.bg : VI.text,
        transition: `all .18s ${VI.ease}`,
      }}
    >
      {icon(Math.round(size * 0.5))}
    </button>
  );
}

// Section header — JetBrains Mono ledger style.
function ASectionHd({ num, title, subtitle, action, onAction }) {
  return (
    <div style={{
      display: 'flex', alignItems: 'flex-end', justifyContent: 'space-between',
      padding: '0 20px', marginBottom: 14,
    }}>
      <div>
        <div style={{
          fontFamily: VI.fontMono, fontSize: 10, color: VI.textMute,
          letterSpacing: '0.18em', textTransform: 'uppercase', marginBottom: 6,
        }}>{num} · {subtitle}</div>
        <div style={{
          fontFamily: VI.fontDisp, fontWeight: 300, fontSize: 26,
          letterSpacing: '-0.01em', color: VI.text, lineHeight: 1.05,
        }}>{title}</div>
      </div>
      {action && (
        <button className="ctx-btn" onClick={onAction} style={{
          fontFamily: VI.fontMono, fontSize: 10, color: VI.accent,
          letterSpacing: '0.14em', textTransform: 'uppercase',
          padding: '4px 0', display: 'flex', alignItems: 'center', gap: 4,
        }}>{action} {Icon.chevronR(11)}</button>
      )}
    </div>
  );
}

// Specimen card — numbered field-guide plate. Hooks save/caught from context.
// Real cover photo via FishImage (with gradient fallback).
// Strict-data: drop top-right protection chip and LAYER · SIZE meta strip.
function ASpecimenCard({ fish, n, onClick }) {
  const sv = useSave();
  const isCaught = sv?.isCaught(fish.id);
  const isSaved  = sv?.isSaved(fish.id);
  const onKey = (e) => {
    if (e.key === 'Enter' || e.key === ' ') {
      e.preventDefault();
      onClick && onClick();
    }
  };
  return (
    <div
      role="button"
      tabIndex={0}
      onClick={onClick}
      onKeyDown={onKey}
      style={{
        width: '100%', textAlign: 'left', cursor: 'pointer',
        background: VI.bgCard, border: `0.5px solid ${VI.border}`,
        borderRadius: 4, padding: 0, overflow: 'hidden',
        transition: `border-color .22s ${VI.ease}`,
      }}
    >
      <div style={{ position: 'relative' }}>
        <FishImage fish={fish} height={120} radius={0} />
        <div style={{
          position: 'absolute', top: 8, left: 8,
          fontFamily: VI.fontMono, fontSize: 9, color: 'rgba(255,255,255,0.92)',
          letterSpacing: '0.12em', textShadow: '0 1px 4px rgba(0,0,0,0.7)',
        }}>№ {String(n).padStart(3, '0')}</div>
        {sv && (
          <div style={{
            position: 'absolute', bottom: 6, right: 6,
            display: 'flex', gap: 5, zIndex: 2,
          }}>
            <ASaveButton size={26} active={isSaved}
              onClick={() => sv.toggleSaved(fish.id)}
              icon={Icon.bookmark}
              ariaLabel={isSaved ? 'Remove from saved' : 'Save'} />
            <ASaveButton size={26} active={isCaught}
              onClick={() => sv.toggleCaught(fish.id)}
              icon={Icon.hook}
              ariaLabel={isCaught ? 'Mark as not caught' : 'Mark as caught'} />
          </div>
        )}
      </div>
      <div style={{ padding: '10px 11px 11px' }}>
        <div style={{
          fontFamily: VI.fontDisp, fontWeight: 600, fontSize: 14,
          color: VI.text, lineHeight: 1.2, marginBottom: 3,
          whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis',
        }}>{fish.name}</div>
        <div style={{
          fontFamily: VI.fontDisp, fontStyle: 'italic', fontWeight: 300,
          fontSize: 10, color: VI.textDim, lineHeight: 1.2, marginBottom: 8,
          whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis',
        }}>{fish.latin}</div>
        <div style={{
          display: 'flex', gap: 4, alignItems: 'center',
          fontFamily: VI.fontMono, fontSize: 8, color: VI.textMute,
          letterSpacing: '0.04em',
        }}>
          <span>{(fish.water || '').slice(0, 4).toUpperCase()}</span>
          {fish.family ? (
            <>
              <span style={{ width: 2, height: 2, background: VI.textFaint, borderRadius: 99 }}/>
              <span style={{ overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{fish.family.toUpperCase()}</span>
            </>
          ) : null}
        </div>
      </div>
    </div>
  );
}

// Filter chip row (Collection)
function AFilterChips({ value, onChange, options }) {
  return (
    <div style={{
      display: 'flex', gap: 6, padding: '0 20px 18px',
      overflowX: 'auto', WebkitOverflowScrolling: 'touch',
    }}>
      {options.map(([k, lbl, count]) => {
        const on = value === k;
        return (
          <button key={k} className="ctx-btn" onClick={() => onChange(k)} style={{
            display: 'flex', alignItems: 'center', gap: 6,
            padding: '7px 11px',
            background: on ? VI.text : 'transparent',
            border: `0.5px solid ${on ? VI.text : VI.border}`,
            borderRadius: 99,
            color: on ? VI.bg : VI.textDim,
            fontFamily: VI.fontMono, fontSize: 9.5,
            letterSpacing: '0.14em', textTransform: 'uppercase',
            whiteSpace: 'nowrap',
            transition: `all .18s ${VI.ease}`,
          }}>
            <span>{lbl}</span>
            <span style={{
              fontSize: 8.5, opacity: 0.7,
              padding: '1px 5px', borderRadius: 99,
              background: on ? 'rgba(8,8,10,0.18)' : 'rgba(255,255,255,0.04)',
            }}>{count}</span>
          </button>
        );
      })}
    </div>
  );
}

function AGroupLabel({ icon, text, count }) {
  return (
    <div style={{
      display: 'flex', alignItems: 'center', gap: 8,
      padding: '0 20px 10px',
    }}>
      <span style={{ color: VI.accent, display: 'flex' }}>{icon(12)}</span>
      <span style={{
        fontFamily: VI.fontMono, fontSize: 9, color: VI.textDim,
        letterSpacing: '0.18em', textTransform: 'uppercase',
      }}>{text}</span>
      <span style={{
        flex: 1, height: 0, borderTop: `0.5px solid ${VI.border}`,
      }}/>
      <span style={{
        fontFamily: VI.fontMono, fontSize: 9, color: VI.textMute,
        letterSpacing: '0.10em',
      }}>{String(count).padStart(2, '0')}</span>
    </div>
  );
}

function AEmptyState({ onBrowse }) {
  return (
    <div className="ctx-fadeIn" style={{
      margin: '12px 20px 36px',
      padding: '40px 24px',
      border: `0.5px dashed ${VI.border}`,
      borderRadius: 4,
      textAlign: 'center',
      background: `repeating-linear-gradient(135deg, ${VI.bgElev} 0 6px, transparent 6px 12px), ${VI.bg}`,
    }}>
      <div style={{
        width: 44, height: 44, borderRadius: 99, margin: '0 auto 14px',
        border: `0.5px solid ${VI.border}`,
        display: 'flex', alignItems: 'center', justifyContent: 'center',
        color: VI.textMute,
      }}>{Icon.collection(20)}</div>
      <div style={{
        fontFamily: VI.fontDisp, fontWeight: 300, fontSize: 22,
        color: VI.text, letterSpacing: '-0.01em', marginBottom: 6,
      }}>Your ledger is blank.</div>
      <div style={{
        fontFamily: VI.fontBody, fontSize: 13, color: VI.textDim,
        lineHeight: 1.5, maxWidth: 240, margin: '0 auto 20px',
      }}>
        Tap <span style={{ color: VI.accent }}>{Icon.bookmark(11)}</span> on a
        species to save it, or <span style={{ color: VI.accent }}>{Icon.hook(11)}</span>
        {' '}to mark it caught.
      </div>
      <button className="ctx-btn" onClick={onBrowse} style={{
        padding: '10px 16px',
        background: VI.text, color: VI.bg,
        border: 'none', borderRadius: 2,
        fontFamily: VI.fontMono, fontSize: 10,
        letterSpacing: '0.16em', textTransform: 'uppercase',
      }}>Browse the Index</button>
    </div>
  );
}

// Bottom tab bar — Index / Search / Collection.
function ATabBar({ active, onChange }) {
  const tabs = [
    ['home', 'Index', Icon.grid],
    ['search', 'Search', Icon.search],
    ['collection', 'Collection', Icon.collection],
  ];
  return (
    <div style={{
      position: 'sticky', bottom: 0, left: 0, right: 0, zIndex: 30,
      background: 'rgba(8,8,10,0.88)', backdropFilter: 'blur(20px) saturate(180%)',
      borderTop: `0.5px solid ${VI.border}`,
      padding: '8px 0 calc(env(safe-area-inset-bottom, 0px) + 14px)',
    }}>
      <div style={{ display: 'flex', justifyContent: 'space-around', alignItems: 'center' }}>
        {tabs.map(([k, lbl, I]) => (
          <button key={k} className="ctx-btn" onClick={() => onChange(k)} style={{
            display: 'flex', flexDirection: 'column', alignItems: 'center',
            gap: 3, padding: '6px 10px',
            color: active === k ? VI.accent : VI.textMute,
            transition: `color .18s ${VI.ease}`,
          }}>
            {I(20)}
            <span style={{
              fontFamily: VI.fontMono, fontSize: 8.5, letterSpacing: '0.12em',
              textTransform: 'uppercase',
            }}>{lbl}</span>
          </button>
        ))}
      </div>
    </div>
  );
}

Object.assign(window, {
  SaveContext, SaveProvider, useSave,
  ASaveButton, ASectionHd, ASpecimenCard,
  AFilterChips, AGroupLabel, AEmptyState, ATabBar,
});
