/* app.jsx — main token economy app (pixel edition, Dutch).
   Navigation: Klaslijst | Recepten
   Persists state to localStorage.
*/

const { useState, useEffect, useCallback, useRef } = React;

const ADMIN_PASS  = '1994';
const STORAGE_KEY = 'l3a-economy-v4';

// ---- client-side image compression -----------------------------------
async function compressImage(file, { maxDim = 192, quality = 0.78 } = {}) {
  const bitmap = await createImageBitmap(file);
  const scale = Math.min(1, maxDim / Math.max(bitmap.width, bitmap.height));
  const w = Math.round(bitmap.width * scale);
  const h = Math.round(bitmap.height * scale);
  const canvas = document.createElement('canvas');
  canvas.width = w; canvas.height = h;
  const ctx = canvas.getContext('2d');
  ctx.imageSmoothingEnabled = false;
  ctx.drawImage(bitmap, 0, 0, w, h);
  bitmap.close?.();
  let q = quality;
  let dataUrl = canvas.toDataURL('image/jpeg', q);
  while (dataUrl.length > 100_000 * 1.37 && q > 0.25) {
    q -= 0.1;
    dataUrl = canvas.toDataURL('image/jpeg', q);
  }
  return dataUrl;
}

// ---- state persistence -----------------------------------------------
function loadState() {
  try {
    const raw = localStorage.getItem(STORAGE_KEY);
    if (raw) {
      const s = JSON.parse(raw);
      return {
        students:     s.students     || SEED_STUDENTS,
        classChest:   s.classChest   || SEED_CHEST,
        classRewards: s.classRewards || [],
        recipes:      s.recipes      || RECIPES,
      };
    }
  } catch {}
  return { students: SEED_STUDENTS, classChest: SEED_CHEST, classRewards: [], recipes: RECIPES };
}
function saveState(state) {
  try { localStorage.setItem(STORAGE_KEY, JSON.stringify(state)); }
  catch (e) { console.warn('save failed', e); }
}

// ---- App ------------------------------------------------------------
function App() {
  const initial = loadState();
  const [students,     setStudents]     = useState(initial.students);
  const [classChest,   setClassChest]   = useState(initial.classChest);
  const [classRewards, setClassRewards] = useState(initial.classRewards);
  const [recipes,      setRecipes]      = useState(initial.recipes);

  const [page, setPage]                 = useState('roster');
  const [openId, setOpenId]             = useState(null);
  const [adminMode, setAdmin]           = useState(false);
  const [showLogin, setShowLogin]       = useState(false);
  const [loginErr, setLoginErr]         = useState('');
  const [donateForId, setDonateForId]   = useState(null);
  const [showClassCraft, setShowClassCraft] = useState(false);
  const [showRecipeEditor, setShowRecipeEditor] = useState(false);
  // giftTarget: null | { type: 'student', studentId } | { type: 'chest' } | { type: 'all' }
  const [giftTarget, setGiftTarget]     = useState(null);
  const [toasts, setToasts]             = useState([]);
  const [splash, setSplash]             = useState(null);
  const importRef = useRef(null);

  useEffect(() => { saveState({ students, classChest, classRewards, recipes }); },
    [students, classChest, classRewards, recipes]);

  const openStudent   = openId       != null ? students.find(s => s.id === openId)       : null;
  const donateStudent = donateForId  != null ? students.find(s => s.id === donateForId)  : null;
  const giftStudent   = giftTarget?.type === 'student'
                        ? students.find(s => s.id === giftTarget.studentId)
                        : null;

  // ---- toasts ----
  const pushToast = useCallback((text, kind = 'info', icon = null) => {
    const id = Math.random().toString(36).slice(2);
    setToasts(t => [...t, { id, text, kind, icon }]);
    setTimeout(() => setToasts(t => t.filter(x => x.id !== id)), 2400);
  }, []);

  // ---- admin ----
  const tryLogin = (pass) => {
    if (pass === ADMIN_PASS) {
      setAdmin(true); setShowLogin(false); setLoginErr('');
      pushToast('Leerkrachtmodus aan', 'success');
    } else {
      setLoginErr('Verkeerd wachtwoord.');
    }
  };
  const toggleAdmin = () => {
    if (adminMode) { setAdmin(false); pushToast('Leerkrachtmodus uit', 'info'); }
    else setShowLogin(true);
  };

  // ---- export / import ----
  const exportData = () => {
    const blob = new Blob(
      [JSON.stringify({ students, classChest, classRewards, recipes }, null, 2)],
      { type: 'application/json' }
    );
    const url = URL.createObjectURL(blob);
    const a = document.createElement('a');
    a.href = url;
    a.download = `l3a-economie-${new Date().toISOString().slice(0, 10)}.json`;
    a.click();
    URL.revokeObjectURL(url);
    pushToast('Instellingen geëxporteerd', 'success');
  };

  const importData = (file) => {
    if (!file) return;
    const reader = new FileReader();
    reader.onload = (e) => {
      try {
        const d = JSON.parse(e.target.result);
        if (d.students)     setStudents(d.students);
        if (d.classChest)   setClassChest(d.classChest);
        if (d.classRewards) setClassRewards(d.classRewards);
        if (d.recipes)      setRecipes(d.recipes);
        pushToast('Instellingen geladen', 'success');
      } catch {
        pushToast('Ongeldig bestand', 'error');
      }
    };
    reader.readAsText(file);
    importRef.current.value = '';
  };

  // ---- avatar upload ----
  const uploadAvatar = useCallback(async (studentId, file) => {
    try {
      const dataUrl = await compressImage(file);
      setStudents(prev => prev.map(s =>
        s.id === studentId ? { ...s, avatar: dataUrl } : s));
      pushToast('Foto geüpload', 'success');
    } catch (e) {
      console.error(e);
      pushToast('Kon de foto niet lezen', 'error');
    }
  }, [pushToast]);

  // ---- student crafting ----
  const craftForStudent = useCallback((studentId, recipe, evt) => {
    if (evt?.clientX != null) {
      setSplash({ key: recipe.output, x: evt.clientX, y: evt.clientY, ts: Date.now() });
      setTimeout(() => setSplash(s => s ? null : s), 700);
    }
    setStudents(prev => prev.map(s => {
      if (s.id !== studentId) return s;
      for (const [k, q] of recipe.cost) if ((s.inventory[k] || 0) < q) return s;
      const inv = { ...s.inventory };
      for (const [k, q] of recipe.cost) inv[k] = (inv[k] || 0) - q;
      inv[recipe.output] = (inv[recipe.output] || 0) + 1;
      return { ...s, inventory: inv };
    }));
    const outputName = ITEMS[recipe.output]?.name ?? recipe.name;
    pushToast(`${outputName} gemaakt`, 'success', recipe.output);
  }, [pushToast]);

  // ---- donate (student → chest) ----
  const confirmDonate = useCallback((studentId, picks) => {
    setStudents(prev => prev.map(s => {
      if (s.id !== studentId) return s;
      const inv = { ...s.inventory };
      for (const [k, q] of Object.entries(picks)) {
        const take = Math.min(inv[k] || 0, q);
        if (take > 0) inv[k] = (inv[k] || 0) - take;
      }
      return { ...s, inventory: inv };
    }));
    setClassChest(prev => {
      const next = { ...prev };
      for (const [k, q] of Object.entries(picks)) {
        if (q > 0) next[k] = (next[k] || 0) + q;
      }
      return next;
    });
    const total = Object.values(picks).reduce((a, b) => a + b, 0);
    pushToast(`${total} item${total === 1 ? '' : 's'} gedoneerd aan de kist`, 'success');
    setDonateForId(null);
  }, [pushToast]);

  // ---- class craft (chest → class reward) ----
  const classCraft = useCallback((recipe, evt) => {
    for (const [k, q] of recipe.cost) {
      if ((classChest[k] || 0) < q) {
        pushToast('De kist heeft te weinig — doneer eerst meer', 'error');
        return;
      }
    }
    if (evt?.clientX != null) {
      setSplash({ key: recipe.output, x: evt.clientX, y: evt.clientY, ts: Date.now() });
      setTimeout(() => setSplash(s => s ? null : s), 700);
    }
    setClassChest(prev => {
      const next = { ...prev };
      for (const [k, q] of recipe.cost) next[k] = (next[k] || 0) - q;
      return next;
    });
    setClassRewards(prev => [...prev, { key: recipe.output, ts: Date.now() }]);
    pushToast(`Klas heeft ${recipe.name} verdiend!`, 'success', recipe.output);
    setShowClassCraft(false);
  }, [classChest, pushToast]);

  // ---- gift flow (teacher only) ----
  const confirmGift = useCallback((picks) => {
    if (!giftTarget) return;

    // Filter out zero-deltas to keep the toast clean
    const nonzero = Object.entries(picks).filter(([, v]) => v !== 0);
    if (nonzero.length === 0) { setGiftTarget(null); return; }

    if (giftTarget.type === 'student') {
      setStudents(prev => prev.map(s => {
        if (s.id !== giftTarget.studentId) return s;
        const inv = { ...s.inventory };
        for (const [k, v] of nonzero) {
          inv[k] = Math.max(0, (inv[k] || 0) + v);
        }
        return { ...s, inventory: inv };
      }));
      const target = students.find(s => s.id === giftTarget.studentId);
      const firstName = target?.name.split(' ')[0] ?? 'inwoner';
      pushToast(`Materiaal gegeven aan ${firstName}`, 'success');
    } else if (giftTarget.type === 'chest') {
      setClassChest(prev => {
        const next = { ...prev };
        for (const [k, v] of nonzero) {
          next[k] = Math.max(0, (next[k] || 0) + v);
        }
        return next;
      });
      pushToast('Materiaal aan de Klaskist gegeven', 'success');
    } else if (giftTarget.type === 'all') {
      // broadcast picks are positive-only (enforced by GiftModal)
      setStudents(prev => prev.map(s => {
        if (s.hidden) return s;
        const inv = { ...s.inventory };
        for (const [k, v] of nonzero) {
          inv[k] = Math.max(0, (inv[k] || 0) + v);
        }
        return { ...s, inventory: inv };
      }));
      const visibleCount = students.filter(s => !s.hidden).length;
      pushToast(`Materiaal gegeven aan iedereen (${visibleCount} inwoners)`, 'success');
    }
    setGiftTarget(null);
  }, [giftTarget, students, pushToast]);

  // Build the modal title/subtitle/currentMap for the active gift target.
  let giftModalProps = null;
  if (giftTarget) {
    if (giftTarget.type === 'student' && giftStudent) {
      giftModalProps = {
        title: `Geef materiaal aan ${giftStudent.name.split(' ')[0]}`,
        subtitle: 'Klik + of − om de inventaris aan te passen.',
        currentMap: giftStudent.inventory,
        broadcast: false,
        confirmLabel: 'Geef',
      };
    } else if (giftTarget.type === 'chest') {
      giftModalProps = {
        title: 'Geef materiaal aan de Klaskist',
        subtitle: 'Klik + of − om de kist aan te passen.',
        currentMap: classChest,
        broadcast: false,
        confirmLabel: 'Geef',
      };
    } else if (giftTarget.type === 'all') {
      giftModalProps = {
        title: 'Geef materiaal aan iedereen',
        subtitle: `Elke inwoner (${students.filter(s => !s.hidden).length}) krijgt dezelfde set materialen.`,
        currentMap: null,
        broadcast: true,
        confirmLabel: 'Geef aan iedereen',
      };
    }
  }

  return (
    <>
      <header className="appbar">
        <div className="brand">
          <BrandGlyph/>
          <span>L3A&nbsp;ECONOMIE</span>
          <span className="brand-sub">3DE LJR.</span>
        </div>

        <NavTabs value={page} onChange={setPage}/>

        <div className="appbar-spacer"/>

        {adminMode && (
          <div style={{ display: 'flex', gap: 8, alignItems: 'center' }}>
            <button
              className="btn-pixel violet"
              style={{ padding: '10px 16px', fontSize: 11, boxShadow: 'none' }}
              onClick={() => setGiftTarget({ type: 'all' })}
              title="Geef materiaal aan alle inwoners"
            >
              <span>＋</span> Geef aan iedereen
            </button>
            <button
              className="btn-pixel ghost"
              style={{ padding: '10px 16px', fontSize: 11, boxShadow: 'none' }}
              onClick={exportData}
              title="Exporteer alle instellingen als JSON"
            >
              ↓ Exporteer
            </button>
            <label
              className="btn-pixel ghost"
              style={{ padding: '10px 16px', fontSize: 11, boxShadow: 'none', cursor: 'pointer' }}
              title="Laad instellingen uit een eerder geëxporteerd bestand"
            >
              ↑ Importeer
              <input ref={importRef} type="file" accept=".json,application/json" hidden
                onChange={e => importData(e.target.files?.[0])} />
            </label>
          </div>
        )}

        <button
          className={`admin-toggle ${adminMode ? 'active' : ''}`}
          onClick={toggleAdmin}
        >
          <span className="admin-dot"/>
          {adminMode ? 'Leerkracht AAN' : 'Leerkracht UIT'}
        </button>
      </header>

      <main className="page">
        {page === 'roster' && (
          <>
            <ChestBanner
              classChest={classChest}
              classRewards={classRewards}
              adminMode={adminMode}
              recipes={recipes}
              onOpenClassCraft={() => setShowClassCraft(true)}
              onGiftToChest={() => setGiftTarget({ type: 'chest' })}
            />

            <div className="villager-grid">
              {students.filter(s => !s.hidden).map(s => (
                <VillagerCard
                  key={s.id}
                  student={s}
                  onOpen={() => setOpenId(s.id)}
                />
              ))}
            </div>
          </>
        )}

        {page === 'recipes' && (
          <RecipesPage
            recipes={recipes}
            adminMode={adminMode}
            onEditRecipes={() => setShowRecipeEditor(true)}
          />
        )}
      </main>

      {openStudent && (
        <StudentDetail
          student={openStudent}
          adminMode={adminMode}
          recipes={recipes}
          onClose={() => setOpenId(null)}
          onCraft={craftForStudent}
          onDonate={() => setDonateForId(openStudent.id)}
          onGift={() => setGiftTarget({ type: 'student', studentId: openStudent.id })}
          onUploadAvatar={(file) => uploadAvatar(openStudent.id, file)}
        />
      )}

      {donateStudent && (
        <DonateModal
          student={donateStudent}
          onCancel={() => setDonateForId(null)}
          onConfirm={(picks) => confirmDonate(donateStudent.id, picks)}
        />
      )}

      {showClassCraft && (
        <ClassCraftModal
          classChest={classChest}
          recipes={recipes}
          onCancel={() => setShowClassCraft(false)}
          onConfirm={classCraft}
        />
      )}

      {giftModalProps && (
        <GiftModal
          {...giftModalProps}
          onCancel={() => setGiftTarget(null)}
          onConfirm={confirmGift}
        />
      )}

      {showRecipeEditor && (
        <RecipeEditorModal
          recipes={recipes}
          onSave={(updated) => { setRecipes(updated); setShowRecipeEditor(false); pushToast('Recepten opgeslagen', 'success'); }}
          onReset={() => { setRecipes(RECIPES); setShowRecipeEditor(false); pushToast('Recepten hersteld', 'info'); }}
          onCancel={() => setShowRecipeEditor(false)}
        />
      )}

      {showLogin && (
        <AdminLoginModal
          onSubmit={tryLogin}
          onCancel={() => { setShowLogin(false); setLoginErr(''); }}
          error={loginErr}
        />
      )}

      <Toasts items={toasts}/>

      {splash && (
        <div className="craft-splash" style={{ left: splash.x - 40, top: splash.y - 40 }}>
          <div className="box">
            <ItemIcon itemKey={splash.key} size={44} glow/>
          </div>
        </div>
      )}
    </>
  );
}

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