/* graph.jsx — tenký wrapper nad Microsoft Graph REST volaniami pre SharePoint zoznamy.
   Žiadny bundler, žiadny backend — appka volá graph.microsoft.com priamo z prehliadača
   s tokenom prihláseného technika (window.HELPDESK_AUTH.getToken()).
*/
(function () {
  "use strict";

  const cfg = window.HELPDESK_CONFIG;
  const GRAPH_BASE = "https://graph.microsoft.com/v1.0";

  async function graphFetch(path, options) {
    const token = await window.HELPDESK_AUTH.getToken();
    const res = await fetch(GRAPH_BASE + path, {
      ...options,
      headers: {
        Authorization: "Bearer " + token,
        "Content-Type": "application/json",
        ...(options && options.headers),
      },
    });
    if (res.status === 429) {
      // Throttling — Graph hovorí, koľko sekúnd počkať. Skús raz znova.
      const retryAfter = Number(res.headers.get("Retry-After") || "2");
      await new Promise((r) => setTimeout(r, retryAfter * 1000));
      return graphFetch(path, options);
    }
    if (!res.ok) {
      let message = res.status + " " + res.statusText;
      try {
        const body = await res.json();
        if (body && body.error && body.error.message) message = body.error.message;
      } catch (_) {}
      throw new Error("Graph API chyba: " + message);
    }
    if (res.status === 204) return null; // No Content (napr. po PATCH)
    return res.json();
  }

  // Vytiahne všetky položky zoznamu, nasleduje @odata.nextLink kým existuje.
  // expandFields: názvy Person/Lookup polí, ktoré chceme rozbaliť na skutočný objekt
  // (LookupValue/Email) — bez toho Graph vráti len "{Pole}LookupId": "19" (číslo), viď
  // plán, Riziko #2 (overené na reálnom tenante: Konto/Autor/PriradenyTechnik/Technik
  // sú Person polia a BEZ $expand sa nedá dopátrať k e-mailu).
  async function listAllItems(listId, query, expandFields) {
    const expandPart = expandFields && expandFields.length ? "($expand=" + expandFields.join(",") + ")" : "";
    let path = "/sites/" + cfg.SITE_ID + "/lists/" + listId + "/items?expand=fields" + expandPart + (query || "");
    let items = [];
    while (path) {
      const page = await graphFetch(path.startsWith("http") ? path.replace(GRAPH_BASE, "") : path);
      items = items.concat(page.value || []);
      path = page["@odata.nextLink"] ? page["@odata.nextLink"].replace(GRAPH_BASE, "") : null;
    }
    return items;
  }

  function listTickets() {
    return listAllItems(cfg.LIST_ID.TICKETY, "&$top=200", ["PriradenyTechnik"]);
  }

  // Jedno volanie na celý zoznam Komunikacia — zoskupenie podľa TiketCislo sa robí
  // v JS (v data.jsx), namiesto samostatného filtrovaného requestu na každý tiket.
  function listAllMessages() {
    return listAllItems(cfg.LIST_ID.KOMUNIKACIA, "&$top=200", ["Autor"]);
  }

  function listTechnicians() {
    return listAllItems(cfg.LIST_ID.TECHNICI, "&$top=200", ["Konto"]);
  }

  function listTimeEntries(ticketCislo) {
    const filter = "&$filter=" + encodeURIComponent("fields/TiketCislo eq '" + ticketCislo + "'");
    return listAllItems(cfg.LIST_ID.CAS_ZAZNAMY, filter, ["Technik"]);
  }

  // Jedno volanie na celý zoznam CasZaznamy (rovnaký prístup ako listAllMessages) —
  // zoskupenie a súčet minút podľa TiketCislo sa robí v JS (data.jsx), namiesto
  // samostatného filtrovaného requestu na každý tiket.
  function listAllTimeEntries() {
    return listAllItems(cfg.LIST_ID.CAS_ZAZNAMY, "&$top=200", ["Technik"]);
  }

  function patchTicket(itemId, fieldsPatch) {
    return graphFetch(
      "/sites/" + cfg.SITE_ID + "/lists/" + cfg.LIST_ID.TICKETY + "/items/" + itemId + "/fields",
      { method: "PATCH", body: JSON.stringify(fieldsPatch) }
    );
  }

  function createMessage(fields) {
    return graphFetch("/sites/" + cfg.SITE_ID + "/lists/" + cfg.LIST_ID.KOMUNIKACIA + "/items", {
      method: "POST",
      body: JSON.stringify({ fields }),
    });
  }

  function createTimeEntry(fields) {
    return graphFetch("/sites/" + cfg.SITE_ID + "/lists/" + cfg.LIST_ID.CAS_ZAZNAMY + "/items", {
      method: "POST",
      body: JSON.stringify({ fields }),
    });
  }

  function listAttachments(listId, itemId) {
    return graphFetch("/sites/" + cfg.SITE_ID + "/lists/" + listId + "/items/" + itemId + "/attachments").catch(
      () => ({ value: [] })
    );
  }

  // POZOR: Graph podpora pre klasické SharePoint list-item Attachments je historicky
  // nekonzistentná/obmedzená (viď plán, riziko #1). Overiť ako prvé cez Graph Explorer
  // proti reálnemu tenantu, skôr než sa appka spolieha na túto funkciu v UI.
  async function uploadAttachment(listId, itemId, file) {
    const token = await window.HELPDESK_AUTH.getToken();
    const buf = await file.arrayBuffer();
    const res = await fetch(
      GRAPH_BASE + "/sites/" + cfg.SITE_ID + "/lists/" + listId + "/items/" + itemId + "/attachments",
      {
        method: "POST",
        headers: {
          Authorization: "Bearer " + token,
          "Content-Type": "application/json",
        },
        body: JSON.stringify({ name: file.name, contentBytes: btoa(String.fromCharCode(...new Uint8Array(buf))) }),
      }
    );
    if (!res.ok) throw new Error("Nahratie prílohy zlyhalo: " + res.status + " " + res.statusText);
    return res.json();
  }

  window.HELPDESK_GRAPH = {
    listTickets,
    listAllMessages,
    listTechnicians,
    listTimeEntries,
    listAllTimeEntries,
    patchTicket,
    createMessage,
    createTimeEntry,
    listAttachments,
    uploadAttachment,
  };
})();
