// Avo XOX — personel tarafı: garson "Hediye kodu" ekranı + admin "XOX · Hediye kahve" sekmesi.
// window.AvbAvo = { GiftRedeem, AdminXox }
// Okuma: avo_config, avo_daily, avo_vouchers, avo_consents. Yazma (sunucuya istek): avo_redeems, avo_admin_req.
(function(){
const { useState, useEffect } = React;
const U = window.AvbOrdUI;
const O = window.AvbOrd;
const { INK, GREEN, HAIR, HAIR2 } = U;
const TZ = 'Europe/Istanbul';
const dayKey = (t) => new Intl.DateTimeFormat('en-CA', { timeZone:TZ, year:'numeric', month:'2-digit', day:'2-digit' }).format(t ? new Date(t) : new Date());
const saat = (t) => t ? new Intl.DateTimeFormat('tr-TR', { timeZone:TZ, hour:'2-digit', minute:'2-digit' }).format(new Date(t)) : '';
const gunTR = (k) => k ? k.split('-').reverse().join('.') : '';
const tarih = (t) => t ? gunTR(dayKey(t)) : '';
const tl = (n) => Math.round(Number(n) || 0).toLocaleString('tr-TR') + ' ₺';
const CAPS = { fontSize:11, fontWeight:700, letterSpacing:'0.08em', textTransform:'uppercase', color:'#808080', marginBottom:6 };
const INPUT = { height:40, padding:'0 12px', borderRadius:10, border:'1px solid ' + HAIR2, fontSize:15, color:INK, outline:'none', boxSizing:'border-box', background:'#FFFFFF' };
const CARD = { background:'#FFFFFF', borderRadius:16, border:'1px solid ' + HAIR, padding:16 };
const BTN = (on) => ({ height:40, padding:'0 16px', borderRadius:12, border:'none', background: on === false ? 'rgba(26,26,26,0.12)' : INK, color: on === false ? '#8A8A8A' : GREEN, fontSize:14, fontWeight:800, cursor: on === false ? 'default' : 'pointer' });
const BTN2 = { height:40, padding:'0 14px', borderRadius:12, border:'1px solid ' + HAIR2, background:'#FFFFFF', color:INK, fontSize:13.5, fontWeight:700, cursor:'pointer' };
const HATA = {
  not_found:'Bu kod bulunamadı. Harfleri kontrol edin.',
  already_redeemed:'Bu kod daha önce kullanılmış.',
  void:'Bu kod iptal edilmiş.',
  expired:'Kodun süresi geçmiş. Kod yalnız kazanıldığı gün geçerli.',
  weekly_used:'Bu telefon bu hafta hediye içeceğini zaten almış.',
  not_staff:'Bu işlem için personel girişi gerekli.',
  not_admin:'Bu işlem için admin girişi gerekli.',
  bad_drink:'Bu ürün hediye listesinde değil.',
  bad_phone:'Telefon 5 ile başlayan 10 hane olmalı.',
  cups_gone:'Bugünün bardakları bitti.',
  timeout:'Sunucu yanıt vermedi.',
};
const temizKod = (s) => String(s || '').toUpperCase().replace(/[^A-Z0-9]/g, '').slice(0, 5);
const durumEt = (v) => v.status === 'redeemed' ? { t:'Teslim edildi', c:'#2E8A4A', bg:'rgba(46,138,74,0.1)' }
  : v.status === 'void' ? { t:'İptal', c:'#A33325', bg:'rgba(192,58,43,0.08)' }
  : (v.status === 'expired' || v.day !== dayKey()) ? { t:'Süresi doldu', c:'#8A8A8A', bg:'rgba(26,26,26,0.05)' }
  : { t:'Bekliyor', c:'#3D4408', bg:'rgba(208,228,18,0.3)' };
// Oyun adresi: test sitesinde kendi /game'i, canlıda avokadobar.com/game
const GAME_URL = window.__AVB_DENEME ? '/game' : 'https://avokadobar.com/game';
const ben = () => { const u = window.auth && window.auth.currentUser; return { by: u ? u.uid : null, staffUid: u ? u.uid : null, test: !!(window.__AVB_DENEME && u && u.isAnonymous) }; };
// Sunucuya istek bırak, cevabı bekle (en çok 25 sn)
function istek(col, body){
  return new Promise((ok, no) => {
    window.db.collection(col).add({ ...body, ...ben(), createdAt: Date.now() }).then(ref => {
      let un = null;
      const t = setTimeout(() => { if (un) un(); no(new Error('timeout')); }, 25000);
      un = ref.onSnapshot(s => { const d = s.data() || {}; if (d.status === 'done' || d.status === 'ok' || d.status === 'error') { clearTimeout(t); un(); ok(d); } }, (e) => { clearTimeout(t); no(e); });
    }).catch(no);
  });
}
const hataMetni = (d) => (d && HATA[d.error]) || 'Bir sorun oldu, tekrar deneyin.';
const odulListesi = (menu) => ((menu && menu.items) || []).filter(i => i.avoPrize);
const ad = (it) => (it.tr && it.tr.n) || (it.en && it.en.n) || it.id;
function csvIndir(dosya, metin, bomsuz){
  const b = new Blob([(bomsuz ? '' : '\uFEFF') + metin], { type:'text/csv;charset=utf-8' });
  const a = document.createElement('a'); a.href = URL.createObjectURL(b); a.download = dosya; document.body.appendChild(a); a.click();
  setTimeout(() => { URL.revokeObjectURL(a.href); a.remove(); }, 500);
}

/* ════ GARSON: hediye kodu ════ */
function GiftRedeem({ initialCode, onScan }){
  const { menu } = O.useMenuConfig();
  const [kod, setKod] = useState('');
  const [v, setV] = useState(null);
  const [durum, setDurum] = useState(null);
  const [busy, setBusy] = useState(false);
  const [bugun, setBugun] = useState(null);
  const [liste, setListe] = useState([]);
  const [swap, setSwap] = useState('');

  useEffect(() => window.db.doc('avo_daily/' + dayKey()).onSnapshot(s => setBugun(s.exists ? s.data() : {}), () => {}), []);
  useEffect(() => window.db.collection('avo_vouchers').where('day', '==', dayKey()).onSnapshot(s => {
    setListe(s.docs.map(x => x.data()).filter(x => x.status === 'redeemed').sort((a,b) => (b.redeemedAt||0) - (a.redeemedAt||0)));
  }, () => {}), []);

  const bul = async (k0) => {
    const k = temizKod(k0 != null ? k0 : kod);
    setDurum(null); setV(null); setSwap('');
    if (k.length !== 5) { setDurum({ ok:false, text:'Kod 5 karakter olmalı.' }); return; }
    setBusy(true);
    try {
      const s = await window.db.doc('avo_vouchers/' + k).get();
      if (!s.exists) setDurum({ ok:false, text:HATA.not_found }); else setV(s.data());
    } catch(e) { setDurum({ ok:false, text:'Okunamadı: ' + ((e && e.message) || 'bağlantı') }); }
    setBusy(false);
  };
  useEffect(() => { if (initialCode) { const k = initialCode.split('#')[0]; setKod(k); bul(k); } }, [initialCode]);

  const teslim = async () => {
    if (!v || busy) return;
    setBusy(true); setDurum(null);
    try {
      const d = await istek('avo_redeems', { code: v.code, ...(swap ? { swapDrinkId: swap } : {}) });
      if (d.status === 'ok') {
        setV(x => ({ ...x, status:'redeemed', redeemedAt: Date.now(), drinkNameTr: d.drinkNameTr }));
        setDurum({ ok:true, text:'Teslim edildi: ' + (d.drinkNameTr || d.drinkName) + (d.firstName ? ' · ' + d.firstName : '') });
      } else {
        const ek = d.error === 'already_redeemed' && d.info ? ' (' + (d.info.by || 'personel') + ', ' + saat(d.info.at) + ')' : '';
        setDurum({ ok:false, text: hataMetni(d) + ek });
      }
    } catch(e) { setDurum({ ok:false, text: hataMetni({ error: e && e.message }) }); }
    setBusy(false);
  };

  const hazir = v && v.status === 'active' && v.day === dayKey();
  const du = v ? durumEt(v) : null;
  const odul = odulListesi(menu);
  return (
    <div style={{ padding:'14px 16px 40px', display:'flex', flexDirection:'column', gap:12 }}>
      <div style={CARD}>
        <div style={CAPS}>Hediye kodu</div>
        <div style={{ fontSize:13.5, color:'#6E6E6E', lineHeight:1.5, marginBottom:12 }}>Müşterinin telefonundaki 5 harfli kodu yazın ya da karekodu okutun.</div>
        <div style={{ display:'flex', gap:8 }}>
          <input value={kod} onChange={e => { setKod(temizKod(e.target.value)); setV(null); setDurum(null); }} onKeyDown={e => { if (e.key === 'Enter') bul(); }}
            placeholder="K7HAT" autoCapitalize="characters" autoCorrect="off" spellCheck={false}
            style={{ ...INPUT, flex:1, minWidth:0, height:54, fontSize:26, fontWeight:800, letterSpacing:'0.2em', textAlign:'center' }} />
          <button onClick={() => bul()} disabled={busy} className="avb3-press" style={{ ...BTN(), height:54 }}>Kontrol et</button>
        </div>
        {onScan && (
          <button onClick={onScan} className="avb3-press" style={{ ...BTN2, width:'100%', marginTop:8, height:46 }}>Karekod okut</button>
        )}
      </div>

      {v && (
        <div style={{ ...CARD, border:(hazir ? 2 : 1) + 'px solid ' + (hazir ? INK : HAIR2) }}>
          <div style={{ display:'flex', justifyContent:'space-between', alignItems:'center', marginBottom:10 }}>
            <span style={{ fontSize:22, fontWeight:900, letterSpacing:'0.16em', color:INK }}>{v.code}</span>
            <span style={{ padding:'4px 10px', borderRadius:999, background:du.bg, color:du.c, fontSize:12.5, fontWeight:800 }}>{du.t}</span>
          </div>
          <div style={{ fontSize:26, fontWeight:800, color:INK, lineHeight:1.15 }}>{v.drinkNameTr || v.drinkName}</div>
          <div style={{ fontSize:14, color:'#6E6E6E', marginTop:6, lineHeight:1.5 }}>
            {v.firstName} · {gunTR(v.day)} {saat(v.createdAt)}
            {v.status === 'redeemed' && <><br />Teslim: {v.redeemedByName || 'personel'} · {saat(v.redeemedAt)}</>}
            {v.status === 'void' && v.voidReason && <><br />İptal sebebi: {v.voidReason}</>}
          </div>
          {hazir && odul.length > 1 && (
            <label style={{ display:'block', marginTop:12 }}>
              <div style={CAPS}>İçecek yoksa değiştir</div>
              <select value={swap} onChange={e => setSwap(e.target.value)} style={{ ...INPUT, width:'100%' }}>
                <option value="">{v.drinkNameTr || v.drinkName} (seçilen)</option>
                {odul.filter(i => i.id !== v.drinkId).map(i => <option key={i.id} value={i.id}>{ad(i)}{i.soldOut ? ' (tükendi)' : ''}</option>)}
              </select>
            </label>
          )}
          {hazir && (
            <button onClick={teslim} disabled={busy} className="avb3-press"
              style={{ ...BTN(), width:'100%', height:56, marginTop:14, fontSize:16, opacity: busy ? 0.6 : 1 }}>
              {busy ? 'İşleniyor…' : 'Teslim edildi'}
            </button>
          )}
        </div>
      )}

      {durum && (
        <div style={{ padding:'12px 14px', borderRadius:12, fontSize:14, fontWeight:700, lineHeight:1.45,
          background: durum.ok ? 'rgba(46,138,74,0.1)' : 'rgba(192,58,43,0.08)', color: durum.ok ? '#2E8A4A' : '#A33325' }}>{durum.text}</div>
      )}

      <div style={CARD}>
        <div style={CAPS}>Bugün teslim edilenler · {bugun ? (bugun.redeemed || 0) : '–'} / {bugun ? (bugun.issued || 0) : '–'} kod</div>
        {!liste.length && <div style={{ fontSize:13.5, color:'#8A8A8A' }}>Henüz yok.</div>}
        {liste.slice(0, 20).map(k => (
          <div key={k.code} style={{ display:'flex', gap:10, padding:'8px 0', borderTop:'1px solid ' + HAIR, fontSize:13.5 }}>
            <span style={{ fontWeight:800, letterSpacing:'0.1em', width:64 }}>{k.code}</span>
            <span style={{ flex:1, minWidth:0 }}>{k.drinkNameTr || k.drinkName} · {k.firstName}</span>
            <span style={{ color:'#8A8A8A' }}>{saat(k.redeemedAt)} {k.redeemedByName || ''}</span>
          </div>
        ))}
      </div>
    </div>
  );
}

/* ════ ADMİN: XOX sekmesi ════ */
const ALT = [['bugun','Bugün'], ['takvim','Takvim'], ['kodlar','Kodlar'], ['musteri','Müşteriler'], ['izin','İzinler (İYS)'], ['rapor','Raporlar'], ['ayar','Ayarlar']];
function AdminXox({ d, mut }){
  const [alt, setAlt] = useState('bugun');
  const [cfg, setCfg] = useState(null);
  const [gunler, setGunler] = useState([]);
  const [kuponlar, setKuponlar] = useState([]);
  useEffect(() => window.db.doc('avo_config/main').onSnapshot(s => {
    setCfg(Object.assign({ enabled:true, dailyCups:5, openTime:'08:00', closeTime:'22:00', summary:false, floatOn:true, eveningOn:true, eveningFrom:'19:30', eveningStart:90, eveningFloor:75 }, s.exists ? s.data() : {}));
  }, () => {}), []);
  useEffect(() => {
    const keys = Array.from({ length:30 }, (_, i) => dayKey(Date.now() - i * 864e5));
    return window.db.collection('avo_daily').where('day', '>=', keys[29]).onSnapshot(s => {
      const m = {}; s.docs.forEach(x => { m[x.id] = x.data(); });
      setGunler(keys.map(k => ({ day:k, ...(m[k] || {}) })));
    }, () => {});
  }, []);
  useEffect(() => window.db.collection('avo_vouchers').where('day', '>=', dayKey(Date.now() - 29 * 864e5)).onSnapshot(s => {
    setKuponlar(s.docs.map(x => x.data()).sort((a,b) => (b.createdAt||0) - (a.createdAt||0)));
  }, () => {}), []);

  return (
    <div style={{ display:'flex', flexDirection:'column', gap:14, padding:'4px 0 60px' }}>
      <div className="avb3-noscroll" style={{ display:'flex', gap:6, overflowX:'auto', paddingBottom:2 }}>
        {ALT.map(([id, t]) => (
          <button key={id} onClick={() => setAlt(id)} style={{ height:34, padding:'0 13px', borderRadius:999, border:'1px solid ' + (alt === id ? INK : HAIR2), background: alt === id ? INK : '#FFFFFF', color: alt === id ? GREEN : '#3D3D3D', fontSize:13, fontWeight:700, cursor:'pointer', whiteSpace:'nowrap', flexShrink:0 }}>{t}</button>
        ))}
      </div>
      {alt === 'bugun' && <Bugun cfg={cfg} gun={gunler[0] || {}} kuponlar={kuponlar.filter(k => k.day === dayKey())} />}
      {alt === 'takvim' && <Takvim cfg={cfg} d={d} />}
      {alt === 'kodlar' && <Kodlar kuponlar={kuponlar} />}
      {alt === 'musteri' && <Musteriler />}
      {alt === 'izin' && <Izinler />}
      {alt === 'rapor' && <Raporlar gunler={gunler} kuponlar={kuponlar} />}
      {alt === 'ayar' && <Ayarlar cfg={cfg} d={d} mut={mut} />}
    </div>
  );
}

function Sayi({ items }){
  return (
    <div style={{ display:'grid', gridTemplateColumns:'repeat(' + Math.min(items.length, 3) + ',1fr)', gap:10 }}>
      {items.map(([t, v]) => (
        <div key={t} style={{ ...CARD, padding:14 }}>
          <div style={{ fontSize:24, fontWeight:900, color:INK, fontVariantNumeric:'tabular-nums' }}>{v}</div>
          <div style={{ fontSize:12, color:'#808080', fontWeight:600, marginTop:2 }}>{t}</div>
        </div>
      ))}
    </div>
  );
}
function KodSatir({ k, onVoid }){
  const du = durumEt(k);
  return (
    <div style={{ display:'flex', alignItems:'center', gap:10, padding:'10px 0', borderTop:'1px solid ' + HAIR, flexWrap:'wrap' }}>
      <span style={{ fontSize:15, fontWeight:900, letterSpacing:'0.12em', width:70 }}>{k.code}</span>
      <span style={{ flex:1, minWidth:160, fontSize:14, color:INK }}>{k.drinkNameTr || k.drinkName}{k.swappedFrom ? ' (önce: ' + k.swappedFrom + ')' : ''}
        <span style={{ color:'#8A8A8A' }}> · {k.firstName} · {gunTR(k.day)} {saat(k.createdAt)}{k.manual ? ' · elle' : ''}{k.redeemedByName ? ' · ' + k.redeemedByName + ' ' + saat(k.redeemedAt) : ''}</span></span>
      <span style={{ padding:'3px 9px', borderRadius:999, background:du.bg, color:du.c, fontSize:12, fontWeight:800 }}>{du.t}</span>
      {onVoid && (k.status === 'active' || k.status === 'redeemed') && <button onClick={() => onVoid(k)} style={{ border:'none', background:'transparent', color:'#A33325', fontSize:12.5, fontWeight:700, cursor:'pointer' }}>İptal</button>}
    </div>
  );
}
async function iptalEt(k){
  const reason = window.prompt(k.code + ' iptal sebebi (örn. yanlış teslim):', '');
  if (reason == null) return;
  const refund = window.confirm('Bardak bugünkü sayıya iade edilsin mi? (Tamam = iade et)');
  try { const r = await istek('avo_admin_req', { type:'void', code:k.code, reason, refund }); if (r.status !== 'done') window.alert(hataMetni(r)); }
  catch(e) { window.alert(hataMetni({ error:e && e.message })); }
}

function Bugun({ cfg, gun, kuponlar }){
  const oz = cfg ? gunOzet(cfg, dayKey()) : null;
  const kalan = oz ? Math.max(0, (oz.cups || 0) - (gun.issued || 0)) : '–';
  return (
    <>
      {cfg && !cfg.enabled && <div style={{ ...CARD, background:'rgba(192,58,43,0.06)', color:'#A33325', fontWeight:700, fontSize:14 }}>Hediye kahve şu an kapalı (Ayarlar).</div>}
      {oz && !oz.def && <div style={{ ...CARD, background: oz.prize ? GREEN : '#FFFFFF', fontWeight:800, fontSize:14.5 }}>Bugün takvimde: {oz.t}{oz.prize && oz.items ? ' · kazanan şunlardan seçer: ' + oz.items.length + ' ürün' : ''}</div>}
      <Sayi items={[['Kalan', kalan + ' / ' + (oz ? oz.cups : '–')], ['Verilen kod', gun.issued || 0], ['Teslim edilen', gun.redeemed || 0]]} />
      <Sayi items={[['Oynanan (Avo)', gun.games || 0], ['7x7 oyun', gun.games7 || 0], ['7x7 kazanan', gun.wins7 || 0]]} />
      <div style={CARD}>
        <div style={CAPS}>Bugünkü kodlar</div>
        {!kuponlar.length && <div style={{ fontSize:13.5, color:'#8A8A8A' }}>Bugün henüz kod verilmedi.</div>}
        {kuponlar.map(k => <KodSatir key={k.code} k={k} onVoid={iptalEt} />)}
      </div>
      <ElleKod />
    </>
  );
}

function ElleKod(){
  const { menu } = O.useMenuConfig();
  const [acik, setAcik] = useState(false);
  const [f, setF] = useState({ name:'', phone:'', drinkId:'' });
  const [msg, setMsg] = useState(null);
  const [busy, setBusy] = useState(false);
  const odul = odulListesi(menu);
  const ver = async () => {
    setBusy(true); setMsg(null);
    try { const r = await istek('avo_admin_req', { type:'manual_issue', ...f }); setMsg(r.status === 'done' ? { ok:true, t:'Kod: ' + r.code + (r.reused ? ' (bugün zaten vardı)' : '') } : { ok:false, t:hataMetni(r) }); }
    catch(e) { setMsg({ ok:false, t:hataMetni({ error:e && e.message }) }); }
    setBusy(false);
  };
  if (!acik) return <button onClick={() => setAcik(true)} style={{ ...BTN2, alignSelf:'flex-start' }}>Elle kod ver (WhatsApp'ı olmayan misafir)</button>;
  const tamam = !busy && f.drinkId && f.phone;
  return (
    <div style={CARD}>
      <div style={CAPS}>Elle kod ver</div>
      <div style={{ fontSize:12.5, color:'#808080', lineHeight:1.5, marginBottom:10 }}>WhatsApp doğrulaması ve ticari ileti izni olmadan verilir; raporda "elle" diye görünür. Haftalık sınır yine işler, günlük bardak sınırı işlemez.</div>
      <div style={{ display:'flex', gap:8, flexWrap:'wrap' }}>
        <input placeholder="Ad" value={f.name} onChange={e => setF({ ...f, name:e.target.value })} style={{ ...INPUT, width:130 }} />
        <input placeholder="5xx xxx xx xx" inputMode="tel" value={f.phone} onChange={e => setF({ ...f, phone:e.target.value })} style={{ ...INPUT, width:160 }} />
        <select value={f.drinkId} onChange={e => setF({ ...f, drinkId:e.target.value })} style={{ ...INPUT, minWidth:160 }}>
          <option value="">İçecek seçin</option>
          {odul.map(i => <option key={i.id} value={i.id}>{ad(i)}</option>)}
        </select>
        <button onClick={ver} disabled={!tamam} style={BTN(!!tamam)}>{busy ? '…' : 'Kod ver'}</button>
      </div>
      {msg && <div style={{ marginTop:10, fontSize:14, fontWeight:800, color: msg.ok ? '#2E8A4A' : '#A33325' }}>{msg.t}</div>}
    </div>
  );
}

function Kodlar({ kuponlar }){
  const [q, setQ] = useState('');
  const [st, setSt] = useState('all');
  const qq = q.trim().toLocaleLowerCase('tr');
  const durumUyar = (k) => st === 'all' || (st === 'active' && durumEt(k).t === 'Bekliyor') || (st === 'redeemed' && k.status === 'redeemed') || (st === 'void' && k.status === 'void') || (st === 'expired' && durumEt(k).t === 'Süresi doldu');
  const list = kuponlar.filter(k => durumUyar(k)
    && (!qq || (k.code || '').toLowerCase().includes(qq) || (k.firstName || '').toLocaleLowerCase('tr').includes(qq) || (k.drinkNameTr || '').toLocaleLowerCase('tr').includes(qq)));
  const csv = () => csvIndir('avo-kodlar.csv', ['kod;gun;saat;kahve;isim;durum;teslim_eden;teslim_saati;elle'].concat(list.map(k => [k.code, gunTR(k.day), saat(k.createdAt), k.drinkNameTr || k.drinkName, k.firstName, durumEt(k).t, k.redeemedByName || '', saat(k.redeemedAt), k.manual ? 'evet' : ''].join(';'))).join('\n'));
  return (
    <div style={CARD}>
      <div style={{ display:'flex', gap:8, flexWrap:'wrap', marginBottom:8 }}>
        <input placeholder="Kod, isim veya içecek ara" value={q} onChange={e => setQ(e.target.value)} style={{ ...INPUT, flex:1, minWidth:180 }} />
        <select value={st} onChange={e => setSt(e.target.value)} style={INPUT}>
          <option value="all">Tümü (30 gün)</option><option value="active">Bekleyen</option><option value="redeemed">Teslim edilen</option><option value="expired">Süresi dolan</option><option value="void">İptal</option>
        </select>
        <button onClick={csv} style={BTN2}>CSV</button>
      </div>
      <div style={{ fontSize:12.5, color:'#808080', marginBottom:4 }}>{list.length} kod</div>
      {list.map(k => <KodSatir key={k.code} k={k} onVoid={iptalEt} />)}
    </div>
  );
}

function Musteriler(){
  const [rows, setRows] = useState(null);
  const [busy, setBusy] = useState(false);
  const [err, setErr] = useState(null);
  const [q, setQ] = useState('');
  const yukle = async () => {
    setBusy(true); setErr(null);
    try { const r = await istek('avo_admin_req', { type:'customers' }); if (r.status === 'done') setRows(r.rows || []); else setErr(hataMetni(r)); }
    catch(e) { setErr(hataMetni({ error:e && e.message })); }
    setBusy(false);
  };
  const sil = async (r) => {
    if (!window.confirm((r.name || 'Bu kişi') + ' silinsin mi? Ad, telefon ve e-posta silinir, ileti izni kapanır (RET). İzin kanıtı yasal süre (3 yıl) kilitli kalır.')) return;
    try { const x = await istek('avo_admin_req', { type:'delete', phoneHash:r.phoneHash }); if (x.status === 'done') yukle(); else window.alert(hataMetni(x)); } catch(e) { window.alert(hataMetni({ error:e && e.message })); }
  };
  const qq = q.trim().toLocaleLowerCase('tr'), qd = qq.replace(/\D/g, '');
  const list = (rows || []).filter(r => !qq || (r.name || '').toLocaleLowerCase('tr').includes(qq) || (qd && (r.phone || '').includes(qd)) || (r.email || '').toLowerCase().includes(qq));
  const csv = () => csvIndir('avo-musteriler.csv', ['ad;telefon;eposta;whatsapp;sms;eposta_izni;durum;ilk_izin;son_izin;hediye;icilen;son_teslim'].concat(list.map(r => [r.name || '', r.phone || '', r.email || '', r.channels.wa ? 'evet' : '', r.channels.sms ? 'evet' : '', r.channels.email ? 'evet' : '', r.status === 'active' ? 'izinli' : 'RET', tarih(r.firstConsentAt), tarih(r.lastConsentAt), r.gifts, r.redeemed, tarih(r.lastRedeemedAt)].join(';'))).join('\n'));
  return (
    <div style={CARD}>
      <div style={CAPS}>Müşteriler</div>
      <div style={{ fontSize:12.5, color:'#808080', lineHeight:1.5, marginBottom:10 }}>Bilgiler şifreli saklanır; listeyi her açışınız erişim günlüğüne yazılır. Garson bu ekranı göremez.</div>
      {!rows && <button onClick={yukle} disabled={busy} style={BTN(!busy)}>{busy ? 'Açılıyor…' : 'Listeyi aç'}</button>}
      {err && <div style={{ color:'#A33325', fontWeight:700, fontSize:13.5, marginTop:8 }}>{err}</div>}
      {rows && (
        <>
          <div style={{ display:'flex', gap:8, flexWrap:'wrap', margin:'4px 0 8px' }}>
            <input placeholder="İsim, telefon, e-posta" value={q} onChange={e => setQ(e.target.value)} style={{ ...INPUT, flex:1, minWidth:180 }} />
            <button onClick={csv} style={BTN2}>CSV indir</button>
            <button onClick={yukle} style={BTN2}>Yenile</button>
          </div>
          <div style={{ fontSize:12.5, color:'#808080', marginBottom:4 }}>{list.length} kişi · {list.filter(r => r.redeemed >= 2).length} kişi 2+ kez geldi</div>
          {list.map(r => (
            <div key={r.phoneHash} style={{ display:'flex', alignItems:'center', gap:10, padding:'10px 0', borderTop:'1px solid ' + HAIR, flexWrap:'wrap', fontSize:14 }}>
              <span style={{ fontWeight:800, minWidth:110 }}>{r.name || '(silindi)'}</span>
              <span style={{ fontVariantNumeric:'tabular-nums', minWidth:130 }}>{r.phone || '—'}</span>
              <span style={{ flex:1, minWidth:140, color:'#6E6E6E' }}>{r.email || ''}</span>
              <span style={{ color: r.status === 'active' ? '#2E8A4A' : '#A33325', fontWeight:700 }}>{r.status === 'active' ? 'İzinli' : 'RET'}</span>
              <span style={{ color:'#8A8A8A' }}>{r.redeemed} kahve · son {tarih(r.lastRedeemedAt) || '—'}</span>
              {r.phone && <button onClick={() => sil(r)} style={{ border:'none', background:'transparent', color:'#A33325', fontSize:12.5, fontWeight:700, cursor:'pointer' }}>Sil</button>}
            </div>
          ))}
        </>
      )}
    </div>
  );
}

function Izinler(){
  const [list, setList] = useState(null);
  const [son, setSon] = useState(null);
  const [busy, setBusy] = useState(false);
  const [msg, setMsg] = useState(null);
  useEffect(() => window.db.collection('avo_consents').orderBy('lastConsentAt', 'desc').limit(200).onSnapshot(s => setList(s.docs.map(x => x.data())), () => setList([])), []);
  const bekleyen = (list || []).filter(z => z.iys && z.iys.uploaded === false);
  const indir = async (all) => {
    setBusy(true); setMsg(null);
    try {
      const r = await istek('avo_admin_req', { type:'iys_csv', all: !!all });
      if (r.status !== 'done') setMsg(hataMetni(r));
      else {
        // İYS paneli bir dosyadan ilk 50 izni alır: 50'şerlik dosyalara böl.
        const L = r.lines || [], parca = Math.max(1, Math.ceil(L.length / 50));
        for (let i = 0; i < parca; i++) {
          setTimeout(() => csvIndir('iys-' + dayKey() + (all ? '-tum' : '') + (parca > 1 ? '-' + (i + 1) : '') + '.csv', [r.head].concat(L.slice(i * 50, i * 50 + 50)).join('\n') + '\n', true), i * 400);
        }
        if (parca > 1) setMsg(parca + ' dosya indirildi (her biri en çok 50 izin). Hepsini ayrı ayrı yükleyin.');
        if (!all) setSon({ hashes:r.hashes || [] });
      }
    } catch(e) { setMsg(hataMetni({ error:e && e.message })); }
    setBusy(false);
  };
  const isaretle = async () => {
    if (!son || !window.confirm(son.hashes.length + ' kayıt İYS\'ye yüklendi olarak işaretlensin mi?')) return;
    setBusy(true);
    try { const r = await istek('avo_admin_req', { type:'iys_mark', hashes:son.hashes }); setMsg(r.status === 'done' ? r.count + ' kayıt işaretlendi.' : hataMetni(r)); setSon(null); } catch(e) { setMsg(hataMetni({ error:e && e.message })); }
    setBusy(false);
  };
  const gec = bekleyen.filter(z => Date.now() - ((z.iys || {}).since || Date.now()) > 2 * 864e5).length;
  return (
    <>
      <Sayi items={[['İzinli', (list || []).filter(z => z.status === 'active').length], ['RET', (list || []).filter(z => z.status !== 'active').length], ['İYS bekleyen', bekleyen.length]]} />
      {gec > 0 && <div style={{ ...CARD, background:'rgba(212,133,28,0.1)', color:'#9A5F10', fontWeight:700, fontSize:14 }}>{gec} kayıt 2 günden uzun süredir bekliyor. Yasal sınır 3 iş günü.</div>}
      <div style={CARD}>
        <div style={CAPS}>İYS'ye yükleme</div>
        <div style={{ fontSize:13, color:'#6E6E6E', lineHeight:1.55, marginBottom:10 }}>
          1. Bekleyenleri indir. 2. İYS Hizmet Sağlayıcı panelinde toplu izin yükleme ile dosyayı yükle. 3. Yükleme başarılıysa "Yüklendi olarak işaretle"ye bas.
          Dosya İYS'nin "Örnek Bireysel .csv" biçiminde; panelde Bireysel toplu yükleme seçilmeli. 50'den fazla izin varsa birden çok dosya iner.
        </div>
        <div style={{ display:'flex', gap:8, flexWrap:'wrap' }}>
          <button onClick={() => indir(false)} disabled={busy || !bekleyen.length} style={BTN(!(busy || !bekleyen.length))}>Bekleyenleri indir ({bekleyen.length})</button>
          {son && <button onClick={isaretle} disabled={busy} style={BTN2}>Yüklendi olarak işaretle ({son.hashes.length})</button>}
          <button onClick={() => indir(true)} disabled={busy} style={BTN2}>Tüm kayıtlar</button>
        </div>
        {msg && <div style={{ marginTop:8, fontSize:13.5, fontWeight:700 }}>{msg}</div>}
        <div style={{ fontSize:12, color:'#8A8A8A', marginTop:10 }}>Otomatik İYS bağlantısı için İYS API kullanıcı bilgileri gerekiyor; gelince bu adım kendiliğinden yapılacak.</div>
      </div>
      <div style={CARD}>
        <div style={CAPS}>Son izin kayıtları</div>
        {list && !list.length && <div style={{ fontSize:13.5, color:'#8A8A8A' }}>Henüz kayıt yok.</div>}
        {(list || []).slice(0, 60).map((z, i) => (
          <div key={z.phoneHash || i} style={{ display:'flex', justifyContent:'space-between', gap:10, padding:'8px 0', borderTop:'1px solid ' + HAIR, fontSize:13.5, flexWrap:'wrap' }}>
            <span style={{ fontFamily:'ui-monospace,Menlo,monospace', color:'#6E6E6E' }}>#{String(z.phoneHash || '').slice(0, 8)}</span>
            <span>{z.status === 'active' ? [z.channels && z.channels.wa && 'WhatsApp', z.channels && z.channels.sms && 'SMS', z.channels && z.channels.email && 'E-posta'].filter(Boolean).join(' · ') : 'RET'}</span>
            <span style={{ color:'#8A8A8A' }}>{tarih(z.status === 'active' ? z.lastConsentAt : z.withdrawnAt)} · {z.iys && z.iys.uploaded ? 'İYS ✓' : 'İYS bekliyor (' + ((z.iys || {}).pending || '') + ')'}</span>
          </div>
        ))}
      </div>
    </>
  );
}

function Raporlar({ gunler, kuponlar }){
  const [aralik, setAralik] = useState(7);
  const g = gunler.slice(0, aralik);
  const sum = (k) => g.reduce((s, x) => s + (Number(x[k]) || 0), 0);
  const ks = kuponlar.filter(k => k.day >= dayKey(Date.now() - (aralik - 1) * 864e5));
  const red = ks.filter(k => k.status === 'redeemed');
  const huni = [['7x7 oyun', sum('games7')], ['7x7 kazanan', sum('wins7')], ['Kod alan', sum('issued')], ['İçeceği alan', sum('redeemed')]];
  const top = {}; red.forEach(k => { const n = k.drinkNameTr || k.drinkName; top[n] = (top[n] || 0) + 1; });
  const saatler = Array.from({ length:24 }, () => [0, 0]);
  ks.forEach(k => { if (k.createdHour != null) saatler[k.createdHour][0]++; });
  red.forEach(k => { if (k.redeemedHour != null) saatler[k.redeemedHour][1]++; });
  const mx = Math.max(1, ...saatler.map(x => Math.max(x[0], x[1])));
  const oran = (a, b) => b ? Math.round(a / b * 100) + '%' : '—';
  return (
    <>
      <div style={{ display:'flex', gap:6 }}>
        {[[1,'Bugün'],[7,'7 gün'],[30,'30 gün']].map(([n, t]) => <button key={n} onClick={() => setAralik(n)} style={{ ...BTN2, height:34, background: aralik === n ? INK : '#FFFFFF', color: aralik === n ? GREEN : INK }}>{t}</button>)}
      </div>
      <Sayi items={[['İkram edilen içecek', sum('redeemed')], ['Menü fiyatıyla', tl(sum('value'))], ['Kazanma oranı (7x7)', oran(sum('wins7'), sum('games7'))]]} />
      <div style={CARD}>
        <div style={CAPS}>Huni</div>
        {huni.map(([t, v], i) => (
          <div key={t} style={{ display:'flex', alignItems:'center', gap:10, padding:'6px 0' }}>
            <span style={{ width:110, fontSize:13.5 }}>{t}</span>
            <div style={{ flex:1, height:22, background:'rgba(26,26,26,0.05)', borderRadius:6, overflow:'hidden' }}>
              <div style={{ width: (huni[0][1] ? Math.max(2, v / huni[0][1] * 100) : 0) + '%', height:'100%', background: i === 3 ? GREEN : INK }} />
            </div>
            <span style={{ width:80, textAlign:'right', fontSize:13.5, fontWeight:800, fontVariantNumeric:'tabular-nums' }}>{v}{i > 0 ? ' · ' + oran(v, huni[i-1][1]) : ''}</span>
          </div>
        ))}
        <div style={{ fontSize:12, color:'#8A8A8A', marginTop:6 }}>Kod alıp gelmeyen: {Math.max(0, sum('issued') - sum('redeemed'))} · Elle verilen: {sum('manual')}</div>
      </div>
      <div style={CARD}>
        <div style={CAPS}>En çok seçilen içecek</div>
        {!Object.keys(top).length && <div style={{ fontSize:13.5, color:'#8A8A8A' }}>Henüz yok.</div>}
        {Object.entries(top).sort((a,b) => b[1] - a[1]).map(([n, c]) => (
          <div key={n} style={{ display:'flex', justifyContent:'space-between', padding:'6px 0', borderTop:'1px solid ' + HAIR, fontSize:14 }}><span>{n}</span><b>{c}</b></div>
        ))}
      </div>
      <div style={CARD}>
        <div style={CAPS}>Saat dağılımı · siyah kazanılan, lime teslim edilen</div>
        <div style={{ display:'flex', alignItems:'flex-end', gap:2, height:90 }}>
          {saatler.map((x, h) => (
            <div key={h} title={h + ':00 · ' + x[0] + ' kod, ' + x[1] + ' teslim'} style={{ flex:1, display:'flex', gap:1, alignItems:'flex-end', height:'100%' }}>
              <div style={{ flex:1, height:(x[0] / mx * 100) + '%', background:INK, borderRadius:2 }} />
              <div style={{ flex:1, height:(x[1] / mx * 100) + '%', background:GREEN, borderRadius:2 }} />
            </div>
          ))}
        </div>
        <div style={{ display:'flex', justifyContent:'space-between', fontSize:11, color:'#8A8A8A', marginTop:4 }}><span>00</span><span>06</span><span>12</span><span>18</span><span>23</span></div>
      </div>
      <div style={CARD}>
        <div style={CAPS}>Gün gün</div>
        {g.map(x => (
          <div key={x.day} style={{ display:'flex', justifyContent:'space-between', padding:'6px 0', borderTop:'1px solid ' + HAIR, fontSize:13.5, fontVariantNumeric:'tabular-nums' }}>
            <span>{gunTR(x.day)}</span><span style={{ color:'#6E6E6E' }}>{x.games7 || 0} oyun · {x.wins7 || 0} kazanan · {x.issued || 0} kod · {x.redeemed || 0} teslim</span>
          </div>
        ))}
      </div>
    </>
  );
}


/* ════ Takvim: gün gün / haftalık ödül planı ════
   avo_config.special["YYYY-MM-DD"] ya da avo_config.weekly["0-6"] (0=Pazar)
   { mode:'off' } | { mode:'cups', cups } | { mode:'prize', items:[id], cups, label } */
const GUN_AD = ['Pazar','Pazartesi','Salı','Çarşamba','Perşembe','Cuma','Cumartesi'];
const AY_AD = ['Ocak','Şubat','Mart','Nisan','Mayıs','Haziran','Temmuz','Ağustos','Eylül','Ekim','Kasım','Aralık'];
const dowOf = (k) => new Date(k + 'T12:00:00Z').getUTCDay();
function kural(cfg, k){
  if (!cfg) return null;
  const own = (cfg.special || {})[k];
  const r = own || (cfg.weekly || {})[String(dowOf(k))] || null;
  if (!r) return null;
  const mode = r.mode || (Array.isArray(r.items) && r.items.length ? 'prize' : 'cups');
  return { ...r, mode, weekly: !own };
}
function gunOzet(cfg, k){
  const r = kural(cfg, k), def = cfg ? (cfg.dailyCups == null ? 5 : cfg.dailyCups) : 5;
  if (cfg && cfg.enabled === false) return { off:true, t:'Oyun kapalı', cups:0 };
  if (!r) return { cups:def, t:def + ' kahve', def:true };
  if (r.mode === 'off') return { off:true, t:'Ödül yok', cups:0, weekly:r.weekly };
  if (r.mode === 'cups') return { cups:r.cups, t:r.cups + ' kahve', weekly:r.weekly, changed:true };
  return { cups:r.cups, t:r.cups + ' ' + (r.label || 'ödül'), weekly:r.weekly, prize:true, items:r.items || [] };
}
function Takvim({ cfg, d }){
  const bugun = dayKey();
  const [ay, setAy] = useState(() => bugun.slice(0, 7));
  const [sec, setSec] = useState(bugun);
  const [f, setF] = useState(null);
  const [q, setQ] = useState('');
  const [msg, setMsg] = useState(null);
  const items = (d && d.items) || [];
  const adIt = (id) => { const it = items.find(i => i.id === id); return it ? ad(it) : id; };
  useEffect(() => {
    const r = kural(cfg, sec);
    setF(r ? { mode:r.mode, cups:r.cups == null ? 1 : r.cups, label:r.label || '', items:r.items || [], weekly:r.weekly } : { mode:'def', cups:(cfg && cfg.dailyCups) || 5, label:'', items:[], weekly:false });
    setMsg(null); setQ('');
  }, [sec, cfg]);
  const [Y, M] = ay.split('-').map(Number);
  const ilk = new Date(Date.UTC(Y, M - 1, 1)), gunSay = new Date(Date.UTC(Y, M, 0)).getUTCDate();
  const bas = (ilk.getUTCDay() + 6) % 7; // Pazartesi başlangıç
  const hucre = []; for (let i = 0; i < bas; i++) hucre.push(null);
  for (let g = 1; g <= gunSay; g++) hucre.push(Y + '-' + String(M).padStart(2, '0') + '-' + String(g).padStart(2, '0'));
  const ayKay = (n) => { const t = new Date(Date.UTC(Y, M - 1 + n, 1)); setAy(t.getUTCFullYear() + '-' + String(t.getUTCMonth() + 1).padStart(2, '0')); };
  const yaz = async (veri) => {
    const ref = window.db.doc('avo_config/main');
    const FP = firebase.firestore.FieldPath, DEL = firebase.firestore.FieldValue.delete();
    const dow = String(dowOf(sec));
    try {
      await ref.set({}, { merge:true });
      if (f.weekly) await ref.update(new FP('weekly', dow), veri == null ? DEL : veri, new FP('special', sec), DEL);
      else await ref.update(new FP('special', sec), veri == null ? DEL : veri);
      setMsg('Kaydedildi');
    } catch(e) { setMsg('Kaydedilemedi: ' + ((e && e.message) || '')); }
  };
  const kaydet = () => {
    if (f.mode === 'def') return yaz(null);
    if (f.mode === 'off') return yaz({ mode:'off' });
    const cups = Math.max(0, parseInt(f.cups, 10) || 0);
    if (f.mode === 'cups') return yaz({ mode:'cups', cups });
    if (!f.items.length) { setMsg('En az bir ürün seçin.'); return; }
    return yaz({ mode:'prize', cups, label: f.label.trim() || null, items: f.items });
  };
  const qq = q.trim().toLocaleLowerCase('tr');
  const bul = qq ? items.filter(i => ad(i).toLocaleLowerCase('tr').includes(qq)).slice(0, 10) : [];
  const haftalik = Object.entries((cfg && cfg.weekly) || {});
  const secOz = gunOzet(cfg, sec);
  const R = (v, t) => (
    <label style={{ display:'flex', alignItems:'center', gap:8, padding:'7px 0', fontSize:14.5, cursor:'pointer' }}>
      <input type="radio" checked={f && f.mode === v} onChange={() => setF({ ...f, mode:v, cups: v === 'prize' && f.mode !== 'prize' ? 1 : f.cups })} style={{ width:18, height:18, accentColor:INK }} />{t}
    </label>
  );
  return (
    <>
      <div style={CARD}>
        <div style={{ display:'flex', alignItems:'center', justifyContent:'space-between', marginBottom:10 }}>
          <button onClick={() => ayKay(-1)} style={BTN2}>‹</button>
          <b style={{ fontSize:17 }}>{AY_AD[M - 1]} {Y}</b>
          <button onClick={() => ayKay(1)} style={BTN2}>›</button>
        </div>
        <div style={{ display:'grid', gridTemplateColumns:'repeat(7,1fr)', gap:4 }}>
          {['Pzt','Sal','Çar','Per','Cum','Cmt','Paz'].map(g => <div key={g} style={{ fontSize:11, fontWeight:700, color:'#808080', textAlign:'center', paddingBottom:4 }}>{g}</div>)}
          {hucre.map((k, i) => {
            if (!k) return <div key={'b' + i} />;
            const o = gunOzet(cfg, k), gecmis = k < bugun, secili = k === sec;
            return (
              <button key={k} onClick={() => setSec(k)} disabled={gecmis}
                style={{ minHeight:58, padding:'5px 4px', borderRadius:10, textAlign:'left', cursor: gecmis ? 'default' : 'pointer', opacity: gecmis ? 0.4 : 1,
                  border: secili ? '2px solid ' + INK : '1px solid ' + HAIR2,
                  background: o.prize ? GREEN : o.off ? 'rgba(26,26,26,0.06)' : o.changed ? 'rgba(208,228,18,0.25)' : '#FFFFFF' }}>
                <div style={{ fontSize:13, fontWeight:800, color:INK }}>{Number(k.slice(8))}{k === bugun ? ' ·' : ''}</div>
                <div style={{ fontSize:10.5, lineHeight:1.2, color: o.def ? '#9A9A9A' : INK, fontWeight: o.def ? 500 : 700, textDecoration: o.off ? 'line-through' : 'none', marginTop:2 }}>{o.t}</div>
                {o.weekly && <div style={{ fontSize:9.5, color:'#6E6E6E' }}>her hafta</div>}
              </button>
            );
          })}
        </div>
        <div style={{ display:'flex', gap:12, flexWrap:'wrap', marginTop:10, fontSize:11.5, color:'#6E6E6E' }}>
          <span><b style={{ display:'inline-block', width:10, height:10, background:GREEN, verticalAlign:'middle' }} /> özel ödül</span>
          <span><b style={{ display:'inline-block', width:10, height:10, background:'rgba(208,228,18,0.25)', verticalAlign:'middle' }} /> farklı kahve sayısı</span>
          <span style={{ textDecoration:'line-through' }}>ödül yok</span>
          <span>gri: varsayılan ({(cfg && cfg.dailyCups) || 5} kahve)</span>
        </div>
      </div>

      {f && (
        <div style={CARD}>
          <div style={CAPS}>{gunTR(sec)} · {GUN_AD[dowOf(sec)]}</div>
          <div style={{ fontSize:13.5, color:'#6E6E6E', marginBottom:8 }}>Şu an: <b style={{ color:INK }}>{secOz.t}</b>{secOz.weekly ? ' (her ' + GUN_AD[dowOf(sec)] + ')' : ''}</div>
          {R('def', 'Varsayılan (' + ((cfg && cfg.dailyCups) || 5) + ' kahve)')}
          {R('cups', 'Farklı sayıda kahve')}
          {R('prize', 'Özel ödül (örn. tartin)')}
          {R('off', 'Bu gün ödül yok')}
          {(f.mode === 'cups' || f.mode === 'prize') && (
            <div style={{ display:'flex', gap:10, flexWrap:'wrap', marginTop:6 }}>
              <label><div style={CAPS}>Adet</div><input type="number" min="0" max="200" value={f.cups} onChange={e => setF({ ...f, cups:e.target.value })} style={{ ...INPUT, width:80 }} /></label>
              {f.mode === 'prize' && <label><div style={CAPS}>Oyunda görünen ad (İng.)</div><input value={f.label} placeholder="tartine" onChange={e => setF({ ...f, label:e.target.value })} style={{ ...INPUT, width:160 }} /></label>}
            </div>
          )}
          {f.mode === 'prize' && (
            <div style={{ marginTop:10 }}>
              <div style={CAPS}>Ürün(ler) · kazanan bunlardan birini seçer</div>
              <div style={{ display:'flex', flexWrap:'wrap', gap:6, marginBottom:6 }}>
                {f.items.map(id => <button key={id} onClick={() => setF({ ...f, items: f.items.filter(x => x !== id) })} style={{ height:30, padding:'0 10px', borderRadius:999, border:'none', background:INK, color:'#FFFFFF', fontSize:13, fontWeight:700, cursor:'pointer' }}>{adIt(id)} ✕</button>)}
              </div>
              <input value={q} onChange={e => setQ(e.target.value)} placeholder="Ürün ara (örn. tartine)" style={{ ...INPUT, width:'100%' }} />
              {bul.map(i => (
                <button key={i.id} onClick={() => { if (!f.items.includes(i.id)) setF({ ...f, items: f.items.concat(i.id) }); setQ(''); }}
                  style={{ display:'block', width:'100%', textAlign:'left', padding:'9px 4px', border:'none', borderBottom:'1px solid ' + HAIR, background:'transparent', fontSize:14, color:INK, cursor:'pointer' }}>{ad(i)}</button>
              ))}
            </div>
          )}
          <label style={{ display:'flex', alignItems:'center', gap:8, marginTop:12, fontSize:14, cursor:'pointer' }}>
            <input type="checkbox" checked={!!f.weekly} onChange={e => setF({ ...f, weekly:e.target.checked })} style={{ width:18, height:18, accentColor:INK }} />
            Her {GUN_AD[dowOf(sec)]} tekrarla
          </label>
          <div style={{ display:'flex', alignItems:'center', gap:10, marginTop:12 }}>
            <button onClick={kaydet} style={BTN()}>Kaydet</button>
            {msg && <span style={{ fontSize:13, color:'#6E6E6E', fontWeight:600 }}>{msg}</span>}
          </div>
        </div>
      )}

      {haftalik.length > 0 && (
        <div style={CARD}>
          <div style={CAPS}>Her hafta tekrarlayanlar</div>
          {haftalik.sort((a, b) => ((+a[0] + 6) % 7) - ((+b[0] + 6) % 7)).map(([dw, r]) => (
            <div key={dw} style={{ display:'flex', alignItems:'center', gap:10, padding:'8px 0', borderTop:'1px solid ' + HAIR, fontSize:14, flexWrap:'wrap' }}>
              <b style={{ width:90 }}>{GUN_AD[+dw]}</b>
              <span style={{ flex:1, minWidth:160 }}>{r.mode === 'off' ? 'Ödül yok' : r.mode === 'cups' ? r.cups + ' kahve' : r.cups + ' ' + (r.label || 'ödül') + ' · ' + (r.items || []).map(adIt).join(', ')}</span>
              <button onClick={async () => { if (window.confirm('Her ' + GUN_AD[+dw] + ' kuralı silinsin mi?')) { try { await window.db.doc('avo_config/main').update(new firebase.firestore.FieldPath('weekly', dw), firebase.firestore.FieldValue.delete()); } catch(e) {} } }}
                style={{ border:'none', background:'transparent', color:'#A33325', fontSize:12.5, fontWeight:700, cursor:'pointer' }}>Sil</button>
            </div>
          ))}
        </div>
      )}
    </>
  );
}

function Ayarlar({ cfg, d, mut }){
  const [form, setForm] = useState(null);
  const [kayit, setKayit] = useState(null);
  const [acikKat, setAcikKat] = useState(null);
  useEffect(() => { if (cfg && !form) setForm(cfg); }, [cfg]);
  const kaydet = async () => {
    setKayit('…');
    try {
      await window.db.doc('avo_config/main').set({
        enabled: !!form.enabled, dailyCups: Math.max(0, Math.min(200, parseInt(form.dailyCups, 10) || 0)),
        openTime: form.openTime || '08:00', closeTime: form.closeTime || '22:00', summary: !!form.summary, floatOn: form.floatOn !== false,
        eveningOn: !!form.eveningOn, eveningFrom: form.eveningFrom || '19:30',
        eveningStart: Math.max(50, Math.min(100, parseInt(form.eveningStart, 10) || 90)),
        eveningFloor: Math.max(50, Math.min(100, parseInt(form.eveningFloor, 10) || 75)),
        updatedAt: Date.now(),
      }, { merge:true });
      setKayit('Kaydedildi');
    } catch(e) { setKayit('Kaydedilemedi: ' + ((e && e.message) || '')); }
    setTimeout(() => setKayit(null), 2500);
  };
  const degisti = cfg && form && ['enabled','dailyCups','openTime','closeTime','summary','floatOn','eveningOn','eveningFrom','eveningStart','eveningFloor'].some(k => String(cfg[k]) !== String(form[k]));
  const items = (d && d.items) || [];
  const cats = ((d && d.categories) || []).slice().sort((a,b) => (a.sort||0) - (b.sort||0));
  const secili = items.filter(i => i.avoPrize);
  const toggle = (k) => setForm({ ...form, [k]: !form[k] });
  const satir = (t, s, k) => (
    <div style={{ display:'flex', alignItems:'center', justifyContent:'space-between', gap:12, padding:'10px 0', borderBottom:'1px solid ' + HAIR }}>
      <div><div style={{ fontSize:15, fontWeight:700, color:INK }}>{t}</div><div style={{ fontSize:12.5, color:'#808080' }}>{s}</div></div>
      <button onClick={() => toggle(k)} style={{ width:52, height:30, borderRadius:999, border:'none', background: form[k] ? INK : 'rgba(26,26,26,0.15)', position:'relative', cursor:'pointer', flexShrink:0 }}>
        <span style={{ position:'absolute', top:3, left: form[k] ? 25 : 3, width:24, height:24, borderRadius:99, background: form[k] ? GREEN : '#FFFFFF', transition:'left 160ms' }} />
      </button>
    </div>
  );
  return (
    <>
      {form && (
        <div style={CARD}>
          <div style={CAPS}>Oyun ayarları</div>
          {satir('Hediye kahve açık', 'Kapalıyken oyun oynanır, kod verilmez; menüdeki kart gizlenir.', 'enabled')}
          {satir('Menüde Avo balonu', 'Menünün köşesinde çıkan "Avo\'yu yen" balonu. Kapalıyken yalnız menü listesindeki kart kalır.', 'floatOn')}
          {satir('Sabah özeti (Telegram)', "Her sabah 09:05'te dünün sayıları ve İYS gecikme uyarısı.", 'summary')}
          <div style={{ display:'flex', gap:14, flexWrap:'wrap', paddingTop:12 }}>
            <label><div style={CAPS}>Günlük bardak</div><input type="number" min="0" max="200" value={form.dailyCups} onChange={e => setForm({ ...form, dailyCups: e.target.value })} style={{ ...INPUT, width:90 }} /></label>
            <label><div style={CAPS}>Kod verme başlangıç</div><input type="time" value={form.openTime} onChange={e => setForm({ ...form, openTime: e.target.value })} style={{ ...INPUT, width:118 }} /></label>
            <label><div style={CAPS}>Bitiş (kapanış)</div><input type="time" value={form.closeTime} onChange={e => setForm({ ...form, closeTime: e.target.value })} style={{ ...INPUT, width:118 }} /></label>
          </div>
          <div style={{ fontSize:12.5, color:'#808080', lineHeight:1.5, marginTop:10 }}>Kafe kapalıyken kazanan kod alamaz; haftalık hakkı da gitmez. Kod yalnız kazanıldığı gün geçerli. Haftalık hak, garson "Teslim edildi" dediğinde düşer.</div>
          <div style={{ marginTop:14 }}>
            {satir('Akşam zorluğu', "Belirtilen saatten sonra 7×7'de Avo daha güçlü oynar.", 'eveningOn')}
            {form.eveningOn && (
              <div style={{ display:'flex', gap:14, flexWrap:'wrap', paddingTop:12 }}>
                <label><div style={CAPS}>Başlangıç saati</div><input type="time" value={form.eveningFrom} onChange={e => setForm({ ...form, eveningFrom: e.target.value })} style={{ ...INPUT, width:118 }} /></label>
                <label><div style={CAPS}>Avo gücü (%)</div><input type="number" min="50" max="100" value={form.eveningStart} onChange={e => setForm({ ...form, eveningStart: e.target.value })} style={{ ...INPUT, width:90 }} /></label>
                <label><div style={CAPS}>En düşük (%)</div><input type="number" min="50" max="100" value={form.eveningFloor} onChange={e => setForm({ ...form, eveningFloor: e.target.value })} style={{ ...INPUT, width:90 }} /></label>
              </div>
            )}
            <div style={{ fontSize:12.5, color:'#808080', lineHeight:1.5, marginTop:8 }}>Gün içinde Avo %80'den başlar, her kayıptan sonra 5 puan düşer, en fazla %60'a iner. Akşam modunda bu değerler yukarıdaki gibi olur.</div>
          </div>
          <div style={{ display:'flex', alignItems:'center', gap:10, marginTop:12 }}>
            <button onClick={kaydet} disabled={!degisti} style={BTN(!!degisti)}>Ayarları kaydet</button>
            {kayit && <span style={{ fontSize:13, color:'#6E6E6E', fontWeight:600 }}>{kayit}</span>}
          </div>
        </div>
      )}
      <div style={CARD}>
        <div style={CAPS}>Avo'yu yenenler alabilir · {secili.length} ürün</div>
        <div style={{ fontSize:12.5, color:'#808080', lineHeight:1.5, marginBottom:10 }}>Kazanan bu ürünlerden birini seçer. Değişiklik üstteki "Kaydet & yayınla" ile yayına girer.</div>
        {secili.length > 0 && (
          <div style={{ display:'flex', flexWrap:'wrap', gap:6, marginBottom:10 }}>
            {secili.map(it => (
              <button key={it.id} onClick={() => mut(dd => { const x = dd.items.find(i => i.id === it.id); if (x) delete x.avoPrize; })}
                style={{ height:32, padding:'0 12px', borderRadius:999, border:'none', background:INK, color:'#FFFFFF', fontSize:13, fontWeight:700, cursor:'pointer' }}>{ad(it)} ✕</button>
            ))}
          </div>
        )}
        {cats.map(c => {
          const list = items.filter(i => i.cat === c.id);
          if (!list.length) return null;
          const n = list.filter(i => i.avoPrize).length, open = acikKat === c.id;
          return (
            <div key={c.id} style={{ borderTop:'1px solid ' + HAIR }}>
              <button onClick={() => setAcikKat(open ? null : c.id)}
                style={{ width:'100%', display:'flex', justifyContent:'space-between', alignItems:'center', padding:'11px 2px', border:'none', background:'transparent', cursor:'pointer', fontSize:14.5, fontWeight:700, color:INK }}>
                <span>{(typeof c.tr === 'string' ? c.tr : (c.tr && c.tr.n)) || c.name || c.id}</span>
                <span style={{ fontSize:12.5, color:'#808080', fontWeight:600 }}>{n ? n + ' seçili · ' : ''}{list.length} ürün {open ? '▴' : '▾'}</span>
              </button>
              {open && list.map(it => (
                <label key={it.id} style={{ display:'flex', alignItems:'center', gap:10, padding:'8px 4px', cursor:'pointer' }}>
                  <input type="checkbox" checked={!!it.avoPrize} onChange={e => { const on = e.target.checked; mut(dd => { const x = dd.items.find(i => i.id === it.id); if (!x) return; if (on) x.avoPrize = true; else delete x.avoPrize; }); }}
                    style={{ width:20, height:20, accentColor:INK }} />
                  <span style={{ fontSize:14.5, color:INK }}>{ad(it)}</span>
                  {it.soldOut && <span style={{ fontSize:11.5, color:'#A33325', fontWeight:700 }}>tükendi</span>}
                </label>
              ))}
            </div>
          );
        })}
      </div>
    </>
  );
}

/* ════ MENÜ: XOX kartı (kalan bardak) / bugünkü kupon pili ════ */
function MenuCard({ lang }){
  const en = lang === 'en';
  const [cfg, setCfg] = useState(null);
  const [gun, setGun] = useState({});
  const [kupon, setKupon] = useState(null);
  useEffect(() => window.db.doc('avo_config/main').onSnapshot(s => setCfg(Object.assign({ enabled:true, dailyCups:5 }, s.exists ? s.data() : {})), () => setCfg({ enabled:true, dailyCups:5 })), []);
  useEffect(() => window.db.doc('avo_daily/' + dayKey()).onSnapshot(s => setGun(s.exists ? s.data() : {}), () => {}), []);
  useEffect(() => {
    let v = null; try { v = JSON.parse(localStorage.getItem('ax_voucher') || 'null'); } catch(e) {}
    if (!v || v.day !== dayKey() || v.redeemed) return;
    setKupon(v);
    return window.db.doc('avo_vouchers/' + v.code).onSnapshot(s => { if (s.exists && s.data().status !== 'active') { setKupon(null); try { v.redeemed = s.data().status === 'redeemed'; v.status = s.data().status; localStorage.setItem('ax_voucher', JSON.stringify(v)); } catch(e) {} } }, () => {});
  }, []);
  if (!cfg || !window.AVO) return null;
  if (kupon) return (
    <a href={GAME_URL + '?lang=' + (en ? 'en' : 'tr')} className="avb3-press" style={{ display:'flex', alignItems:'center', gap:12, margin:'4px 2px 14px', padding:'12px 16px', borderRadius:999, background:GREEN, color:INK, textDecoration:'none' }}>
      <span style={{ width:40, height:40, flexShrink:0 }} dangerouslySetInnerHTML={{ __html: window.AVO('h', { anim:false }) }} />
      <span style={{ flex:1, fontSize:15, fontWeight:800 }}>{en ? 'Your free drink' : 'Hediye içeceğin'} · {kupon.drink}</span>
      <span style={{ fontSize:17, fontWeight:900, letterSpacing:'0.14em' }}>{kupon.code}</span>
    </a>
  );
  const oz = gunOzet(cfg, dayKey());
  if (oz.off) return null;
  const toplam = oz.cups || 0, kalan = Math.max(0, toplam - (gun.issued || 0));
  return (
    <a href={GAME_URL + '?lang=' + (en ? 'en' : 'tr')} className="avb3-press"
      style={{ display:'flex', alignItems:'center', gap:14, margin:'4px 2px 14px', padding:'16px 18px', borderRadius:18, background:INK, color:'#FFFFFF', textDecoration:'none' }}>
      <span style={{ width:64, height:64, flexShrink:0 }} dangerouslySetInnerHTML={{ __html: window.AVO(kalan ? 'n' : 'z') }} />
      <span style={{ flex:1, minWidth:0 }}>
        <span style={{ display:'block', fontSize:18, fontWeight:800, letterSpacing:'-0.01em' }}>{en ? 'Beat Avo, win a drink' : "Avo'yu yen, kahven bizden"}</span>
        <span style={{ display:'block', fontSize:13, color:'rgba(255,255,255,0.65)', marginTop:3 }}>
          {kalan ? (en ? kalan + ' of ' + toplam + ' left today' : 'Bugün ' + toplam + ' ödülden ' + kalan + ' kaldı') : (en ? "Today's drinks are gone. Play for fun" : 'Bugünün içecekleri bitti, eğlencesine oyna')}
        </span>
      </span>
      <span style={{ width:36, height:36, borderRadius:99, background:GREEN, display:'flex', alignItems:'center', justifyContent:'center', flexShrink:0 }}>
        <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke={INK} strokeWidth="2.6" strokeLinecap="round" strokeLinejoin="round"><path d="M5 12h14M13 6l6 6-6 6" /></svg>
      </span>
    </a>
  );
}

/* ════ MENÜ: sağ altta yüzen Avo (WhatsApp balonu gibi) ════
   Dokununca konuşma balonu açılır: "Avo'yu yen, kahveyi kap". Çarpı ile o gün için gizlenir. */
function FloatAvo({ lang, lift, hidden }){
  const en = lang === 'en';
  const [cfg, setCfg] = useState(null);
  const [gun, setGun] = useState({});
  const [acik, setAcik] = useState(false);
  const [gor, setGor] = useState(false);
  const [kapali, setKapali] = useState(() => { try { return localStorage.getItem('avb_avo_hide') === dayKey(); } catch(e) { return false; } });
  const [kuponVar, setKuponVar] = useState(() => { try { const v = JSON.parse(localStorage.getItem('ax_voucher') || 'null'); return !!(v && v.day === dayKey() && !v.redeemed && v.status !== 'void'); } catch(e) { return false; } });
  useEffect(() => { let v = null; try { v = JSON.parse(localStorage.getItem('ax_voucher') || 'null'); } catch(e) {}
    if (!v || v.day !== dayKey() || v.redeemed) return;
    return window.db.doc('avo_vouchers/' + v.code).onSnapshot(s => { if (s.exists && s.data().status !== 'active') { setKuponVar(false); try { v.redeemed = s.data().status === 'redeemed'; v.status = s.data().status; localStorage.setItem('ax_voucher', JSON.stringify(v)); } catch(e) {} } }, () => {}); }, []);
  useEffect(() => window.db.doc('avo_config/main').onSnapshot(s => setCfg(Object.assign({ enabled:true, dailyCups:5 }, s.exists ? s.data() : {})), () => setCfg({ enabled:true, dailyCups:5 })), []);
  useEffect(() => window.db.doc('avo_daily/' + dayKey()).onSnapshot(s => setGun(s.exists ? s.data() : {}), () => {}), []);
  useEffect(() => { const t = setTimeout(() => setGor(true), 2500); return () => clearTimeout(t); }, []);
  useEffect(() => { if (!gor) return; const t = setTimeout(() => setAcik(a => a === false ? 'peek' : a), 900); const u = setTimeout(() => setAcik(a => a === 'peek' ? false : a), 6000); return () => { clearTimeout(t); clearTimeout(u); }; }, [gor]);
  if (!cfg || !window.AVO || cfg.floatOn === false || kapali || kuponVar || hidden || !gor) return null;
  const oz = gunOzet(cfg, dayKey());
  if (oz.off) return null;
  const kalan = Math.max(0, (oz.cups || 0) - (gun.issued || 0));
  const pz = oz.prize ? ((kural(cfg, dayKey()) || {}).label || (en ? 'treat' : 'ikram')) : (en ? 'coffee' : 'kahve');
  const kapat = (e) => { e.stopPropagation(); try { localStorage.setItem('avb_avo_hide', dayKey()); } catch(_) {} setKapali(true); };
  const git = () => { window.location.href = GAME_URL + '?lang=' + (en ? 'en' : 'tr'); };
  const balon = !!acik;
  return (
    <div style={{ position:'absolute', right:14, bottom: (lift ? 84 : 18), zIndex:7, display:'flex', flexDirection:'column', alignItems:'flex-end', gap:8, pointerEvents:'none', transition:'bottom 260ms cubic-bezier(.2,.8,.2,1)' }}>
      {balon && (
        <div onClick={git} className="avb3-press" style={{ pointerEvents:'auto', maxWidth:250, background:'#FFFFFF', color:INK, borderRadius:18, padding:'12px 14px 12px 16px', boxShadow:'0 10px 30px rgba(26,26,26,.18)', border:'1px solid ' + HAIR, cursor:'pointer', animation:'avb3SheetUp 260ms cubic-bezier(.2,.8,.2,1)', position:'relative' }}>
          <div style={{ fontSize:16, fontWeight:800, lineHeight:1.2 }}>{en ? 'Beat Avo, grab a ' + pz + '!' : (oz.prize ? "Avo'yu yen, ikramın bizden!" : "Avo'yu yen, kahven bizden!")}</div>
          <div style={{ fontSize:12.5, color:'#6E6E6E', marginTop:4, lineHeight:1.35 }}>
            {kalan ? (en ? kalan + ' left today · 7×7 XOX' : 'Bugün ' + kalan + ' tane kaldı · 7x7 XOX') : (en ? "Today's are gone. Play for fun." : 'Bugünkü bitti, eğlencesine oyna.')}
          </div>
          {acik === true && <div style={{ marginTop:10, height:36, borderRadius:999, background:INK, color:GREEN, display:'flex', alignItems:'center', justifyContent:'center', fontSize:14, fontWeight:800 }}>{en ? 'Play now' : 'Hemen oyna'}</div>}
          <span style={{ position:'absolute', right:24, bottom:-7, width:14, height:14, background:'#FFFFFF', borderRight:'1px solid ' + HAIR, borderBottom:'1px solid ' + HAIR, transform:'rotate(45deg)' }} />
        </div>
      )}
      <div style={{ position:'relative', pointerEvents:'auto' }}>
        <button onClick={() => setAcik(a => a === true ? false : true)} aria-label={en ? 'Beat Avo, win a drink' : "Avo'yu yen, içecek kazan"}
          style={{ width:64, height:64, borderRadius:999, border:'none', background:GREEN, boxShadow:'0 10px 26px rgba(26,26,26,.25)', padding:6, cursor:'pointer', animation:'avb3SheetUp 360ms cubic-bezier(.2,.8,.2,1)' }}>
          <span style={{ display:'block', width:'100%', height:'100%' }} dangerouslySetInnerHTML={{ __html: window.AVO(balon ? 'h' : 'n', { cheek:'#FFFFFF' }) }} />
        </button>
        <button onClick={kapat} aria-label={en ? 'Hide' : 'Gizle'}
          style={{ position:'absolute', top:-6, left:-6, width:24, height:24, borderRadius:99, border:'2px solid #FFFFFF', background:INK, color:'#FFFFFF', fontSize:12, fontWeight:900, lineHeight:1, cursor:'pointer', display:'flex', alignItems:'center', justifyContent:'center', padding:0 }}>✕</button>
      </div>
    </div>
  );
}

window.AvbAvo = { GiftRedeem, AdminXox, MenuCard, FloatAvo };
})();
