// Avokado Bar — Sipariş Sistemi v3 ortak veri katmanı (window.AvbOrd)
// Menü: Firestore menu_config/main (yoksa gömülü varsayılanlar)
// Siparişler: menu_orders koleksiyonu, no sayacı: menu_orders_meta/counter
// Firebase: shared.js'in global `db` / `auth` binding'leri (classic script scope)
(function(){
const { useState, useEffect, useRef } = React;

function fsdb(){ try { return (typeof db !== 'undefined' && db) ? db : null; } catch(_) { return null; } }
function fsauth(){ try { return (typeof auth !== 'undefined' && auth) ? auth : null; } catch(_) { return null; } }

/* ── Taban menü ──
   Gerçek veri app/menu-data.js dosyasında (order app'in canlı Firestore
   menüsünden üretildi: fiyat, açıklama, foto, alerjen, diyet etiketi, ekstra
   grupları ve istasyon). menu_config/main yayınlandıysa o kazanır. */
const DEFAULT_MENU = window.AvbMenuData || {
  categories: [], items: [], extraGroups: {}, badges: {}, allergens: {},
  areas: [{ id:'ic', tr:'İç Mekan', en:'Indoor' }, { id:'dis', tr:'Dış Mekan', en:'Outdoor' }],
  tables: [],
};

const TONES = {
  green:['#E9F2B8','#C8DC2E'], cream:['#F2EAD5','#E0D4B0'], yolk:['#F5E2A8','#DCB870'],
  smoke:['#D9D4C2','#938B72'], berry:['#E8C7D0','#B06478'], tomato:['#F0C8B0','#C97A5A'], oat:['#F0E6CC','#C9A86B'],
};

/* ── Hazırlayan istasyon (mutfak / bar) ──
   Her ürün ya mutfakta ya barda hazırlanır; bu ayar ürünün kendi kaydında
   tutulur (menu_config → items[].station) ve admin panelindeki ürün
   ayarlarından değiştirilir. Fiş bu alana göre ayrılır: bir siparişte hem
   mutfak hem bar ürünü varsa iki ayrı fiş basılır.
   Hiç ayarlanmamış ürünler için kategoriden makul bir başlangıç üretilir. */
const STATIONS = {
  mutfak: { id:'mutfak', label:'Mutfak', caps:'MUTFAK', bg:'rgba(212,133,28,0.12)', fg:'#B36F14' },
  bar:    { id:'bar',    label:'Bar',    caps:'BAR',    bg:'rgba(46,90,138,0.12)',  fg:'#2E5A8A' },
};
const STATION_IDS = ['mutfak', 'bar'];
const DRINK_CATS = ['cat_smoothies', 'cat_smoothie_bowls', 'cat_coffee', 'cat_cold_coffee', 'cat_cold_drinks', 'cat_hot_drinks'];
function defaultStation(catId){ return DRINK_CATS.includes(catId) ? 'bar' : 'mutfak'; }
// 'servis' eski addı — bar olarak okunur.
function normStation(s){ return s === 'servis' ? 'bar' : (STATION_IDS.includes(s) ? s : null); }
function stationMeta(id){ return STATIONS[normStation(id)] || STATIONS.mutfak; }
function withStations(items){
  return (items || []).map(it => {
    const s = normStation(it.station);
    return s === it.station ? it : { ...it, station: s || defaultStation(it.cat) };
  });
}
// Sipariş satırının istasyonu: satırda yazılıysa o, yoksa ürün kaydından bulunur.
function lineStation(menu, l){
  const own = l ? normStation(l.station) : null;
  if (own) return own;
  const items = (menu && menu.items) || [];
  let it = (l && l.itemId) ? items.find(i => i.id === l.itemId) : null;
  if (!it && l && l.name) it = items.find(i => i.tr && i.tr.n === l.name);
  const s = it ? normStation(it.station) : null;
  if (s) return s;
  return it ? defaultStation(it.cat) : 'mutfak';
}
// Siparişi istasyonlara böler → [{ id, meta, lines, total }]
function splitByStation(menu, order){
  const buckets = {};
  ((order && order.lines) || []).forEach(l => {
    const s = lineStation(menu, l);
    if (!buckets[s]) buckets[s] = [];
    buckets[s].push(l);
  });
  return STATION_IDS.filter(s => buckets[s] && buckets[s].length).map(s => ({
    id: s, meta: STATIONS[s], lines: buckets[s],
    total: buckets[s].reduce((a,l) => a + (Number(l.total) || 0), 0),
  }));
}

/* ── Karşılama ekranı görseli ──
   Müşteri ilk açılışta gördüğü sheet'in üst görseli. image boşsa marka logosu
   yeşil zeminde gösterilir. shape: 'square' (1:1) | 'wide' (geniş şerit). */
const ONBOARD_SHAPES = [
  { id:'wide',   label:'Geniş', note:'Tam genişlik şerit' },
  { id:'square', label:'Kare',  note:'1:1, ortalanmış' },
];
function onboardingOf(menu){
  const o = (menu && menu.onboarding) || {};
  return { image: o.image || null, shape: o.shape === 'square' ? 'square' : 'wide' };
}

/* ── Görünürlük (ürün ve kategori için ortak) ──
   İki bayrak, üç durum:  hidden → müşteri menüsünde yok,
                          staffHidden → garson panelinde de yok. */
const VISIBILITY = [
  { id:'all',   label:'Herkese açık',  chip:null,            note:'Müşteri menüsünde ve garson panelinde' },
  { id:'staff', label:'Sadece garson', chip:'Sadece garson', note:'Müşteri görmez — garson sipariş girebilir' },
  { id:'none',  label:'Kapalı',        chip:'Kapalı',        note:'Yalnız menü yönetiminde görünür' },
];
function visOf(x){ return (x && x.staffHidden) ? 'none' : ((x && x.hidden) ? 'staff' : 'all'); }
function setVis(x, v){ x.hidden = v !== 'all'; x.staffHidden = v === 'none'; }
function visMeta(id){ return VISIBILITY.find(v => v.id === id) || VISIBILITY[0]; }

/* ── Yardımcılar ── */
function deepClone(o){ return JSON.parse(JSON.stringify(o)); }
function defaults(){
  const d = deepClone(DEFAULT_MENU);
  d.items = withStations(d.items);
  d.onboarding = onboardingOf(d);
  return d;
}
function normalizeMenu(m){
  const d = defaults();
  if (!m || !Array.isArray(m.categories) || !Array.isArray(m.items) || !m.extraGroups) return d;
  return {
    categories: m.categories, items: withStations(m.items), extraGroups: m.extraGroups,
    badges: m.badges || d.badges, allergens: m.allergens || d.allergens,
    areas: m.areas || d.areas, tables: m.tables || d.tables,
    onboarding: onboardingOf(m),
  };
}
function fmt(n){ return '₺' + Math.round(Number(n) || 0); }
function timeAgo(t){
  const m = Math.floor((Date.now() - t) / 60000);
  if (m < 1) return 'Az önce';
  if (m < 60) return m + ' dk önce';
  return new Date(t).toLocaleTimeString('tr-TR', { hour:'2-digit', minute:'2-digit' });
}
function fmtWhen(t){ return new Date(t).toLocaleString('tr-TR', { day:'2-digit', month:'2-digit', hour:'2-digit', minute:'2-digit' }); }
function fmtClock(t){ return new Date(t).toLocaleTimeString('tr-TR', { hour:'2-digit', minute:'2-digit' }); }
const STATUS_META = {
  pending:   { label:'Bekliyor',      bg:'rgba(212,133,28,0.12)', fg:'#D4851C' },
  confirmed: { label:'Onaylandı',     bg:'rgba(46,138,74,0.12)',  fg:'#2E8A4A' },
  printed:   { label:'Yazdırıldı',    bg:'rgba(46,90,138,0.12)',  fg:'#2E5A8A' },
  delivered: { label:'Teslim edildi', bg:'rgba(26,26,26,0.07)',   fg:'#3D3D3D' },
  cancelled: { label:'İptal',         bg:'rgba(192,58,43,0.1)',   fg:'#C03A2B' },
};
function statusMeta(st){ return STATUS_META[st] || { label: st, bg:'rgba(26,26,26,0.07)', fg:'#808080' }; }
function tableLabel(menu, id, noneLabel){
  if (!id) return noneLabel || null;
  const t = (menu.tables || []).find(x => x.id === id);
  if (!t) return id;
  const a = (menu.areas || []).find(x => x.id === t.area);
  return (a ? a.tr : t.area) + ' · Masa ' + t.label;
}
function orderSummary(o){
  const lines = o.lines || [];
  return lines.slice(0,3).map(l => l.qty + '× ' + l.name).join(' · ') + (lines.length > 3 ? ' +' + (lines.length - 3) : '');
}
function makeQrUrl(no, id){
  try {
    if (!window.qrcode) return null;
    const q = window.qrcode(0, 'M');
    q.addData('AVB:' + no + ':' + id);
    q.make();
    return q.createDataURL(8, 12);
  } catch(e){ return null; }
}

/* ── Menü config: canlı okuma + yayınlama ── */
function useMenuConfig(){
  const [menu, setMenu] = useState(() => defaults());
  const [live, setLive] = useState(false);     // Firestore yanıt verdi mi
  const [exists, setExists] = useState(null);  // menu_config/main yayınlanmış mı
  useEffect(() => {
    const d = fsdb();
    if (!d) return;
    // onSnapshot → menü her yüzeyde canlı; admin yayınlar, saniyesinde yansır.
    const unsub = d.collection('menu_config').doc('main').onSnapshot(doc => {
      if (doc.exists) { setMenu(normalizeMenu(doc.data())); setExists(true); }
      else { setMenu(defaults()); setExists(false); }
      setLive(true);
    }, err => console.warn('[AvbOrd] menu_config:', err.message));
    return () => { try { unsub(); } catch(_){} };
  }, []);
  return { menu, live, exists };
}
/* ── Adisyo senkronu ──
   Zincir: Adisyo → (Cloud Function adisyoSyncProducts) → Firestore `menu`
   koleksiyonu → (buradaki birleştirme) → v3 menu_config.
   Birinci adım order app'teki "Adisyo ile eşle" düğmesinin çağırdığı
   fonksiyonun aynısıdır; `menu` koleksiyonu ortak.

   Birleştirmede ORDER APP'İN sahibi olduğu her şey birebir alınır: fiyat, ad,
   açıklama, alerjen, ekstra grupları + seçenek fiyatları (settings/extras) ve
   hangi üründe hangi ekstra grubunun açık olduğu.
   Yalnız v3'e özgü ayarlar korunur: istasyon, iki kademeli görünürlük, v3'ten
   yüklenen foto, editöryel rozetler (Popüler/Yeni), sıra ve kategori taşımaları.
   Silme yapılmaz — Adisyo'da olmayanlar yalnız raporlanır.
   Not: ekstra FİYATLARI Adisyo'dan `adisyoSyncExtraPrices` (order app tarafında
   token'lı HTTP uç noktası) ile settings/extras'a yazılır; v3 oradan okur. */
const ADISYO_DIET_MAP = { vegan:'vegan', vegetarian:'veg', gluten_free:'gf', dairy_free:'df', high_protein:'hp' };
const COLD_COFFEE_CAT = 'cat_cold_coffee';

async function runAdisyoSync(){
  if (!window.firebase || !firebase.functions) throw new Error('Functions SDK yüklenmedi');
  const fn = firebase.app().functions('us-central1').httpsCallable('adisyoSyncProducts');
  const res = await fn({});
  return (res && res.data) || {};
}

// Firestore'daki menu + settings'ten v3 şeklinde bir menü kurar
async function fetchSourceMenu(){
  const d = fsdb();
  if (!d) throw new Error('Firestore yok');
  const [menuSnap, catDoc, exDoc] = await Promise.all([
    d.collection('menu').get(),
    d.collection('settings').doc('categories').get(),
    d.collection('settings').doc('extras').get(),
  ]);

  const rawCats = (catDoc.exists && catDoc.data().list) || [];
  const categories = rawCats.map(c => ({
    id: c.id, sort: Number(c.sortOrder) || 99, hidden: !!c.hideFromCustomer,
    tr: c.nameTr || c.id, en: c.nameEn || c.nameTr || c.id,
  }));
  // Adisyo'nun "Soğuk Kahveler"i order app'te cat_coffee'ye eziliyor — ayır
  const hot = categories.find(c => c.id === 'cat_coffee');
  if (hot && !categories.some(c => c.id === COLD_COFFEE_CAT)) {
    hot.tr = 'Sıcak Kahveler'; hot.en = 'Hot Coffees';
    categories.push({ id: COLD_COFFEE_CAT, sort: hot.sort + 0.5, hidden: hot.hidden, tr:'Soğuk Kahveler', en:'Cold Coffees' });
  }
  categories.sort((a,b) => a.sort - b.sort).forEach((c,i) => { c.sort = i + 1; });
  const catIds = categories.map(c => c.id);

  const ex = (exDoc.exists && exDoc.data()) || {};
  const extraGroups = {};
  (ex.global || []).forEach(g => {
    extraGroups[g.id] = {
      id: g.id, tr: g.nameTr || g.id, en: g.nameEn || g.nameTr || g.id,
      type: g.selectionType === 'single' ? 'single' : 'multiple', required: !!g.isRequired,
      options: (g.options || []).map(o => ({ id:o.id, tr:o.nameTr || o.id, en:o.nameEn || o.nameTr || o.id, delta: Number(o.priceDelta) || 0 })),
    };
  });
  const itemExtras = ex.items || {};

  const items = menuSnap.docs.map(doc => {
    const f = doc.data() || {};
    let cat = f.categoryId;
    if (cat === 'cat_coffee' && String(f.adisyoCategoryName || '').trim() === 'Soğuk Kahveler') cat = COLD_COFFEE_CAT;
    if (catIds.indexOf(cat) < 0) cat = 'cat_extras';
    const nameTr = String(f.nameTr || '').trim();
    return {
      id: doc.id, cat, sort: Number(f.sortOrder) || 99, price: Number(f.price) || 0,
      photo: f.imageUrl || null,
      allergens: f.allergens || [],
      badges: (f.dietTags || []).map(t => ADISYO_DIET_MAP[t]).filter(Boolean),
      station: normStation(f.dest) || defaultStation(cat),
      soldOut: !!f.outOfStock,
      hidden: (f.active === false) || !!f.hideFromCustomer,
      staffHidden: f.active === false,
      extras: (itemExtras[doc.id] || []).filter(g => extraGroups[g]),
      tr: { n: nameTr, d: String(f.descTr || '').trim() },
      en: { n: String(f.nameEn || '').trim() || nameTr, d: String(f.descEn || '').trim() },
    };
  });
  // Kategori görünen adı Adisyo'nun kendi adından — settings/categories geride
  // kalabiliyor ("Smoothie" vs Adisyo "Smoothies"). Ürünler dağıtıldıktan sonra
  // hesaplanır ki sıcak/soğuk kahve ayrımı doğru isimlensin.
  const nameCount = {};
  menuSnap.docs.forEach((doc, i) => {
    const an = String((doc.data() || {}).adisyoCategoryName || '').trim();
    if (!an) return;
    const cid = items[i].cat;
    nameCount[cid] = nameCount[cid] || {};
    nameCount[cid][an] = (nameCount[cid][an] || 0) + 1;
  });
  categories.forEach(c => {
    const m = nameCount[c.id];
    if (!m) return;
    c.tr = Object.keys(m).sort((a,b) => m[b] - m[a])[0];
  });

  return { categories, items, extraGroups };
}

// draft'ı kaynağa göre günceller → { merged, report }
function mergeAdisyo(draft, source){
  const merged = deepClone(draft);
  const report = { added: [], priceChanged: [], renamed: [], missing: [], catsAdded: [],
                   remoteImages: 0, extraGroups: [], extraPrices: [], extraLinks: 0, catsRenamed: [], moved: [] };

  /* Ekstra grupları birebir kaynaktan — order app'te ne varsa o */
  Object.values(source.extraGroups).forEach(sg => {
    const cur = merged.extraGroups[sg.id];
    if (!cur) {
      merged.extraGroups[sg.id] = deepClone(sg);
      report.extraGroups.push('+ ' + sg.tr);
      return;
    }
    if (cur.tr !== sg.tr || cur.en !== sg.en || cur.type !== sg.type || !!cur.required !== !!sg.required) {
      report.extraGroups.push('~ ' + sg.tr);
    }
    (sg.options || []).forEach(so => {
      const co = (cur.options || []).find(o => o.id === so.id);
      if (!co) report.extraGroups.push('+ ' + sg.tr + ' · ' + so.tr);
      else if (Number(co.delta) !== Number(so.delta)) {
        report.extraPrices.push({ group: sg.tr, option: so.tr, from: Number(co.delta), to: Number(so.delta) });
      }
    });
    (cur.options || []).forEach(co => {
      if (!(sg.options || []).some(o => o.id === co.id)) report.extraGroups.push('− ' + sg.tr + ' · ' + co.tr);
    });
    merged.extraGroups[sg.id] = deepClone(sg);
  });
  // Kaynakta olmayan grup v3'te elle eklenmiş olabilir — silinmez, raporlanır
  Object.keys(merged.extraGroups).forEach(id => {
    if (!source.extraGroups[id]) report.extraGroups.push('yalnız v3: ' + (merged.extraGroups[id].tr || id));
  });

  source.categories.forEach(sc => {
    const cur = merged.categories.find(c => c.id === sc.id);
    if (!cur) {
      merged.categories.push(deepClone(sc));
      report.catsAdded.push(sc.tr);
      return;
    }
    // Kategori adı Adisyo'yu takip eder (sıra ve görünürlük v3'ün)
    if (cur.tr !== sc.tr) { report.catsRenamed.push(cur.tr + ' → ' + sc.tr); cur.tr = sc.tr; }
  });

  const byId = {};
  merged.items.forEach(it => { byId[it.id] = it; });

  source.items.forEach(si => {
    const cur = byId[si.id];
    if (!cur) {
      merged.items.push(deepClone(si));
      if (si.photo && /^https?:/.test(si.photo)) report.remoteImages++;
      report.added.push({ id: si.id, name: si.tr.n, price: si.price, cat: si.cat });
      return;
    }
    // Adisyo'nun alanları güncellenir
    if (Number(cur.price) !== Number(si.price)) {
      report.priceChanged.push({ name: si.tr.n, from: Number(cur.price), to: Number(si.price) });
      cur.price = si.price;
    }
    if (cur.tr.n !== si.tr.n && si.tr.n) {
      report.renamed.push({ from: cur.tr.n, to: si.tr.n });
      cur.tr.n = si.tr.n;
    }
    if (si.en.n) cur.en.n = si.en.n;
    if (si.tr.d) cur.tr.d = si.tr.d;
    if (si.en.d) cur.en.d = si.en.d;
    if (si.allergens && si.allergens.length) cur.allergens = si.allergens.slice();
    // Hangi üründe hangi ekstra grubu açık — order app'in settings/extras'ı esas
    const a = (cur.extras || []).slice().sort().join(',');
    const b = (si.extras || []).slice().sort().join(',');
    if (a !== b) { cur.extras = (si.extras || []).slice(); report.extraLinks++; }
    // Kategori de Adisyo'nun: soğuk kahve ayrımı gibi düzeltmeler yayılsın
    if (cur.cat !== si.cat) {
      const nm = (n) => { const c = merged.categories.find(x => x.id === n); return c ? c.tr : n; };
      report.moved.push(si.tr.n + ': ' + nm(cur.cat) + ' → ' + nm(si.cat));
      cur.cat = si.cat;
    }
    // istasyon / görünürlük / foto / rozet / sıra: v3'ün, dokunulmaz
  });

  const srcIds = {};
  source.items.forEach(si => { srcIds[si.id] = true; });
  merged.items.forEach(it => { if (!srcIds[it.id]) report.missing.push(it.tr.n); });

  return { merged, report };
}

/* ── Ürün görseli yükleme ──
   Tarayıcıda küçültüp WebP'e çevirip Storage'a atar. Kaynak dosya 5 MB'lık bir
   fotoğraf makinesi çıktısı olsa bile menüye ~40 KB'lık görsel düşer.
   Dosya adı "v3_" önekli — order app'in menu_images/<id>.<ext> orijinallerinin
   ÜZERİNE YAZMAZ. */
const IMG_MAX = 900, IMG_Q = 0.82;
function optimizeImage(file){
  return new Promise((resolve, reject) => {
    const fr = new FileReader();
    fr.onerror = () => reject(new Error('Dosya okunamadı'));
    fr.onload = () => {
      const img = new Image();
      img.onerror = () => reject(new Error('Görsel açılamadı'));
      img.onload = () => {
        let w = img.naturalWidth, h = img.naturalHeight;
        if (!w || !h) return reject(new Error('Görsel boyutu okunamadı'));
        if (w > IMG_MAX || h > IMG_MAX) {
          const s = IMG_MAX / Math.max(w, h);
          w = Math.round(w * s); h = Math.round(h * s);
        }
        const cv = document.createElement('canvas');
        cv.width = w; cv.height = h;
        const ctx = cv.getContext('2d');
        ctx.imageSmoothingQuality = 'high';
        ctx.drawImage(img, 0, 0, w, h);
        cv.toBlob(blob => {
          if (blob && blob.type === 'image/webp') resolve({ blob, ext:'webp', w, h });
          else cv.toBlob(b2 => b2 ? resolve({ blob:b2, ext:'jpg', w, h }) : reject(new Error('Dönüştürülemedi')), 'image/jpeg', IMG_Q);
        }, 'image/webp', IMG_Q);
      };
      img.src = fr.result;
    };
    fr.readAsDataURL(file);
  });
}
async function uploadItemImage(itemId, file){
  if (!file) throw new Error('Dosya seçilmedi');
  if (!/^image\//.test(file.type)) throw new Error('Yalnızca görsel dosyası yüklenebilir');
  if (!window.firebase || !firebase.storage) throw new Error('Storage yüklenmedi — sayfayı yenileyin');
  const opt = await optimizeImage(file);
  const ref = firebase.storage().ref('menu_images/v3_' + itemId + '.' + opt.ext);
  await ref.put(opt.blob, { contentType: opt.blob.type, cacheControl: 'public, max-age=604800' });
  const url = await ref.getDownloadURL();
  return { url, before: file.size, after: opt.blob.size, w: opt.w, h: opt.h };
}

async function publishMenu(draft){
  const d = fsdb();
  if (!d) throw new Error('Firestore yok');
  const payload = normalizeMenu(draft);
  payload.updatedAt = Date.now();
  await d.collection('menu_config').doc('main').set(payload);
}

/* ── Siparişler ── */
function useOrders(opts){
  const limitN = (opts && opts.limit) || 200;
  const [orders, setOrders] = useState([]);
  useEffect(() => {
    const d = fsdb();
    if (!d) return;
    const unsub = d.collection('menu_orders').orderBy('createdAt', 'desc').limit(limitN)
      .onSnapshot(snap => {
        setOrders(snap.docs.map(doc => ({ id: doc.id, ...doc.data() })));
      }, err => console.warn('[AvbOrd] orders:', err.message));
    return () => { try { unsub(); } catch(_){} };
  }, [limitN]);
  return orders;
}
function useOrderDoc(id){
  const [order, setOrder] = useState(null);
  useEffect(() => {
    if (!id) { setOrder(null); return; }
    const d = fsdb();
    if (!d) return;
    const unsub = d.collection('menu_orders').doc(id).onSnapshot(doc => {
      setOrder(doc.exists ? { id: doc.id, ...doc.data() } : null);
    }, () => {});
    return () => { try { unsub(); } catch(_){} };
  }, [id]);
  return order;
}
// opts: { status, tableId, note, createdBy, staffName }
// Müşteri çağrısı opts vermez → pending, masasız (varsayılan davranış korunur).
async function createOrder(lines, total, opts){
  const o = opts || {};
  const d = fsdb();
  if (!d) throw new Error('Firestore yok');
  const counterRef = d.collection('menu_orders_meta').doc('counter');
  const no = await d.runTransaction(async tx => {
    const doc = await tx.get(counterRef);
    const next = doc.exists ? (doc.data().next || 1042) : 1042;
    tx.set(counterRef, { next: next + 1 }, { merge: true });
    return next;
  });
  const status = o.status || 'pending';
  const order = {
    no,
    status,
    tableId: o.tableId || null,
    lines,
    total,
    note: o.note || '',
    createdBy: o.createdBy || 'customer',
    staffName: o.staffName || null,
    createdAt: Date.now(),
  };
  if (status === 'confirmed') order.confirmedAt = Date.now();
  const ref = await d.collection('menu_orders').add(order);
  return { id: ref.id, ...order };
}
async function patchOrder(id, patch){
  const d = fsdb();
  if (!d) throw new Error('Firestore yok');
  await d.collection('menu_orders').doc(id).update(patch);
}
/* Var olan siparişin içeriğini değiştirir (garson düzenlemesi).
   Yazdırılmış sipariş düzenlenirse tekrar "confirmed" olur — mutfak/servis
   eski fişle kalmasın diye yazdırma kuyruğuna yeniden düşer. */
async function reviseOrder(order, lines, total, opts){
  const o = opts || {};
  const patch = {
    lines, total,
    tableId: o.tableId || null,
    note: o.note || '',
    revision: (Number(order.revision) || 0) + 1,
    revisedAt: Date.now(),
    revisedBy: o.staffName || null,
  };
  if (order.status === 'printed') { patch.status = 'confirmed'; patch.confirmedAt = Date.now(); }
  await patchOrder(order.id, patch);
  return { ...order, ...patch };
}

/* ── Personel auth (WhatsApp OTP ile telefon girişi + rol) ──
   Rol iki kaynaktan gelir; firestore.rules'daki isAdmin() ile BİREBİR aynı mantık:
   1) users/{uid}.role
   2) sabit admin telefon listesi (bu numaraların users doc'unda rolü "customer"
      olsa bile kurallar onları admin sayar — panel de saymalı, yoksa kural izin
      verirken arayüz kapıda çeviriyor). */
const ADMIN_PHONES = ['+905379167391', '+905532991207', '+905076331387'];
function useStaffAuth(allowedRoles){
  // status: 'loading' | 'signedout' | 'denied' | 'ok' | 'nofirebase'
  const [state, setState] = useState({ status: 'loading', user: null, role: null });
  useEffect(() => {
    const a = fsauth();
    if (!a) { setState({ status: 'nofirebase', user: null, role: null }); return; }
    const unsub = a.onAuthStateChanged(async u => {
      if (!u) { setState({ status: 'signedout', user: null, role: null }); return; }
      let role = null, name = null;
      try {
        const d = fsdb();
        const snap = d ? await d.collection('users').doc(u.uid).get() : null;
        if (snap && snap.exists) { role = snap.data().role || null; name = snap.data().name || null; }
      } catch(_){}
      if (u.phoneNumber && ADMIN_PHONES.includes(u.phoneNumber)) role = 'admin';
      const ok = role && allowedRoles.includes(role);
      setState({ status: ok ? 'ok' : 'denied', user: { uid: u.uid, email: u.email, phone: u.phoneNumber, name }, role });
    });
    return () => { try { unsub(); } catch(_){} };
  }, []);
  const logout = () => { const a = fsauth(); if (a) a.signOut().catch(()=>{}); };
  return { ...state, logout };
}

window.AvbOrd = {
  DEFAULT_MENU, TONES, defaults, deepClone, normalizeMenu,
  fmt, timeAgo, fmtWhen, fmtClock, statusMeta, tableLabel, orderSummary, makeQrUrl,
  STATIONS, STATION_IDS, defaultStation, stationMeta, lineStation, splitByStation,
  VISIBILITY, visOf, setVis, visMeta,
  ONBOARD_SHAPES, onboardingOf,
  useMenuConfig, publishMenu, uploadItemImage,
  runAdisyoSync, fetchSourceMenu, mergeAdisyo,
  useOrders, useOrderDoc, createOrder, patchOrder, reviseOrder,
  useStaffAuth, fsdb,
};
})();
