// Données ElsiaScreen — récupérées depuis le backend au lieu d'être mockées en dur.

// ---- Constantes statiques (planning grid + stats placeholder) ----
const HOURS = ["07h", "08h", "09h", "10h", "11h", "12h", "13h", "14h", "15h", "16h", "17h", "18h", "19h"];
const DAYS  = ["Lun. 18", "Mar. 19", "Mer. 20", "Jeu. 21", "Ven. 22"];

const STATS_BARS = [
  { day: "Lun 12", value: 184 }, { day: "Mar 13", value: 212 },
  { day: "Mer 14", value: 198 }, { day: "Jeu 15", value: 247 },
  { day: "Ven 16", value: 268 }, { day: "Sam 17", value: 42 },
  { day: "Dim 18", value: 38  },
];
const STATS_TOP = [
  { label: "Boucle matinée — Accueil",   value: 1284, share: 38 },
  { label: "Boucle après-midi",          value: 942,  share: 28 },
  { label: "Veille technique",           value: 421,  share: 13 },
  { label: "All-Hands mensuel",          value: 312,  share: 9  },
  { label: "Rappels QSE",                value: 198,  share: 6  },
  { label: "Autres",                     value: 196,  share: 6  },
];

// ---- Pré-initialisation synchrone de window.DATA ----
// Les view-*.jsx font `const { ... } = window.DATA` au moment du parse, donc
// l'objet doit exister AVANT que ces scripts soient évalués.
// bootElsia() le remplacera plus tard avec les vraies données fetchées.
window.DATA = {
  MEDIA_FILES:     [],
  PLAYLISTS:       [],
  SCREENS:         [],
  HOURS, DAYS,
  SCHEDULE_BLOCKS: [],
  ACTIVITY:        [],
  STATS_BARS, STATS_TOP,
};

// ---- Formatters ----
function formatSize(bytes) {
  if (!bytes) return "—";
  if (bytes < 1024) return bytes + " o";
  if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + " Ko";
  return (bytes / (1024 * 1024)).toFixed(1) + " Mo";
}

function formatRelativeDate(unixSec) {
  if (!unixSec) return "—";
  const now = Date.now() / 1000;
  const diff = now - unixSec;
  if (diff < 60) return "À l'instant";
  if (diff < 3600) return `Il y a ${Math.round(diff / 60)} min`;
  const d = new Date(unixSec * 1000);
  const today = new Date(); today.setHours(0, 0, 0, 0);
  const that  = new Date(d); that.setHours(0, 0, 0, 0);
  const daysDiff = Math.round((today - that) / (1000 * 60 * 60 * 24));
  const time = d.toLocaleTimeString("fr-FR", { hour: "2-digit", minute: "2-digit" });
  if (daysDiff === 0) return `Aujourd'hui, ${time}`;
  if (daysDiff === 1) return `Hier, ${time}`;
  if (daysDiff < 7) return d.toLocaleDateString("fr-FR", { weekday: "short", day: "numeric", month: "short" });
  return d.toLocaleDateString("fr-FR", { day: "numeric", month: "short", year: "numeric" });
}

// ---- Adapters API → forme attendue par le proto ----
function adaptMedia(m) {
  return {
    id: m.id, name: m.name, type: m.type,
    size: m.size_bytes ? formatSize(m.size_bytes) : "—",
    duration: m.duration_display || "—",
    added: formatRelativeDate(m.created_at),
    author: m.author || "—",
    pages: m.pages || 1,
    thumb: m.type,
    tags: Array.isArray(m.tags) ? m.tags : [],
  };
}

function adaptPlaylist(p) {
  const items = Object.values(p.zones || {}).reduce((s, arr) => s + (arr?.length || 0), 0);
  return {
    id: p.id,
    name: p.name,
    items,
    duration: p.duration_display || "—",
    active: !!p.is_active,
    lastUsed: p.is_active ? "En diffusion" : "—",
    schedule: p.schedule || "Non planifié",
    color: p.color || "#60A5FA",
    layout: p.layout || "quad",
    zones: Object.fromEntries(
      ["A", "B", "C", "D"].map((z) => [
        z,
        (p.zones?.[z] || []).map((it) => ({
          id: it.id, mediaId: it.media_id,
          title: it.media_name,
          type: it.media_type,
          duration: it.duration_display || "—",
          storage_path: it.media_storage,
          external_url: it.media_external_url,
          has_file: !!it.media_storage,
        })),
      ])
    ),
  };
}

function adaptScreen(s) {
  return {
    id: s.id, name: s.name, location: s.location || "—",
    resolution: s.resolution || "1920 × 1080",
    status: s.status || "offline",
    playing: "—",
    uptime: s.last_seen_at ? formatRelativeDate(s.last_seen_at) : "—",
    brightness: s.brightness || 0,
    ip: s.ip || "—",
  };
}

function adaptScheduleBlock(b) {
  return { day: b.day, h: b.hour_start, span: b.hour_span, label: b.label || "", color: b.color || "#60A5FA", playlist: b.playlist_id };
}

function adaptActivity(a) {
  return { time: formatRelativeDate(a.created_at), who: a.who || "Système", action: a.action || "", target: a.target || "", type: a.type || "upload" };
}

// ---- Client API exposé globalement pour les mutations ----
async function apiCall(method, path, body) {
  const opts = { method, headers: {} };
  if (body !== undefined) {
    if (body instanceof FormData) opts.body = body;
    else { opts.headers["Content-Type"] = "application/json"; opts.body = JSON.stringify(body); }
  }
  const res = await fetch(path, opts);
  if (!res.ok) throw new Error(`${res.status} ${await res.text()}`);
  if (res.status === 204) return null;
  return res.json();
}

window.ELSIA_API = {
  // Media
  listMedia:        ()          => apiCall("GET",    "/api/media"),
  uploadMedia:      (file, meta = {}) => {
    const fd = new FormData(); fd.append("file", file);
    for (const [k, v] of Object.entries(meta)) fd.append(k, typeof v === "string" ? v : JSON.stringify(v));
    return apiCall("POST", "/api/media", fd);
  },
  addExternalMedia: (data)      => apiCall("POST",   "/api/media/external", data),
  deleteMedia:      (id)        => apiCall("DELETE", `/api/media/${id}`),
  mediaFileUrl:     (id)        => `/api/media/${id}/file`,

  // Playlists
  listPlaylists:    ()          => apiCall("GET",    "/api/playlists"),
  getPlaylist:      (id)        => apiCall("GET",    `/api/playlists/${id}`),
  createPlaylist:   (data)      => apiCall("POST",   "/api/playlists", data),
  updatePlaylist:   (id, data)  => apiCall("PATCH",  `/api/playlists/${id}`, data),
  activatePlaylist: (id)        => apiCall("POST",   `/api/playlists/${id}/activate`),
  deletePlaylist:   (id)        => apiCall("DELETE", `/api/playlists/${id}`),
  setPlaylistItems: (id, zones) => apiCall("PUT",    `/api/playlists/${id}/items`, { zones }),

  // Screens / Schedule / Activity
  listScreens:      ()          => apiCall("GET",    "/api/screens"),
  createScreen:     (data)      => apiCall("POST",   "/api/screens", data),
  updateScreen:     (id, data)  => apiCall("PATCH",  `/api/screens/${id}`, data),
  deleteScreen:     (id)        => apiCall("DELETE", `/api/screens/${id}`),
  listSchedule:     ()          => apiCall("GET",    "/api/schedule"),
  createScheduleBlock: (data)   => apiCall("POST",   "/api/schedule", data),
  deleteScheduleBlock: (id)     => apiCall("DELETE", `/api/schedule/${id}`),
  listActivity:     (limit = 50)=> apiCall("GET",    `/api/activity?limit=${limit}`),
};

// ---- WebSocket pour les updates temps réel ----
function connectWs() {
  const proto = location.protocol === "https:" ? "wss" : "ws";
  const ws = new WebSocket(`${proto}://${location.host}/ws?role=controller`);
  ws.onopen    = () => console.log("[ws] connecté");
  ws.onclose   = () => { console.warn("[ws] déconnecté, retry dans 2s"); setTimeout(connectWs, 2000); };
  ws.onerror   = (e) => console.error("[ws] erreur", e);
  ws.onmessage = (ev) => {
    try {
      const msg = JSON.parse(ev.data);
      window.dispatchEvent(new CustomEvent("elsia:ws", { detail: msg }));
    } catch {}
  };
  window.ELSIA_WS = ws;
}

// ---- Boot : fetch toutes les données, peuple window.DATA, render React ----
async function bootElsia() {
  try {
    const [mediaRaw, playlistsRaw, screensRaw, scheduleRaw, activityRaw] = await Promise.all([
      window.ELSIA_API.listMedia(),
      window.ELSIA_API.listPlaylists(),
      window.ELSIA_API.listScreens(),
      window.ELSIA_API.listSchedule(),
      window.ELSIA_API.listActivity(50),
    ]);

    // Charger les détails de chaque playlist (avec ses zones)
    const playlistsDetailed = await Promise.all(
      playlistsRaw.map((p) => window.ELSIA_API.getPlaylist(p.id))
    );

    window.DATA = {
      MEDIA_FILES:     mediaRaw.map(adaptMedia),
      PLAYLISTS:       playlistsDetailed.map(adaptPlaylist),
      SCREENS:         screensRaw.map(adaptScreen),
      HOURS, DAYS,
      SCHEDULE_BLOCKS: scheduleRaw.map(adaptScheduleBlock),
      ACTIVITY:        activityRaw.map(adaptActivity),
      STATS_BARS, STATS_TOP,
    };

    console.log("[boot] DATA chargée", {
      media: window.DATA.MEDIA_FILES.length,
      playlists: window.DATA.PLAYLISTS.length,
      screens: window.DATA.SCREENS.length,
    });

    connectWs();

    // Render React maintenant que les données sont prêtes
    ReactDOM.createRoot(document.getElementById("root")).render(<App />);
  } catch (err) {
    console.error("[boot] échec", err);
    document.getElementById("root").innerHTML = `
      <div style="font-family: system-ui; padding: 32px; color: #F87171; text-align: center;">
        <h1 style="font-size: 18px; margin-bottom: 8px;">Erreur de chargement</h1>
        <p style="color: #9CA3AF; font-size: 13px;">Impossible de joindre le backend.</p>
        <pre style="background: #1a1a1a; padding: 12px; border-radius: 6px; text-align: left; max-width: 600px; margin: 16px auto; font-size: 11px; color: #fca5a5;">${err.message}</pre>
        <button onclick="location.reload()" style="margin-top: 16px; padding: 8px 16px; background: #F5A623; color: #000; border: none; border-radius: 6px; cursor: pointer; font-weight: 600;">Réessayer</button>
      </div>
    `;
  }
}

// Le boot est déclenché manuellement par app.jsx après que App() soit défini
window.bootElsia = bootElsia;
