// app/data-backend.jsx — Adapter données live pour l'app invité
//
// L'app charge ici la liste d'invités + tables + gîtes depuis le Sheet
// (via backend/config.js, endpoint `getAppData`). Si le backend est HS,
// on retombe sur les placeholders d'APP_DATA. Le résultat est mis en
// cache localStorage 10 min (TTL aligné avec BACKEND.CACHE_TTL).
//
// Le hook renvoie :
//   {
//     invites: [{ id, name, prenom, nom, cote, categorie, tableId, giteId }],
//     tables:  [{ id, name, capacite, note, color, guests: [name…] }],
//     gites:   [{ id, name, beds, occupants: [name…] }],
//     allGuests:   [{ name, tableId, tableName }],   // pour fuzzy match Ma Table
//     allSleepers: [{ name, giteId, giteName }],     // pour fuzzy match Mon Gîte
//     loading,
//     source: "backend" | "cache" | "demo",
//   }

const APP_DATA_CACHE_KEY  = "ea-backend:appdata";
const APP_DATA_CACHE_STAMP = "ea-backend:appdata:at";
const APP_DATA_CACHE_TTL  = 10 * 60 * 1000; // 10 min

// Reconstruit la forme attendue par plan-table.jsx à partir du payload
// backend brut + décorations statiques d'APP_DATA (couleur, note, etc.).
function buildAppShape(rawInvites, rawTables, rawGites) {
  const invites = rawInvites.map((inv) => {
    const prenom = inv.prenom || "";
    const nom = inv.nom || "";
    const name = `${prenom} ${nom}`.trim() || "(sans nom)";
    return {
      id: inv.id,
      name,
      prenom,
      nom,
      cote: inv.cote || "",
      categorie: inv.categorie || "",
      tableId: inv.table_id || "",
      giteId: inv.gite_id || "",
    };
  });

  // Décorations statiques par id, et par index (pour les seeds "t-1" vs "t1")
  const tableDecoById = Object.fromEntries((window.APP_DATA?.tables || []).map(t => [t.id, t]));
  const giteDecoById  = Object.fromEntries((window.APP_DATA?.gites  || []).map(g => [g.id, g]));

  const tables = rawTables.map((t, i) => {
    // Le seed backend utilise "t-1", l'APP_DATA "t1" : on tente les deux.
    const deco = tableDecoById[t.id] || tableDecoById[t.id?.replace("-", "")] || (window.APP_DATA?.tables || [])[i] || {};
    const guests = invites.filter(inv => inv.tableId === t.id).map(inv => inv.name);
    return {
      id: t.id,
      name: t.nom || deco.name || `Table ${i + 1}`,
      capacite: Number(t.capacite) || deco.seats || 8,
      seats: Number(t.capacite) || deco.seats || 8,
      note: t.notes || deco.note || "",
      color: deco.color || PALETTE_FALLBACK[i % PALETTE_FALLBACK.length],
      guests,
    };
  });

  const gites = rawGites.map((g, i) => {
    const deco = giteDecoById[g.id] || (window.APP_DATA?.gites || [])[i] || {};
    const occupants = invites.filter(inv => inv.giteId === g.id).map(inv => inv.name);
    return {
      id: g.id,
      name: g.nom || deco.name || g.id,
      beds: Number(g.lits) || deco.beds || 0,
      note: g.notes || "",
      inChateau: deco.inChateau !== false, // true par défaut si non spécifié
      occupants,
    };
  });

  // Listes plates pour fuzzy match
  const tableNameById = Object.fromEntries(tables.map(t => [t.id, t.name]));
  const giteNameById  = Object.fromEntries(gites.map(g => [g.id, g.name]));
  const allGuests = invites
    .filter(inv => inv.tableId)
    .map(inv => ({ name: inv.name, tableId: inv.tableId, tableName: tableNameById[inv.tableId] || inv.tableId }));
  const allSleepers = invites
    .filter(inv => inv.giteId)
    .map(inv => ({ name: inv.name, giteId: inv.giteId, giteName: giteNameById[inv.giteId] || inv.giteId }));

  return { invites, tables, gites, allGuests, allSleepers };
}

// Palette de fallback si l'APP_DATA n'a pas de décoration pour cet index
const PALETTE_FALLBACK = ["#B85A4E", "#7E8F75", "#BE9A48", "#9FA3CC", "#D88A6A", "#A4B49B", "#8E7128", "#E8C467", "#C8786E", "#B89055"];

// Forme "démo" : ce que l'APP_DATA fournit en placeholder (placement déjà
// inscrit dans APP_DATA.tables[i].guests et APP_DATA.gites[i].occupants).
function buildDemoShape() {
  const APP = window.APP_DATA || {};
  const invites = []; // on ne reconstitue pas la liste d'invités à partir du seed
  const tables = (APP.tables || []).map(t => ({
    id: t.id, name: t.name, capacite: t.seats, seats: t.seats,
    note: t.note || "", color: t.color, guests: t.guests || [],
  }));
  const gites = (APP.gites || []).map(g => ({
    id: g.id, name: g.name, beds: g.beds, note: "",
    inChateau: g.inChateau !== false,
    occupants: g.occupants || [],
  }));
  const allGuests   = APP.allGuests   || [];
  const allSleepers = APP.allSleepers || [];
  return { invites, tables, gites, allGuests, allSleepers };
}

function readCache() {
  try {
    const stamp = Number(localStorage.getItem(APP_DATA_CACHE_STAMP) || 0);
    if (Date.now() - stamp > APP_DATA_CACHE_TTL) return null;
    const cached = JSON.parse(localStorage.getItem(APP_DATA_CACHE_KEY) || "null");
    return cached || null;
  } catch { return null; }
}
function writeCache(payload) {
  try {
    localStorage.setItem(APP_DATA_CACHE_KEY, JSON.stringify(payload));
    localStorage.setItem(APP_DATA_CACHE_STAMP, String(Date.now()));
  } catch {}
}

async function fetchAppData() {
  if (!window.BACKEND) throw new Error("Backend non chargé");
  const res = await window.BACKEND.get("getAppData");
  if (!res?.ok) throw new Error(res?.error || "Réponse invalide");
  return res; // { invites, tables, gites }
}

// Hook React principal
function useAppBackend() {
  const demo = React.useMemo(() => buildDemoShape(), []);
  const [state, setState] = React.useState(() => {
    // Au mount : tente le cache pour afficher quelque chose tout de suite
    const cached = readCache();
    if (cached) {
      const shape = buildAppShape(cached.invites, cached.tables, cached.gites);
      return { ...shape, loading: true, source: "cache" };
    }
    return { ...demo, loading: true, source: "demo" };
  });

  React.useEffect(() => {
    let alive = true;
    (async () => {
      try {
        const payload = await fetchAppData();
        if (!alive) return;
        writeCache({ invites: payload.invites, tables: payload.tables, gites: payload.gites });
        const shape = buildAppShape(payload.invites, payload.tables, payload.gites);
        setState({ ...shape, loading: false, source: "backend" });
      } catch (e) {
        if (!alive) return;
        console.warn("[app] useAppBackend failed", e);
        // Garde le cache ou retombe sur démo
        const cached = readCache();
        if (cached) {
          const shape = buildAppShape(cached.invites, cached.tables, cached.gites);
          setState({ ...shape, loading: false, source: "cache" });
        } else {
          setState({ ...demo, loading: false, source: "demo" });
        }
      }
    })();
    return () => { alive = false; };
  }, [demo]);

  return state;
}

Object.assign(window, { useAppBackend, buildAppShape, buildDemoShape });
