/* ============================================================
   RIVA — Traduction de la carte pour le site

   Ce fichier ne contient AUCUN plat : il lit  carte.js  et le met
   en forme pour le site. Pour modifier la carte, va dans carte.js.
   ============================================================ */

/* ---------- petits utilitaires ---------- */

// « Gyozas crevettes » → « gyozas-crevettes » (sert d'identifiant et de nom de photo)
function btSlug(s) {
  return String(s).normalize('NFD').replace(/[̀-ͯ]/g, '')
    .toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/^-|-$/g, '');
}

// Nom de fichier photo attendu pour un plat (identique à photos\_NOMS.txt)
function btPhotoSlug(catId, nom) {
  return btSlug(catId + '_' + nom);
}

// PHOTOS est fourni par photos.js (généré par le serveur ou par build-site.js).
// Chaque clé est un nom de fichier sans extension, chaque valeur une adresse d'image.
function btPhoto(catId, nom) {
  try {
    const P = (typeof PHOTOS === 'object' && PHOTOS) ? PHOTOS : {};
    return P[btPhotoSlug(catId, nom)] || null;
  } catch (e) { return null; }
}

// Étiquettes déduites de la carte elle-même (rien d'inventé)
function btBadges(cat, item) {
  const badges = [];
  const texte = ((item.n || '') + ' ' + (item.d || '') + ' ' + (cat.note || '')).toLowerCase();
  if (cat.id === 'signature' || item.star) badges.push('signature');
  if (/spicy|piquant|épic|dynamite/.test(texte)) badges.push('hot');
  if (/falafel|végétarien|veggie/.test(texte)) badges.push('veg');
  return badges;
}

/* ---------- conversion carte.js → menu du site ---------- */

function btConstruireMenu() {
  const menu = {};
  CARTE.forEach(cat => {
    const items = cat.items
      .filter(i => i.n && !i.off)
      .map(i => ({
        id: btSlug(cat.id + '-' + i.n),
        name: i.n,
        tagline: '',
        desc: i.d || '',
        price: i.p,
        img: btPhoto(cat.id, i.n),
        photoSlug: btPhotoSlug(cat.id, i.n),
        badges: btBadges(cat, i),
        options: i.options || null,
        composition: (i.d || '').split('•').map(s => s.trim()).filter(Boolean),
        allergenes: [],
        halal: true,
        catId: cat.id,
        catLabel: cat.nom,
        teinte: cat.teinte || 'vert',
      }));
    if (items.length === 0) return;
    menu[cat.id] = {
      id: cat.id,
      label: cat.nom,
      sub: cat.note || '',
      teinte: cat.teinte || 'vert',
      items,
    };
  });
  return menu;
}

// La catégorie « Signatures » passe en premier : c'est elle qui alimente
// la vitrine du haut de page et le plat mis en avant.
function btOrdonner(menu) {
  const ordonne = {};
  if (menu.signature) ordonne.signature = menu.signature;
  Object.keys(menu).forEach(k => { if (k !== 'signature') ordonne[k] = menu[k]; });
  return ordonne;
}

const MENU = btOrdonner(btConstruireMenu());
const DEFAULT_MENU = MENU;

/* ---------- ouverture du restaurant ---------- */

function isOpenNow() {
  const now = new Date();
  const day = (now.getDay() + 6) % 7; // 0 = lundi
  const today = SHOP.hours[day];
  if (!today || today.closed) return { open: false, label: 'Fermé aujourd\'hui' };
  const mins = now.getHours() * 60 + now.getMinutes();
  const slots = today.slots.split('/').map(s => {
    const [from, to] = s.trim().split('–').map(t => {
      const [hh, mm] = t.trim().replace('h', ':').split(':');
      return parseInt(hh) * 60 + parseInt(mm || 0);
    });
    return { from, to };
  });
  for (const slot of slots) {
    if (mins >= slot.from && mins < slot.to) {
      const closeH = Math.floor(slot.to / 60);
      const closeM = slot.to % 60;
      return { open: true, label: `Ouvert · ferme à ${closeH}h${String(closeM).padStart(2, '0')}` };
    }
  }
  return { open: false, label: 'Fermé · ouvre bientôt' };
}

/* ---------- mode de service ------------------------------------------------
   Un QR code de table ouvre le site avec  ?table=7  dans l'adresse.
   On retient le numéro pour toute la visite : le client reste « sur place »
   même s'il navigue, et le ticket de caisse sortira SUR PLACE — TABLE 7.
--------------------------------------------------------------------------- */

function getTable() {
  try {
    const params = new URLSearchParams(location.search);
    const brut = (params.get('table') || params.get('t') || '').trim();
    if (/^[0-9]{1,3}$/.test(brut)) {
      sessionStorage.setItem('bt-table', brut);
      marquerTable(brut);
      return brut;
    }
    const memorise = sessionStorage.getItem('bt-table');
    if (memorise && /^[0-9]{1,3}$/.test(memorise)) { marquerTable(memorise); return memorise; }
  } catch (e) {}
  return null;
}

function quitterLaTable() {
  try { sessionStorage.removeItem('bt-table'); } catch (e) {}
  try { document.cookie = 'riva-table=; Path=/; Max-Age=0; SameSite=Lax'; } catch (e) {}
}

// Petit témoin « ce client est à une table » (4 heures). Le serveur en ligne
// s'en sert pour laisser passer les QR des tables pendant une maintenance :
// ces clients sont déjà dans le restaurant. Il ne donne aucun autre droit.
function marquerTable(numero) {
  try { document.cookie = 'riva-table=' + numero + '; Path=/; Max-Age=14400; SameSite=Lax' + (location.protocol === 'https:' ? '; Secure' : ''); } catch (e) {}
}

// Libellés officiels des trois modes — utilisés à l'identique sur le site,
// sur l'écran de caisse et sur le ticket imprimé.
const MODES = {
  surplace:  { id: 'surplace',  label: 'Sur place',    ticket: 'SUR PLACE',  couleur: 'jade' },
  emporter:  { id: 'emporter',  label: 'À emporter',   ticket: 'À EMPORTER', couleur: 'or' },
  livraison: { id: 'livraison', label: 'Livraison',    ticket: 'LIVRAISON',  couleur: 'rouge' },
};

/* ---------- envoi d'une commande à la caisse ---------- */

function urlServeur(chemin) {
  const base = (typeof SERVEUR_CAISSE === 'string' && SERVEUR_CAISSE) ? SERVEUR_CAISSE.replace(/\/$/, '') : '';
  return base + chemin;
}

// Envoie la commande au serveur de caisse.
// Refusée ou injoignable : { ok: false, erreur } — le client NE DOIT PAS croire
// que sa commande est partie, le panier reste là pour réessayer.
// Seule exception : le site ouvert en double-clic (fichier, sans serveur), où
// la commande est gardée dans le navigateur pour que la démonstration marche.
async function envoyerCommande(commande) {
  const demo = location.protocol === 'file:';
  try {
    // Le patron connecté au tableau de bord peut tester avant l'ouverture :
    // le serveur reconnaît son mot de passe et marque la commande TEST.
    const entetes = { 'Content-Type': 'application/json' };
    const cle = getAdminKey();
    if (cle) entetes['X-Cle-Admin'] = cle;
    const rep = await fetch(urlServeur('/api/commandes'), {
      method: 'POST',
      headers: entetes,
      body: JSON.stringify(commande),
    });
    if (!rep.ok && !demo) {
      let erreur = '';
      try { erreur = (await rep.json()).erreur || ''; } catch (e) {}
      if (!erreur || rep.status >= 500) erreur = 'Le restaurant ne peut pas recevoir la commande pour le moment.';
      return { ok: false, erreur };
    }
    if (!rep.ok) throw new Error('refus du serveur (' + rep.status + ')');
    const data = await rep.json();
    return { ok: true, horsLigne: false, commande: data.commande };
  } catch (e) {
    if (!demo) return { ok: false, erreur: 'Connexion au restaurant impossible. Vérifiez votre connexion internet.' };
    const secours = { ...commande, numero: commande.numero || btNumeroLocal(), recueA: new Date().toISOString(), statut: 'nouvelle' };
    try {
      const liste = JSON.parse(localStorage.getItem('bt-commandes') || '[]');
      liste.unshift(secours);
      localStorage.setItem('bt-commandes', JSON.stringify(liste.slice(0, 50)));
    } catch (e2) {}
    return { ok: true, horsLigne: true, commande: secours, erreur: String(e.message || e) };
  }
}

function btNumeroLocal() {
  return 'RV-' + String(Math.floor(Math.random() * 9000) + 1000);
}

/* ---------- modifications de la carte faites depuis le tableau de bord ----
   Le patron peut ajouter / modifier / masquer des plats sans toucher au
   code : ces changements sont enregistrés dans son navigateur et viennent
   se superposer à carte.js.
--------------------------------------------------------------------------- */

function getEffectiveMenu() {
  let overrides = {};
  let featuredId = null;
  try {
    overrides = JSON.parse(localStorage.getItem('bt-menu-overrides') || '{}');
    featuredId = localStorage.getItem('bt-plat-vedette');
  } catch (e) {}

  const result = {};
  Object.entries(DEFAULT_MENU).forEach(([catId, cat]) => {
    const catOv = overrides[catId] || {};
    const deletedIds = new Set(catOv.deleted || []);
    const editedItems = catOv.items || {};

    const baseItems = cat.items
      .filter(it => !deletedIds.has(it.id))
      .map(it => editedItems[it.id] ? { ...it, ...editedItems[it.id] } : it);

    const customItems = Object.entries(editedItems)
      .filter(([id]) => id.startsWith('custom-'))
      // Un plat ajouté au tableau de bord prend la rubrique où il est rangé
      // (nom de la rubrique sur sa carte, couleur, ticket de cuisine).
      .map(([id, item]) => ({ composition: [], allergenes: [], badges: [], halal: true, ...item, id,
                              catId, catLabel: cat.label, teinte: cat.teinte }));

    const ruptures = getRuptures();
    result[catId] = { ...cat, items: [...baseItems, ...customItems]
      .map(it => ruptures.includes(it.id) ? { ...it, rupture: true } : it) };
  });

  // Les catégories créées au tableau de bord, avec les plats qu'on y a mis.
  (overrides._rubriques || []).forEach(r => {
    if (!r || !r.id || result[r.id]) return;
    const cat = { id: r.id, label: r.label, sub: r.sub || '', teinte: 'vert', perso: true };
    const ruptures = getRuptures();
    cat.items = Object.entries((overrides[r.id] || {}).items || {})
      .filter(([id]) => id.startsWith('custom-'))
      .map(([id, item]) => ({ composition: [], allergenes: [], badges: [], halal: true, ...item, id,
                              catId: r.id, catLabel: r.label, teinte: 'vert' }))
      .map(it => ruptures.includes(it.id) ? { ...it, rupture: true } : it);
    result[r.id] = cat;
  });

  return { menu: result, featuredId };
}

function saveMenuItem(catId, item) {
  try {
    const overrides = JSON.parse(localStorage.getItem('bt-menu-overrides') || '{}');
    if (!overrides[catId]) overrides[catId] = { items: {}, deleted: [] };
    if (!overrides[catId].items) overrides[catId].items = {};
    overrides[catId].items[item.id] = item;
    if (overrides[catId].deleted) {
      overrides[catId].deleted = overrides[catId].deleted.filter(id => id !== item.id);
    }
    localStorage.setItem('bt-menu-overrides', JSON.stringify(overrides));
    if (window.partagerReglage) partagerReglage('bt-menu-overrides');
    return true;
  } catch (e) { return false; }
}

function deleteMenuItem(catId, itemId) {
  try {
    const overrides = JSON.parse(localStorage.getItem('bt-menu-overrides') || '{}');
    if (!overrides[catId]) overrides[catId] = { items: {}, deleted: [] };
    if (itemId.startsWith('custom-')) {
      if (overrides[catId].items) delete overrides[catId].items[itemId];
    } else {
      if (!overrides[catId].deleted) overrides[catId].deleted = [];
      if (!overrides[catId].deleted.includes(itemId)) overrides[catId].deleted.push(itemId);
      if (overrides[catId].items) delete overrides[catId].items[itemId];
    }
    localStorage.setItem('bt-menu-overrides', JSON.stringify(overrides));
    if (window.partagerReglage) partagerReglage('bt-menu-overrides');
    return true;
  } catch (e) { return false; }
}

function resetMenuOverrides() {
  try {
    localStorage.removeItem('bt-menu-overrides');
    localStorage.removeItem('bt-plat-vedette');
    if (window.partagerReglage) { partagerReglage('bt-menu-overrides'); partagerReglage('bt-plat-vedette'); }
    return true;
  } catch (e) { return false; }
}

/* ---------- catégories ajoutées au tableau de bord ----------
   Rangées dans le même réglage que les plats (bt-menu-overrides), donc
   partagées avec le serveur et la caisse :
     _rubriques : [{ id, label, sub, famille }]   famille = id d'une famille
     _familles  : [{ id, nom, accroche }]         familles créées en plus */

function lireOverrides() {
  try { return JSON.parse(localStorage.getItem('bt-menu-overrides') || '{}') || {}; } catch (e) { return {}; }
}
function ecrireOverrides(o) {
  try { localStorage.setItem('bt-menu-overrides', JSON.stringify(o)); } catch (e) { return Promise.resolve(false); }
  if (window.partagerReglage) return partagerReglage('bt-menu-overrides');
  return Promise.resolve(true);
}
function getRubriquesPerso() {
  const o = lireOverrides();
  return { rubriques: Array.isArray(o._rubriques) ? o._rubriques : [],
           familles: Array.isArray(o._familles) ? o._familles : [] };
}
// famille : id d'une famille existante, ou null pour en créer une nouvelle
// (elle aura sa propre case sur la carte, au nom de la catégorie).
function ajouterRubrique(label, sub, famille) {
  const o = lireOverrides();
  const id = 'rubrique-' + Date.now();
  o._rubriques = Array.isArray(o._rubriques) ? o._rubriques : [];
  let fam = famille;
  if (!fam) {
    fam = 'famille-' + Date.now();
    o._familles = Array.isArray(o._familles) ? o._familles : [];
    o._familles.push({ id: fam, nom: label, accroche: sub || '' });
  }
  o._rubriques.push({ id, label, sub: sub || '', famille: fam });
  return ecrireOverrides(o).then(ok => ({ ok, id }));
}
// Retire la catégorie et ses plats ; une famille créée qui se retrouve vide part aussi.
function supprimerRubrique(id) {
  const o = lireOverrides();
  const r = (o._rubriques || []).find(x => x.id === id);
  o._rubriques = (o._rubriques || []).filter(x => x.id !== id);
  delete o[id];
  if (r && (o._familles || []).some(f => f.id === r.famille) && !o._rubriques.some(x => x.famille === r.famille)) {
    o._familles = o._familles.filter(f => f.id !== r.famille);
  }
  return ecrireOverrides(o);
}

/* ---------- plats en rupture ----------
   Le patron coche « En rupture » au tableau de bord : le plat reste sur la
   carte, grisé, et ne peut plus être commandé (le serveur refuse aussi). */

function getRuptures() {
  try {
    const l = JSON.parse(localStorage.getItem('riva-ruptures') || '[]');
    return Array.isArray(l) ? l : [];
  } catch (e) { return []; }
}
// Renvoie une promesse : true si le restaurant l'a bien enregistré.
function setRupture(itemId, enRupture) {
  const liste = getRuptures().filter(id => id !== itemId);
  if (enRupture) liste.push(itemId);
  try {
    if (liste.length) localStorage.setItem('riva-ruptures', JSON.stringify(liste));
    else localStorage.removeItem('riva-ruptures');
  } catch (e) {}
  if (window.partagerReglage) return partagerReglage('riva-ruptures');
  return Promise.resolve(true);
}
function viderRuptures() {
  try { localStorage.removeItem('riva-ruptures'); } catch (e) {}
  if (window.partagerReglage) return partagerReglage('riva-ruptures');
  return Promise.resolve(true);
}

function setPlatVedette(itemId) {
  try {
    if (itemId) localStorage.setItem('bt-plat-vedette', itemId);
    else localStorage.removeItem('bt-plat-vedette');
    if (window.partagerReglage) partagerReglage('bt-plat-vedette');
    return true;
  } catch (e) { return false; }
}

/* ---------- petit mot manuscrit du haut de page ---------- */

function getHeroQuote() {
  try {
    const stored = JSON.parse(localStorage.getItem('bt-mot-accueil') || 'null');
    if (stored) return { actif: true, ...stored };
  } catch (e) {}
  return { actif: true, line1: 'fait minute,\nrien d\'autre.', line2: '', author: '' };
}
function setHeroQuote(q) {
  try { localStorage.setItem('bt-mot-accueil', JSON.stringify(q)); } catch (e) {}
  if (window.partagerReglage) return partagerReglage('bt-mot-accueil');
  return Promise.resolve(true);
}

/* ---------- les textes du haut de page ----------
   Pastilles, titre, phrase de présentation : le patron les change depuis le
   tableau de bord. Une pastille laissée vide disparaît. */

const TEXTES_HERO_DEFAUT = {
  pastille1: '100% Halal',
  pastille2: 'Denain · 59220',
  titre1: 'Pizza',
  titre2: '& panuozzo.',
  signature: 'riva, denain.',
  texte: 'Pâte napolitaine à maturation lente, cuite à la demande. Le panuozzo garni sous vos yeux, les pâtes terminées dans la meule de Parmigiano.',
  texteFort: 'Tout est halal, tout est fait minute.',
};

function getHeroTextes() {
  try {
    const stored = JSON.parse(localStorage.getItem('riva-textes-hero') || 'null');
    if (stored) return { ...TEXTES_HERO_DEFAUT, ...stored };
  } catch (e) {}
  return { ...TEXTES_HERO_DEFAUT };
}
function setHeroTextes(t) {
  try { localStorage.setItem('riva-textes-hero', JSON.stringify(t)); } catch (e) {}
  if (window.partagerReglage) return partagerReglage('riva-textes-hero');
  return Promise.resolve(true);
}
function resetHeroTextes() {
  try { localStorage.removeItem('riva-textes-hero'); } catch (e) {}
  if (window.partagerReglage) return partagerReglage('riva-textes-hero');
  return Promise.resolve(true);
}

/* ---------- accès au tableau de bord ---------- */

/* ---------- l'avis Google -------------------------------------------------
   Avec le Place ID, on ouvre la fenêtre d'avis de Google directement.
   Sans lui, on ouvre la fiche du restaurant : le client appuie lui-même
   sur « Écrire un avis ». Dans les deux cas ça marche.
-------------------------------------------------------------------------- */

function lienAvisGoogle() {
  const id = (SHOP.googlePlaceId || '').trim();
  if (id) return `https://search.google.com/local/writereview?placeid=${encodeURIComponent(id)}`;
  return (SHOP.avisLien || '').trim() || SHOP.mapsLink;
}

/* On ne redemande pas un avis à quelqu'un qui vient d'en laisser un.
   Retenu 60 jours sur son téléphone, rien n'est envoyé nulle part. */
const AVIS_DELAI = 60 * 24 * 3600 * 1000;

function avisDejaDemande() {
  try {
    const t = Number(localStorage.getItem('bt-avis-clique') || 0);
    return t > 0 && (Date.now() - t) < AVIS_DELAI;
  } catch (e) { return false; }
}

function marquerAvisDemande() {
  try { localStorage.setItem('bt-avis-clique', String(Date.now())); } catch (e) {}
}

function getAdminKey() {
  try {
    return sessionStorage.getItem('bt-cle-admin') || '';
  } catch (e) {}
  return '';
}
function setAdminKeyValue(newKey) {
  try {
    if (newKey) sessionStorage.setItem('bt-cle-admin', newKey);
    else sessionStorage.removeItem('bt-cle-admin');
  } catch (e) {}
}

// Plus de fausses commandes de démonstration : la caisse affiche le réel.
const DEMO_ORDERS = [];

Object.assign(window, {
  MENU, DEFAULT_MENU, SHOP, DEMO_ORDERS, SEED_REVIEWS, MODES,
  isOpenNow, getAdminKey, setAdminKeyValue,
  lienAvisGoogle, avisDejaDemande, marquerAvisDemande,
  getEffectiveMenu, saveMenuItem, deleteMenuItem, resetMenuOverrides, setPlatVedette,
  getRuptures, setRupture, viderRuptures,
  getRubriquesPerso, ajouterRubrique, supprimerRubrique,
  getHeroQuote, setHeroQuote,
  TEXTES_HERO_DEFAUT, getHeroTextes, setHeroTextes, resetHeroTextes,
  btSlug, btPhotoSlug, btPhoto, getTable, quitterLaTable, envoyerCommande, urlServeur,
});
