/* ============================================================
   Catered · App — state, tabs, calendar export, tweaks
   ============================================================ */
const { useState: useSA, useEffect: useEA, useCallback: useCbA, useRef: useRefA } = React;
const CAT = window.CAT;
const D = window.CATDATA;

const TWEAK_DEFAULTS = /*EDITMODE-BEGIN*/{
  "accent": "#F25577",
  "weekLayout": "grid",
  "aisleTints": true
}/*EDITMODE-END*/;

const ACCENT_HOVER = { '#F25577': '#D63960', '#6FB35E': '#4F8842', '#5FA9CF': '#3784B0', '#FFC93D': '#C99416' };

const DEFAULT_STATE = { recipes: {}, recipeOrder: [], plans: {}, checks: {}, manuals: {}, currentWeek: '', activeTab: 'recipes', weeksScope: 1 };

function ensureWeek(s, wk) {
  if (!s.plans[wk]) s.plans[wk] = {};
  if (!s.checks[wk]) s.checks[wk] = {};
  if (!s.manuals[wk]) s.manuals[wk] = [];
}
function loadState() {
  let s;
  try { s = { ...DEFAULT_STATE, ...(JSON.parse(localStorage.getItem(D.STORAGE_KEY) || '{}')) }; }
  catch (e) { s = { ...DEFAULT_STATE }; }
  if (!s.currentWeek) s.currentWeek = CAT.ymd(CAT.mondayOf(new Date()));
  ensureWeek(s, s.currentWeek);
  CAT.migrateState(s);
  return s;
}

function App() {
  const [t, setTweak] = useTweaks(TWEAK_DEFAULTS);
  const [state, setState] = useSA(loadState);
  const [tab, setTabState] = useSA(() => state.activeTab || 'recipes');
  const [toastMsg, setToastMsg] = useSA('');
  const toastTimer = useRefA(null);

  // persist
  useEA(() => { try { localStorage.setItem(D.STORAGE_KEY, JSON.stringify(state)); } catch (e) {} }, [state]);

  // tweaks → CSS
  useEA(() => {
    const r = document.documentElement;
    r.style.setProperty('--coral-300', t.accent);
    r.style.setProperty('--coral-400', ACCENT_HOVER[t.accent] || '#D63960');
    r.style.setProperty('--pop', t.accent);
  }, [t.accent]);
  useEA(() => {
    document.body.dataset.weekLayout = t.weekLayout;
    document.body.dataset.aisleTints = t.aisleTints ? 'on' : 'off';
  }, [t.weekLayout, t.aisleTints]);

  const mutate = useCbA((fn) => {
    setState((prev) => { const next = JSON.parse(JSON.stringify(prev)); fn(next); return next; });
  }, []);

  const toast = useCbA((msg) => {
    setToastMsg(msg);
    if (toastTimer.current) clearTimeout(toastTimer.current);
    toastTimer.current = setTimeout(() => setToastMsg(''), 2000);
  }, []);

  const setTab = useCbA((name) => {
    setTabState(name);
    mutate((s) => { s.activeTab = name; });
    window.scrollTo({ top: 0, behavior: 'instant' in window ? 'instant' : 'auto' });
  }, [mutate]);

  const weekStart = state.currentWeek;
  const scope = state.weeksScope || 1;
  const weekStarts = CAT.weekStartsFrom(weekStart, scope);

  const api = {
    weekStart,
    weekStarts,
    scope,
    setTab,
    toast,
    setScope(n) { mutate((s) => { s.weeksScope = n; CAT.weekStartsFrom(s.currentWeek, n).forEach((w) => ensureWeek(s, w)); }); },
    addRecipe(parsed) {
      mutate((s) => {
        const id = CAT.uid();
        s.recipes[id] = {
          id, title: parsed.title || 'Untitled recipe', source_url: parsed.source_url || '',
          image_url: parsed.image_url || null, default_servings: parsed.servings || 4,
          meal: parsed.meal || D.DEFAULT_MEAL,
          ingredients: Array.isArray(parsed.ingredients) ? parsed.ingredients : [],
          tags: Array.isArray(parsed.tags) ? parsed.tags : [],
        };
        s.recipeOrder.unshift(id);
      });
    },
    addManual({ title, ingredients, meal }) {
      const parsed = ingredients.split('\n').map((x) => x.trim()).filter(Boolean).map((line) => CAT.parseManualIngredient(line));
      api.addRecipe({ title, source_url: '', image_url: null, servings: D.DEFAULT_SERVINGS, meal: meal || D.DEFAULT_MEAL, ingredients: parsed, tags: [] });
    },
    setRecipeMeal(id, meal) { mutate((s) => { if (s.recipes[id]) s.recipes[id].meal = meal; }); },
    deleteRecipe(id) {
      mutate((s) => {
        delete s.recipes[id];
        s.recipeOrder = s.recipeOrder.filter((x) => x !== id);
        for (const wk of Object.keys(s.plans)) for (const d of Object.keys(s.plans[wk])) {
          const day = s.plans[wk][d];
          if (!day) continue;
          if (day.recipeId) { if (day.recipeId === id) delete s.plans[wk][d]; continue; }
          for (const m of Object.keys(day)) if (day[m] && day[m].recipeId === id) delete day[m];
          if (Object.keys(day).length === 0) delete s.plans[wk][d];
        }
      });
    },
    setSlot(week, date, meal, recipeId, servings) {
      mutate((s) => {
        ensureWeek(s, week);
        let day = s.plans[week][date];
        if (day && day.recipeId) day = { dinner: { recipeId: day.recipeId, servings: day.servings } };
        if (!day) day = {};
        day[meal] = { recipeId, servings: servings || D.DEFAULT_SERVINGS };
        s.plans[week][date] = day;
      });
    },
    clearSlot(week, date, meal) {
      mutate((s) => {
        const wk = s.plans[week]; if (!wk) return;
        let day = wk[date]; if (!day) return;
        if (day.recipeId) day = { dinner: { recipeId: day.recipeId, servings: day.servings } };
        delete day[meal];
        if (Object.keys(day).length === 0) delete wk[date]; else wk[date] = day;
      });
    },
    bumpServings(week, date, meal, delta) {
      mutate((s) => {
        const day = s.plans[week] && s.plans[week][date]; if (!day) return;
        const slot = day[meal]; if (slot) slot.servings = Math.max(1, (slot.servings || D.DEFAULT_SERVINGS) + delta);
      });
    },
    toggleCheck(key) {
      mutate((s) => { ensureWeek(s, weekStart); if (s.checks[weekStart][key]) delete s.checks[weekStart][key]; else s.checks[weekStart][key] = true; });
    },
    toggleItem(item) {
      mutate((s) => {
        const checked = item.weeks.every((w) => s.checks[w] && s.checks[w][item.checkKey]);
        for (const w of item.weeks) { ensureWeek(s, w); if (checked) delete s.checks[w][item.checkKey]; else s.checks[w][item.checkKey] = true; }
      });
    },
    addManualItem(label, category) {
      mutate((s) => { ensureWeek(s, weekStart); s.manuals[weekStart].push({ id: CAT.uid(), label, qty: null, unit: null, category, checked: false }); });
    },
    removeManualItem(week, id) { mutate((s) => { if (s.manuals[week]) s.manuals[week] = s.manuals[week].filter((m) => m.id !== id); }); },
    navigateWeek(delta) {
      mutate((s) => { const nw = CAT.ymd(CAT.addDays(CAT.parseYmd(s.currentWeek), delta * 7)); s.currentWeek = nw; ensureWeek(s, nw); });
    },
    gotoThisWeek() { mutate((s) => { const nw = CAT.ymd(CAT.mondayOf(new Date())); s.currentWeek = nw; ensureWeek(s, nw); }); },
  };

  const counts = { recipes: state.recipeOrder.length, shopping: CAT.countShoppingItemsRange(state, weekStarts) };

  const { TopNav, Footer, Toast } = window.CATComp;
  const SCREENS = {
    recipes: window.CATRecipes.CATRecipes,
    week: window.CATWeek.CATWeek,
    shopping: window.CATShopping.CATShopping,
    export: window.CATExport.CATExport,
  };
  const Screen = SCREENS[tab] || SCREENS.recipes;

  return (
    <>
      <TopNav tab={tab} setTab={setTab} counts={counts} weekLabel={CAT.rangeLabel(weekStarts)} />
      <main style={{ flex: 1 }} key={tab}>
        <Screen state={state} api={api} t={t} />
      </main>
      <Footer />
      <Toast msg={toastMsg} />

      <TweaksPanel>
        <TweakSection label="Accent" />
        <TweakColor label="Pop colour" value={t.accent}
          options={['#F25577', '#6FB35E', '#5FA9CF', '#FFC93D']}
          onChange={(v) => setTweak('accent', v)} />
        <TweakSection label="The week" />
        <TweakRadio label="Layout" value={t.weekLayout}
          options={['grid', 'rows']}
          onChange={(v) => setTweak('weekLayout', v)} />
        <TweakToggle label="Aisle colour tints" value={t.aisleTints}
          onChange={(v) => setTweak('aisleTints', v)} />
      </TweaksPanel>
    </>
  );
}

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