// app/screen-shopping.jsx — categorised shopping list, generated from the
// recipes you've added. Tick items you already have; order from Woolworths.

const AISLE_RULES = [
  { aisle: 'Fresh produce', keys: ['onion', 'garlic', 'ginger', 'chilli', 'chili', 'lemon', 'lime',
    'broccoli', 'cauliflower', 'pumpkin', 'eggplant', 'spring onion', 'coriander', 'parsley', 'mint',
    'tomato', 'mushroom', 'pomegranate', 'lemongrass', 'galangal', 'kaffir', 'celery', 'potato', 'carrot'] },
  { aisle: 'Meat & seafood', keys: ['chicken', 'lamb', 'beef', 'pork', 'anchov', 'prawn', 'fish', 'bacon', 'sausage'] },
  { aisle: 'Dairy & eggs', keys: ['butter', 'yoghurt', 'buttermilk', 'milk', 'cream', 'egg', 'parmesan', 'cheese'] },
  { aisle: 'Pantry & dry', keys: ['flour', 'rice', 'bean', 'freekeh', 'noodle', 'oil', 'soy', 'vinegar', 'wine',
    'miso', 'mirin', 'sake', 'sugar', 'salt', 'spice', 'peppercorn', 'cumin', 'paprika', 'stock', 'tahini',
    'breadcrumb', 'honey', 'bicarb', 'baking', 'yeast', 'semolina', 'sesame', 'tin', 'oats', 'mustard'] },
];
function aisleFor(line) {
  const l = line.toLowerCase();
  for (const r of AISLE_RULES) if (r.keys.some((k) => l.includes(k))) return r.aisle;
  return 'Other';
}
const AISLE_ORDER = ['Fresh produce', 'Meat & seafood', 'Pantry & dry', 'Dairy & eggs', 'Other'];

// ── Woolworths order CTA — structured: logo tile · label+sub · price ──
function WoolworthsButton({ total, pending, full }) {
  const [hover, setHover] = React.useState(false);
  return (
    <button onClick={() => alert('Opening Woolworths — Luis fills your cart automatically.')}
      onMouseEnter={() => setHover(true)} onMouseLeave={() => setHover(false)}
      style={{ width: full ? '100%' : 'auto', display: 'flex', alignItems: 'center', gap: 14,
        padding: '12px 18px 12px 12px', borderRadius: 16, cursor: 'pointer', textAlign: 'left',
        border: '1px solid rgba(20,120,60,0.5)',
        background: 'linear-gradient(168deg, #1f9e4f 0%, #138a42 48%, #0c6f34 100%)',
        boxShadow: hover
          ? '0 14px 34px rgba(16,120,58,0.42), inset 0 1px 0 rgba(255,255,255,0.28)'
          : '0 8px 22px rgba(16,120,58,0.30), inset 0 1px 0 rgba(255,255,255,0.22)',
        transition: 'box-shadow .16s ease, transform .16s ease',
        transform: hover ? 'translateY(-1px)' : 'none' }}>
      {/* logo tile */}
      <span style={{ width: 40, height: 40, flexShrink: 0, borderRadius: 10, background: '#fff',
        display: 'inline-flex', alignItems: 'center', justifyContent: 'center',
        boxShadow: 'inset 0 0 0 1px rgba(0,0,0,0.06), 0 1px 2px rgba(0,0,0,0.18)' }}>
        <span style={{ fontFamily: 'Bricolage Grotesque', fontWeight: 800, fontSize: 22, lineHeight: 1,
          color: '#0e7d3c', letterSpacing: '-0.04em' }}>W</span>
      </span>
      {/* label */}
      <span style={{ display: 'flex', flexDirection: 'column', gap: 3, minWidth: 0, flex: full ? 1 : 'none' }}>
        <span style={{ fontFamily: 'Bricolage Grotesque', fontWeight: 600, fontSize: 16, lineHeight: 1.1,
          letterSpacing: '-0.01em', color: '#fff', whiteSpace: 'nowrap' }}>Order from Woolworths</span>
        <span style={{ fontFamily: 'Spectral', fontStyle: 'italic', fontSize: 12.5, lineHeight: 1.1,
          color: 'rgba(255,255,255,0.82)', whiteSpace: 'nowrap' }}>
          Luis fills your cart for you
        </span>
      </span>
      {/* price */}
      <span style={{ display: 'inline-flex', alignItems: 'center', gap: 14, flexShrink: 0,
        marginLeft: full ? 16 : 8 }}>
        <span style={{ width: 1, height: 30, background: 'rgba(255,255,255,0.24)', flexShrink: 0 }} />
        <span style={{ fontFamily: 'var(--mono)', fontWeight: 600, fontSize: 17, color: '#fff' }}>
          ${total.toFixed(2)}
        </span>
      </span>
    </button>
  );
}

// ── "Shop up to" date helpers (continuous dated plan) ──
const SHOP_DOW = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'];
const SHOP_MON = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
const shopPad = (n) => String(n).padStart(2, '0');
const shopIso = (d) => `${d.getFullYear()}-${shopPad(d.getMonth() + 1)}-${shopPad(d.getDate())}`;
const shopParse = (k) => { const [y, m, d] = (k || '').split('-').map(Number); return new Date(y, (m || 1) - 1, d || 1); };
const shopFmt = (k) => { const d = shopParse(k); return `${SHOP_DOW[d.getDay()]} ${d.getDate()} ${SHOP_MON[d.getMonth()]}`; };
const SHOP_CAL = 'M8 2v4M16 2v4M3 9h18M5 4h14a2 2 0 012 2v13a2 2 0 01-2 2H5a2 2 0 01-2-2V6a2 2 0 012-2z';
const ShopCal = ({ size = 14 }) => (
  <svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke="currentColor"
    strokeWidth="1.7" strokeLinecap="round" strokeLinejoin="round"><path d={SHOP_CAL} /></svg>
);

function buildList(shoppingRecipes, getRecipe) {
  const byAisle = {};
  shoppingRecipes.forEach((id) => {
    const r = getRecipe(id);
    if (!r) return;
    const short = r.name.split(' with ')[0];
    r.ingredients.forEach((line) => {
      if (!line || line.endsWith(':')) return;
      const aisle = aisleFor(line);
      (byAisle[aisle] = byAisle[aisle] || []).push({ key: id + '::' + line, name: line, for: short, recipeId: id });
    });
  });
  return AISLE_ORDER.filter((a) => byAisle[a]).map((a) => ({ aisle: a, items: byAisle[a] }));
}

function ShoppingScreen() {
  const { layout, state, getRecipe, toggleShopItem, removeRecipeFromShopping, openRecipe, setTab, WEEK_DAYS } = useApp();
  const isMobile = layout === 'mobile';
  const [filter, setFilter] = React.useState('everything');
  const [pendingOnly, setPendingOnly] = React.useState(false);
  const [fromOpen, setFromOpen] = React.useState(false);

  // The Groceries list reflects the plan LIVE, scoped to a "Shop up to" cutoff
  // date: every upcoming planned meal from today through the chosen date (not
  // skipped) contributes its ingredients, unioned with anything added manually
  // via "Add to shopping" (manual adds aren't date-bound). De-duped by recipe
  // id so a meal planned on several days is only counted once.
  const todayKey = (WEEK_DAYS[0] && WEEK_DAYS[0].key) || '0000-00-00';
  const endOfWeekKey = (WEEK_DAYS[6] && WEEK_DAYS[6].key) || todayKey;
  // upcoming planned meals (today onward), regardless of cutoff
  const plannedFuture = React.useMemo(() => Object.entries(state.plan || {})
    .filter(([k, e]) => e && !e.skip && e.recipeId && k >= todayKey)
    .map(([k, e]) => ({ key: k, id: e.recipeId })), [state.plan, todayKey]);
  const minKey = todayKey;
  const maxKey = plannedFuture.reduce((m, p) => (p.key > m ? p.key : m), todayKey);
  // default cutoff = end of the current week, clamped to the last planned meal
  const [cutoff, setCutoff] = React.useState(endOfWeekKey);
  const cutoffKey = cutoff > maxKey ? maxKey : (cutoff < minKey ? minKey : cutoff);
  const stepCutoff = (delta) => {
    const d = shopParse(cutoffKey); d.setDate(d.getDate() + delta);
    const k = shopIso(d);
    if (k < minKey || k > maxKey) return;
    setCutoff(k);
  };

  const manualIds = state.shoppingRecipes || [];
  const plannedWindowIds = plannedFuture.filter((p) => p.key <= cutoffKey).map((p) => p.id);
  const sourceIds = React.useMemo(() => [...new Set([...plannedWindowIds, ...manualIds])],
    [plannedWindowIds.join(','), manualIds.join(',')]);
  const hasAnySource = plannedFuture.length > 0 || manualIds.length > 0;

  const aisles = React.useMemo(() => buildList(sourceIds, getRecipe),
    [sourceIds, getRecipe]);
  const checked = new Set(state.shoppingChecked);
  const allItems = aisles.flatMap((a) => a.items);
  const pending = allItems.filter((it) => !checked.has(it.key)).length;
  // Consumption cost per ingredient line (the value used), keyed by "<id>::<line>",
  // sourced from each recipe's cost breakdown. The grocery total is the sum of
  // those fractions — labelled "ingredient value" (PRD v1 = consumption, not
  // pack-rounded purchase cost).
  const costByKey = React.useMemo(() => {
    const m = {};
    sourceIds.forEach((id) => {
      const r = getRecipe(id);
      (r && r.costBreakdown ? r.costBreakdown : []).forEach((b) => {
        if (b.status === 'section' || b.lineCost == null) return;
        m[id + '::' + b.line] = b.lineCost;
      });
    });
    return m;
  }, [sourceIds.join(','), state.recipes]);
  const estTotal = allItems.reduce((s, it) => s + (costByKey[it.key] || 0), 0);

  // "Shop up to" stepper control — used in the header (desktop right / mobile full)
  const stepBtnStyle = (disabled) => ({ width: 36, height: 36, borderRadius: 999, padding: 0,
    cursor: disabled ? 'default' : 'pointer', display: 'inline-flex', alignItems: 'center', justifyContent: 'center',
    background: disabled ? 'transparent' : 'rgba(255,255,255,0.04)', border: '1px solid var(--hairline)',
    color: disabled ? 'var(--ink-4)' : 'var(--ink-2)', opacity: disabled ? 0.45 : 1, flexShrink: 0 });
  const ShopUpTo = ({ full }) => (
    <div style={{ display: 'inline-flex', alignItems: 'center', gap: full ? 0 : 9,
      height: full ? undefined : 36, boxSizing: 'border-box',
      padding: full ? '8px 8px 8px 16px' : 0, borderRadius: 999,
      background: full ? 'rgba(255,255,255,0.04)' : 'transparent',
      border: full ? '1px solid var(--hairline)' : 'none', width: full ? '100%' : 'auto',
      justifyContent: full ? 'space-between' : 'flex-start' }}>
      <span style={{ display: 'inline-flex', alignItems: 'center', gap: 8, color: 'var(--ink-2)',
        fontFamily: 'Bricolage Grotesque', fontSize: 12.5, fontWeight: 600, letterSpacing: '0.02em', whiteSpace: 'nowrap' }}>
        <ShopCal size={14} />Shop up to
      </span>
      <span style={{ display: 'inline-flex', alignItems: 'center', gap: 4 }}>
        <button onClick={() => stepCutoff(-1)} disabled={cutoffKey <= minKey} style={stepBtnStyle(cutoffKey <= minKey)}
          aria-label="Earlier cutoff"><Icon.chevR size={16} style={{ transform: 'rotate(180deg)' }} /></button>
        <span style={{ minWidth: 92, textAlign: 'center', fontFamily: 'Bricolage Grotesque', fontSize: 13.5,
          fontWeight: 700, color: 'var(--ink)', letterSpacing: '-0.01em' }}>{shopFmt(cutoffKey)}</span>
        <button onClick={() => stepCutoff(1)} disabled={cutoffKey >= maxKey} style={stepBtnStyle(cutoffKey >= maxKey)}
          aria-label="Later cutoff"><Icon.chevR size={16} /></button>
      </span>
    </div>
  );

  const FILTERS = ['everything', ...AISLE_ORDER.filter((a) => aisles.find((x) => x.aisle === a)).map((a) => a.split(' ')[0].toLowerCase())];
  const visAisles = aisles.filter((a) => filter === 'everything' || a.aisle.split(' ')[0].toLowerCase() === filter);

  if (!hasAnySource) {
    return (
      <Shell tab="groceries">
        <div style={{ padding: isMobile ? '60px 24px' : '120px 48px', textAlign: 'center' }}>
          <h1 style={{ fontFamily: 'Bricolage Grotesque', fontWeight: 700, fontSize: isMobile ? 40 : 64,
            lineHeight: 0.95, letterSpacing: '-0.045em', color: 'var(--ink)', margin: 0 }}>
            Nothing on the
            <span style={{ fontFamily: 'Spectral', fontStyle: 'italic', fontWeight: 400, color: 'var(--olive)' }}> list yet.</span>
          </h1>
          <p style={{ fontFamily: 'Spectral', fontStyle: 'italic', fontSize: 18, color: 'var(--ink-3)',
            margin: '16px auto 28px', maxWidth: 460 }}>
            Open any recipe and tap <span style={{ color: 'var(--olive)' }}>Add to shopping</span> — or plan a few dinners and they'll show up here automatically.
          </p>
          <FButton size="l" onClick={() => setTab('recipes')}>Browse recipes →</FButton>
        </div>
      </Shell>
    );
  }

  return (
    <Shell tab="groceries">
      {/* Header */}
      <div style={{ padding: isMobile ? '24px 18px 14px' : '32px 48px 18px', display: 'flex',
        flexDirection: 'column', gap: isMobile ? 12 : 14 }}>
        <div style={{ display: 'flex', alignItems: 'flex-end', justifyContent: 'space-between',
          gap: 24, flexWrap: 'wrap' }}>
          <div>
            <span style={{ fontFamily: 'Bricolage Grotesque', fontSize: isMobile ? 10 : 11, fontWeight: 600,
              letterSpacing: '0.28em', textTransform: 'uppercase', color: 'var(--olive)' }}>
              Shopping list · from {sourceIds.length} {sourceIds.length === 1 ? 'recipe' : 'recipes'}
            </span>
            <h1 style={{ fontFamily: 'Bricolage Grotesque', fontWeight: 700, fontSize: isMobile ? 36 : 72,
              lineHeight: 0.92, letterSpacing: '-0.045em', color: 'var(--ink)', margin: '10px 0 0' }}>
              {allItems.length} items
              <span style={{ fontFamily: 'Spectral', fontStyle: 'italic', fontWeight: 400, color: 'var(--olive)' }}>
                {' '}across {aisles.length} aisles.</span>
            </h1>
          </div>
          {!isMobile && (
            <WoolworthsButton total={estTotal} pending={pending} />
          )}
        </div>

        {!isMobile && (
          <p style={{ fontFamily: 'Spectral', fontStyle: 'italic', fontSize: 17,
            color: 'var(--ink-2)', margin: 0, maxWidth: 560 }}>
            Items you already have are crossed off — tick the rest as you shop.
          </p>
        )}

        {isMobile && (
          <div style={{ display: 'flex', flexDirection: 'column', gap: 12 }}>
            <ShopUpTo full />
            <WoolworthsButton total={estTotal} pending={pending} full />
          </div>
        )}
      </div>

      {/* ── Controls ── */}
      {!isMobile ? (
        <>
          {/* Filter bar */}
          <div style={{ padding: '24px 48px 0', display: 'flex', alignItems: 'center',
            gap: 8, flexWrap: 'wrap' }}>
            {FILTERS.map((c) => (
              <button key={c} onClick={() => setFilter(c)} style={{ fontFamily: 'Bricolage Grotesque', fontSize: 12,
                fontWeight: 500, height: 36, boxSizing: 'border-box', padding: '0 11px', borderRadius: 999, cursor: 'pointer',
                textTransform: 'capitalize', display: 'inline-flex', alignItems: 'center', justifyContent: 'center',
                background: filter === c ? 'linear-gradient(180deg, rgba(255,255,255,0.12), rgba(255,255,255,0.03))' : 'transparent',
                border: filter === c ? '1px solid rgba(255,255,255,0.18)' : '1px solid var(--hairline)',
                color: filter === c ? 'var(--ink)' : 'var(--ink-3)' }}>{c}</button>
            ))}
            <button onClick={() => setPendingOnly((p) => !p)} style={{ fontFamily: 'Bricolage Grotesque',
              fontSize: 11, fontWeight: 500, height: 36, boxSizing: 'border-box', padding: '0 11px', borderRadius: 999,
              cursor: 'pointer', display: 'inline-flex', alignItems: 'center', justifyContent: 'center',
              background: pendingOnly ? 'rgba(240,168,80,0.14)' : 'transparent',
              border: '1px solid ' + (pendingOnly ? 'rgba(240,168,80,0.3)' : 'var(--hairline)'),
              color: pendingOnly ? 'var(--olive)' : 'var(--ink-3)' }}>
              {pendingOnly ? 'showing: to buy' : 'show: to buy only'}
            </button>
            <span style={{ flex: 1 }} />
            <ShopUpTo />
          </div>
        </>
      ) : (
        <div style={{ padding: '14px 18px 0', display: 'flex', flexDirection: 'column', gap: 12 }}>
          {/* progress + All/To-buy segmented */}
          <div style={{ display: 'flex', alignItems: 'center', gap: 12 }}>
            <span style={{ fontFamily: 'Spectral', fontStyle: 'italic', fontSize: 14, color: 'var(--ink-2)' }}>
              <strong style={{ fontFamily: 'Bricolage Grotesque', fontStyle: 'normal', fontWeight: 600,
                color: 'var(--ink)' }}>{pending}</strong> still to buy
            </span>
            <span style={{ flex: 1 }} />
            <div style={{ display: 'inline-flex', padding: 3, borderRadius: 999,
              background: 'rgba(255,255,255,0.04)', border: '1px solid var(--hairline)' }}>
              {[['all', 'All'], ['buy', 'To buy']].map(([v, label]) => {
                const on = (v === 'buy') === pendingOnly;
                return (
                  <button key={v} onClick={() => setPendingOnly(v === 'buy')} style={{
                    fontFamily: 'Bricolage Grotesque', fontSize: 12, fontWeight: 600, padding: '6px 16px',
                    borderRadius: 999, cursor: 'pointer', border: 'none',
                    background: on ? 'linear-gradient(180deg, rgba(240,168,80,0.92), rgba(217,135,40,0.92))' : 'transparent',
                    color: on ? '#1a1208' : 'var(--ink-3)' }}>{label}</button>
                );
              })}
            </div>
          </div>

          {/* aisle chips — single scrolling row */}
          <div className="no-scrollbar" style={{ display: 'flex', gap: 7, overflowX: 'auto', paddingBottom: 2 }}>
            {FILTERS.map((c) => (
              <button key={c} onClick={() => setFilter(c)} style={{ fontFamily: 'Bricolage Grotesque', fontSize: 12.5,
                fontWeight: 500, padding: '8px 14px', borderRadius: 999, cursor: 'pointer', textTransform: 'capitalize',
                flexShrink: 0, whiteSpace: 'nowrap',
                background: filter === c ? 'linear-gradient(180deg, rgba(255,255,255,0.12), rgba(255,255,255,0.03))' : 'transparent',
                border: filter === c ? '1px solid rgba(255,255,255,0.18)' : '1px solid var(--hairline)',
                color: filter === c ? 'var(--ink)' : 'var(--ink-3)' }}>{c}</button>
            ))}
          </div>
        </div>
      )}

      {/* Aisles */}
      <div style={{ padding: isMobile ? '24px 18px 28px' : '36px 48px 80px', display: 'grid',
        gridTemplateColumns: isMobile ? '1fr' : '1fr 1fr', gap: isMobile ? 16 : '24px 36px' }}>
        {allItems.length === 0 && (
          <div style={{ gridColumn: '1 / -1', padding: isMobile ? '40px 22px' : '56px 28px', textAlign: 'center',
            border: '1px dashed var(--hairline)', borderRadius: 16, background: 'rgba(255,255,255,0.015)' }}>
            <div style={{ fontFamily: 'Spectral', fontStyle: 'italic', fontSize: isMobile ? 17 : 19, color: 'var(--ink-2)' }}>
              No dinners planned through {shopFmt(cutoffKey)}.
            </div>
            <div style={{ fontFamily: 'Bricolage Grotesque', fontSize: 13.5, color: 'var(--ink-3)', marginTop: 8 }}>
              {cutoffKey < maxKey ? 'Nudge “Shop up to” later to pull more meals in.'
                : 'Plan a few dinners and they\u2019ll show up here.'}
            </div>
          </div>
        )}
        {visAisles.map((a) => {
          const items = pendingOnly ? a.items.filter((it) => !checked.has(it.key)) : a.items;
          if (!items.length) return null;
          return (
            <div key={a.aisle} style={{ padding: '20px 22px', background: 'rgba(255,255,255,0.03)',
              border: '1px solid var(--hairline)', borderRadius: 14, alignSelf: 'start' }}>
              <div style={{ display: 'flex', alignItems: 'center', gap: 10, marginBottom: 14 }}>
                <span style={{ fontFamily: 'Bricolage Grotesque', fontSize: 11, fontWeight: 600,
                  letterSpacing: '0.28em', textTransform: 'uppercase', color: 'var(--olive)' }}>{a.aisle}</span>
                <span style={{ flex: 1, height: 1, background: 'var(--hairline-2)' }} />
                <span style={{ fontFamily: 'var(--mono)', fontSize: 10, color: 'var(--ink-3)' }}>{items.length}</span>
              </div>
              <ul style={{ listStyle: 'none', padding: 0, margin: 0 }}>
                {items.map((it) => {
                  const has = checked.has(it.key);
                  return (
                    <li key={it.key}>
                      <label onClick={() => toggleShopItem(it.key)} style={{ display: 'flex', alignItems: 'flex-start',
                        gap: 12, padding: '8px 6px', cursor: 'pointer', borderRadius: 6, opacity: has ? 0.5 : 1 }}>
                        <span style={{ width: 20, height: 20, borderRadius: 4, marginTop: 1, flexShrink: 0,
                          border: has ? 'none' : '1.5px solid var(--ink-3)',
                          background: has ? 'linear-gradient(135deg, #f0a850, #c97818)' : 'transparent',
                          color: '#1a1208', display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
                          {has && <Icon.check size={12} stroke={3} />}
                        </span>
                        <div style={{ flex: 1, minWidth: 0 }}>
                          <span style={{ fontFamily: 'Spectral', fontSize: 16, lineHeight: 1.45,
                            color: has ? 'var(--ink-3)' : 'var(--ink)', textDecoration: has ? 'line-through' : 'none' }}>{it.name}</span>
                          <div style={{ fontFamily: 'Spectral', fontStyle: 'italic', fontSize: 12,
                            color: 'var(--olive)', marginTop: 2 }}>for {it.for}</div>
                        </div>
                        {costByKey[it.key] != null && (
                          <span style={{ fontFamily: 'var(--mono)', fontSize: 12, color: 'var(--ink-3)',
                            whiteSpace: 'nowrap', flexShrink: 0, marginTop: 1 }}>${costByKey[it.key].toFixed(2)}</span>
                        )}
                      </label>
                    </li>
                  );
                })}
              </ul>
            </div>
          );
        })}
      </div>
    </Shell>
  );
}

Object.assign(window, { ShoppingScreen });
