// b/app.jsx — Briklab Viewfinder prototype shell + state machine.

const ACCENTS = ['#d97757', '#2f6cc0', '#1f8a5b', '#7a5ae0', '#c8483b'];

const TWEAK_DEFAULTS = /*EDITMODE-BEGIN*/{
  "accent": "#d97757",
  "motion": true
}/*EDITMODE-END*/;

function useScale(w, h) {
  const [scale, setScale] = React.useState(1);
  React.useEffect(() => {
    const fit = () => setScale(Math.min(1, (window.innerHeight - 48) / h, (window.innerWidth - 32) / w));
    fit();
    window.addEventListener('resize', fit);
    return () => window.removeEventListener('resize', fit);
  }, [w, h]);
  return scale;
}

// On a real phone we drop the on-screen bezel and run full-bleed; on a larger
// screen (PC/tablet) we keep the framed phone mock.
function useIsPhone() {
  const q = '(max-width: 640px)';
  const [phone, setPhone] = React.useState(() => typeof window !== 'undefined' && window.matchMedia(q).matches);
  React.useEffect(() => {
    const m = window.matchMedia(q);
    const fn = () => setPhone(m.matches);
    m.addEventListener ? m.addEventListener('change', fn) : m.addListener(fn);
    return () => { m.removeEventListener ? m.removeEventListener('change', fn) : m.removeListener(fn); };
  }, []);
  return phone;
}

function TopBar({ savedCount, cartCount, onSaved, onCart, brickCount }) {
  return (
    <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', padding: '12px 18px 4px' }}>
      <div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
        <span style={{ width: 7, height: 7, borderRadius: 7, background: 'var(--accent)' }} />
        <span style={{ fontFamily: mono, fontSize: 11, letterSpacing: 1, color: T.ink }}>BRIKLAB</span>
        <span style={{ fontFamily: mono, fontSize: 10, color: T.ink2 }}>· {brickCount} klodser</span>
      </div>
      <div style={{ display: 'flex', gap: 8 }}>
        <PillBtn onClick={onSaved} count={savedCount}>♥</PillBtn>
        <PillBtn onClick={onCart} count={cartCount}>⌃</PillBtn>
      </div>
    </div>
  );
}
function PillBtn({ children, count, onClick }) {
  return (
    <button onClick={onClick} style={{ position: 'relative', width: 34, height: 34, borderRadius: 17, border: '1px solid ' + T.line, background: T.paper, cursor: 'pointer', fontSize: 14, color: T.ink, display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
      {children === '⌃' ? <CartIcon /> : children}
      {count > 0 && (
        <span style={{ position: 'absolute', top: -5, right: -5, minWidth: 16, height: 16, padding: '0 4px', borderRadius: 8, background: 'var(--accent)', color: '#fff', fontFamily: mono, fontSize: 9.5, fontWeight: 600, display: 'flex', alignItems: 'center', justifyContent: 'center' }}>{count}</span>
      )}
    </button>
  );
}
function CartIcon() {
  return (
    <svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke={T.ink} strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round">
      <circle cx="9" cy="20" r="1.4" /><circle cx="18" cy="20" r="1.4" />
      <path d="M2 3h2.2l2.3 12.2a1.6 1.6 0 0 0 1.6 1.3h8.4a1.6 1.6 0 0 0 1.6-1.2L21.4 7H5.4" />
    </svg>
  );
}

function App() {
  const [t, setTweak] = useTweaks(TWEAK_DEFAULTS);
  const motion = t.motion;

  const [screen, setScreen] = React.useState('camera'); // camera|analyzing|inventory|deck|detail
  const [active, setActive] = React.useState(null);      // active set
  const [savedIds, setSavedIds] = React.useState([]);
  const [cart, setCart] = React.useState([]);
  const [sheet, setSheet] = React.useState(null);        // 'saved'|'cart'|null
  const [toast, setToast] = React.useState(null);

  // inventory + matching state
  const [photo, setPhoto] = React.useState(null);        // data url preview
  const [items, setItems] = React.useState([]);          // editable inventory rows {part,color,count}
  const [projects, setProjects] = React.useState([]);    // matched real sets
  const [source, setSource] = React.useState('manual');  // api|manual
  const [anError, setAnError] = React.useState(false);
  const [finding, setFinding] = React.useState(false);
  const reqId = React.useRef(0);

  React.useEffect(() => {
    document.documentElement.style.setProperty('--accent', t.accent);
  }, [t.accent]);

  const flash = (msg) => { setToast(msg); clearTimeout(flash._id); flash._id = setTimeout(() => setToast(null), 1700); };

  const toggleSave = (p) => {
    setSavedIds(ids => {
      if (ids.includes(p.id)) { flash('Fjernet fra gemte'); return ids.filter(x => x !== p.id); }
      flash('Gemt ♥  ·  ' + p.name); return [...ids, p.id];
    });
  };
  const addToCart = (p) => {
    if (!p.missing.length) { flash('Du har alle delene 🎉'); return; }
    setCart(c => {
      if (c.some(it => it.from === p.name)) return c;
      flash('Lagt på indkøbslisten'); 
      return [...c, ...p.missing.map(m => ({ ...m, from: p.name }))];
    });
  };
  const inList = (p) => cart.some(it => it.from === p.name);

  // ---- photo → seed inventory (AI guess the user then edits) ----
  const onCapture = async (shot) => {
    const myReq = ++reqId.current;
    setPhoto(shot.preview); setAnError(false); setProjects([]);
    setScreen('analyzing');
    try {
      const res = await analyzeImage(shot.base64, shot.mediaType);
      if (myReq !== reqId.current) return;
      setItems(res.items); setSource(res.source);
      setScreen('inventory');
    } catch (e) {
      console.warn(e);
      if (myReq === reqId.current) { setItems([]); setSource('manual'); setScreen('inventory'); }
    }
  };

  // ---- inventory → match real sets (client-side, against sets-pool.json) ----
  const onFind = async () => {
    setFinding(true);
    try {
      const res = await findSets(items);
      setProjects(res.projects);
      if (res.placeholder) flash('Demo-sæt · kør build-pool for rigtige sæt');
      setScreen('deck');
    } catch (e) { console.warn(e); flash('Kunne ikke hente sæt'); }
    finally { setFinding(false); }
  };

  const openInstructions = (p) => { window.open(p.instr, '_blank', 'noopener'); };

  const restart = () => { setScreen('camera'); setSheet(null); setAnError(false); };

  const W = 392, H = 808;
  const scale = useScale(W, H);
  const isPhone = useIsPhone();
  const darkTop = screen === 'camera' || screen === 'analyzing' || screen === 'inventory';
  const brickCount = items.length ? items.reduce((a, it) => a + (Number(it.count) || 0), 0) : '—';

  const topBar = (
    <TopBar savedCount={savedIds.length} cartCount={cart.reduce((a,it)=>a+it.q,0)} brickCount={brickCount}
      onSaved={() => setSheet('saved')} onCart={() => setSheet('cart')} />
  );

  let body = null;
  if (screen === 'camera') body = <Camera onCapture={onCapture} />;
  else if (screen === 'analyzing') body = (
    <Analyzing photo={photo} motion={motion} error={anError}
      onRetry={restart}
      onUpload={() => { restart(); }} />
  );
  else if (screen === 'inventory') body = (
    <InventoryReveal items={items} onItems={setItems} motion={motion} source={source}
      finding={finding} catalog={window.CATALOG}
      onClose={restart} onFind={onFind} />
  );
  else if (screen === 'deck') body = (
    <Deck projects={projects} motion={motion} savedIds={savedIds} topBar={topBar} brickCount={brickCount}
      onOpen={(p) => { setActive(p); setScreen('detail'); }}
      onSave={(p) => toggleSave(p)} />
  );
  else if (screen === 'detail') body = (
    <Detail project={active} saved={savedIds.includes(active.id)} inList={inList(active)}
      onBack={() => setScreen('deck')}
      onBuild={() => openInstructions(active)}
      onSave={() => toggleSave(active)}
      onAddAll={() => addToCart(active)} />
  );

  // The phone "screen" — identical content whether it's bezeled (desktop mock)
  // or running full-bleed on a real phone. `chrome` = draw the fake status bar +
  // notch (desktop only); on a real phone we honor the device safe-area instead.
  const topInset = (chrome) => (chrome ? 30 : 'env(safe-area-inset-top, 0px)');
  const renderScreen = (chrome) => (
    <div style={{ position: 'absolute', inset: chrome ? 11 : 0, borderRadius: chrome ? 36 : 0, overflow: 'hidden', background: darkTop ? T.screen : T.paper }}>
      {chrome && (
        <>
          {/* status bar */}
          <div style={{ position: 'absolute', top: 0, left: 0, right: 0, height: 30, zIndex: 100, display: 'flex', justifyContent: 'space-between', alignItems: 'center', padding: '0 24px',
            color: darkTop ? '#f7f5ee' : T.ink, pointerEvents: 'none' }}>
            <span style={{ fontFamily: mono, fontSize: 11, fontWeight: 500 }}>9:41</span>
            <span style={{ fontFamily: mono, fontSize: 10, letterSpacing: 1 }}>5G ▚▚▚ ▮</span>
          </div>
          {/* notch */}
          <div style={{ position: 'absolute', top: 8, left: '50%', transform: 'translateX(-50%)', width: 116, height: 26, background: '#0b0b09', borderRadius: 16, zIndex: 101 }} />
        </>
      )}

      {/* content */}
      <div style={{ position: 'absolute', top: topInset(chrome), left: 0, right: 0, bottom: 0, overflow: 'hidden' }}>
        {body}
        <Toast msg={toast} />
      </div>

      {/* sheets */}
      {sheet === 'saved' && (
        <div style={{ position: 'absolute', top: topInset(chrome), left: 0, right: 0, bottom: 0 }}>
          <SavedSheet projects={projects} savedIds={savedIds} motion={motion}
            onClose={() => setSheet(null)}
            onOpen={(p) => { setActive(p); setSheet(null); setScreen('detail'); }} />
        </div>
      )}
      {sheet === 'cart' && (
        <div style={{ position: 'absolute', top: topInset(chrome), left: 0, right: 0, bottom: 0 }}>
          <ShoppingSheet items={cart} motion={motion}
            onClose={() => setSheet(null)}
            onRemove={(i) => setCart(c => c.filter((_, k) => k !== i))} />
        </div>
      )}
    </div>
  );

  return (
    <>
      {isPhone ? (
        /* real phone — full screen, no bezel */
        <div style={{ position: 'fixed', inset: 0, overflow: 'hidden', background: darkTop ? T.screen : T.paper }}>
          {renderScreen(false)}
        </div>
      ) : (
        /* PC / tablet — framed phone mock */
        <div style={{ position: 'fixed', inset: 0, display: 'flex', alignItems: 'center', justifyContent: 'center', overflow: 'hidden' }}>
          <div style={{ transform: `scale(${scale})`, transformOrigin: 'center' }}>
            {/* phone */}
            <div style={{ width: W, height: H, borderRadius: 46, background: '#0b0b09', padding: 11, boxShadow: '0 40px 90px rgba(0,0,0,.5), inset 0 0 0 2px #2a2926', position: 'relative' }}>
              {renderScreen(true)}
            </div>
          </div>
        </div>
      )}

      <TweaksPanel title="Tweaks">
        <TweakSection label="Udseende" />
        <TweakColor label="Accent-farve" value={t.accent} options={ACCENTS} onChange={(v) => setTweak('accent', v)} />
        <TweakToggle label="Animationer" value={t.motion} onChange={(v) => setTweak('motion', v)} />
        <TweakSection label="Demo" />
        <TweakButton label="Tilbage til kameraet" onClick={restart} />
        <div style={{ fontFamily: mono, fontSize: 10, color: 'rgba(41,38,27,.55)', padding: '4px 2px', lineHeight: 1.5 }}>
          Tag/upload et foto → ret dit inventar → find rigtige LEGO-sæt du kan bygge, med ærligt match og links til de officielle byggevejledninger. Swipe sæt (← spring over · ↑ gem · → åbn).
        </div>
      </TweaksPanel>
    </>
  );
}

ReactDOM.createRoot(document.getElementById('root')).render(<App />);
