/* data.jsx — načítanie reálnych dát zo SharePointu (nahrádza pôvodné hardkódované TIKETY/TECHNICI).
   window.HELPDESK_DATA má NA KONCI presne ten istý tvar ako predtým (SLA, STAVY, PRIORITY,
   KATEGORIE, PODKATEGORIE, TECHNICI, TIKETY) — vďaka tomu panels.jsx/conversation.jsx/
   details.jsx/stats.jsx nepotrebujú vedieť, že dáta už nie sú mock, ale zo SharePointu.
*/
(function () {
  "use strict";

  // Tieto zostávajú lokálne konštanty — zrkadlia SharePoint Choice polia, appka ich
  // nepotrebuje sťahovať (sú to len popisky/farebné mapovania použité v UI).
  const SLA = { "Kritická": 4, "Vysoká": 24, "Stredná": 72, "Nízka": 120 };
  const STAVY = ["Nový", "Priradený", "V riešení", "Čaká na zákazníka", "Vyriešený", "Zatvorený"];
  const PRIORITY = ["Nízka", "Stredná", "Vysoká", "Kritická"];
  const KATEGORIE = ["Hardvér", "Softvér", "Sieť", "Iné"];
  const PODKATEGORIE = {
    "Hardvér": ["Tlačiarne a periférie", "Hardvérové poruchy"],
    "Softvér": ["Heslá a prístupy", "E-mail a Outlook", "Inštalácie softvéru"],
    "Sieť": ["VPN a vzdialený prístup", "Sieť a internet", "Zmena nastavení konta"],
    "Iné": ["Iné"],
  };

  const FARBY_PALETA = ["#0f6cbd", "#8764b8", "#0e7a6b", "#c2410c", "#4f46e5", "#c50f1f"];
  function farbaZretazca(kluc) {
    let h = 0;
    for (let i = 0; i < kluc.length; i++) h = (h * 31 + kluc.charCodeAt(i)) >>> 0;
    return FARBY_PALETA[h % FARBY_PALETA.length];
  }
  function iniciuly(meno) {
    return (meno || "")
      .split(/\s+/)
      .filter(Boolean)
      .slice(0, 2)
      .map((s) => s[0].toUpperCase())
      .join("");
  }

  // Person polia (Konto/PriradenyTechnik/Autor/Technik) — overené empiricky cez konzolu na
  // reálnom tenante (plán, Riziko #2): Graph s $expand=fields($expand=PoleMeno) vráti pole
  // priamo ako REŤAZEC s celým menom (napr. "Jakub Pernecký"), NIE ako objekt s Email/LookupValue.
  // E-mail sa touto cestou nedá získať — appka preto páruje ľudí podľa mena, nie e-mailu.
  function personoveMeno(pole) {
    if (!pole) return null;
    if (typeof pole === "string") return pole;
    return pole.LookupValue || pole.Title || pole.DisplayName || pole.displayName || null;
  }

  function isoNaEpoch(iso) {
    return iso ? new Date(iso).getTime() : undefined;
  }

  function mapTechnik(item) {
    const f = item.fields || {};
    // Meno berieme z Konto (rozbalené Person pole = celé meno, napr. "Jakub Pernecký"),
    // NIE z Title — Title je v tomto zozname len skrátené meno použité v SharePoint UI
    // (napr. "Jakub"), čo by appke pokazilo zobrazovanie aj párovanie prihláseného usera.
    const meno = personoveMeno(f.Konto) || f.Title || "";
    // KontoLookupId = SharePoint LookupId osoby v User Information List danej lokality —
    // rovnaké ID sa používa pri zápise PriradenyTechnikLookupId/AutorLookupId na iných zoznamoch.
    const personLookupId = f.KontoLookupId != null ? String(f.KontoLookupId) : null;
    return {
      id: item.id,
      meno,
      rola: f.Rola || "Technik",
      aktivny: f.Aktivny !== false,
      personLookupId,
      iniciuly: iniciuly(meno),
      farba: farbaZretazca(personLookupId || meno || item.id),
    };
  }

  function najdiTechnikaPodlaPersonPola(technici, pole) {
    if (!pole) return null;
    const meno = personoveMeno(pole);
    if (!meno) return null;
    const t = technici.find((x) => (x.meno || "").toLowerCase() === meno.toLowerCase());
    return t || { meno }; // aspoň meno na zobrazenie, aj keď nie je v Technici zozname
  }

  function mapSprava(item, technici) {
    const f = item.fields || {};
    const autorZTechnici = najdiTechnikaPodlaPersonPola(technici, f.Autor);
    // "Prijatý e-mail" typicky nemá platného M365 Autora (externý zákazník) — použi meno žiadateľa.
    const autor = (autorZTechnici && autorZTechnici.meno) || f.ZiadatelMeno || personoveMeno(f.Autor) || "?";
    return {
      id: item.id,
      typ: f.TypSpravy,
      autor,
      cas: isoNaEpoch(f.Created),
      text: f.Text || "",
      // Prílohy jednotlivých správ zámerne vynechané v tejto fáze — hromadné dotiahnutie
      // príloh pre každú správu zvlášť by výrazne zvýšilo počet Graph volaní. Dá sa doplniť
      // rovnakým spôsobom ako prílohy tiketu (nižšie), keď bude endpoint príloh overený (plán, Riziko #1).
      prilohy: [],
    };
  }

  function mapTiket(item, technici, spravyPodlaCisla, prilohyPodlaId, casPodlaCisla) {
    const f = item.fields || {};
    const cislo = f.CisloTiketu;
    const technikObj = najdiTechnikaPodlaPersonPola(technici, f.PriradenyTechnik);
    return {
      _spItemId: item.id,
      cislo,
      predmet: f.Title || "",
      stav: f.Stav,
      priorita: f.Priorita,
      kategoria: f.Kategoria,
      podkategoria: f.Podkategoria || (PODKATEGORIE[f.Kategoria] || ["Iné"])[0],
      technik: technikObj ? technikObj.meno : null,
      ziadatelMeno: f.ZiadatelMeno || "",
      ziadatelEmail: f.ZiadatelEmail || "",
      kopia: f.Kopia || "",
      zdroj: f.Zdroj || "E-mail",
      eskalovany: !!f.Eskalovany,
      termin: isoNaEpoch(f.Termin),
      vytvorene: isoNaEpoch(item.createdDateTime),
      vyriesene: isoNaEpoch(f.DatumVyriesenia),
      prilohyTiketu: prilohyPodlaId[item.id] || [],
      komunikacia: spravyPodlaCisla[cislo] || [],
      celkovyCasMinut: (casPodlaCisla && casPodlaCisla[cislo]) || 0,
    };
  }

  function mapPrilohy(attachmentsResponse) {
    const zoznam = (attachmentsResponse && attachmentsResponse.value) || [];
    return zoznam.map((a) => ({
      nazov: a.name,
      velkost: a.size ? Math.round(a.size / 1024) + " kB" : "",
      typ: (a.name || "").split(".").pop(),
    }));
  }

  // SLA reset pri odpovedi zákazníkovi — overený vzorec z produkčného handoff dokumentu:
  // nový Termín = max(existujúci Termín, teraz + (SLA_hodiny − 24h)), nikdy nad (SLA − 1 deň).
  function computeNextTermin(existingTerminMs, priorita) {
    const slaMs = (SLA[priorita] || 72) * 3600 * 1000;
    const kandidat = Date.now() + (slaMs - 24 * 3600 * 1000);
    return Math.max(existingTerminMs || 0, kandidat);
  }

  // Opačné mapovanie: patch v existujúcom slovenskom tvare -> SharePoint polia pre PATCH.
  // Podkategoria/DatumVyriesenia stĺpce v SharePointe existujú (overené cez /columns —
  // interné názvy sa presne zhodujú), takže ich appka opäť zapisuje.
  function mapPatchNaSharePoint(patch, technici) {
    const out = {};
    if ("stav" in patch) out.Stav = patch.stav;
    if ("priorita" in patch) out.Priorita = patch.priorita;
    if ("kategoria" in patch) out.Kategoria = patch.kategoria;
    if ("podkategoria" in patch) out.Podkategoria = patch.podkategoria;
    if ("termin" in patch) out.Termin = patch.termin ? new Date(patch.termin).toISOString() : null;
    if ("eskalovany" in patch) out.Eskalovany = !!patch.eskalovany;
    if ("vyriesene" in patch) out.DatumVyriesenia = patch.vyriesene ? new Date(patch.vyriesene).toISOString() : null;
    if ("technik" in patch) {
      const t = patch.technik ? technici.find((x) => x.meno === patch.technik) : null;
      out.PriradenyTechnikLookupId = t && t.personLookupId ? t.personLookupId : null;
    }
    return out;
  }

  async function loadHelpdeskData() {
    const graph = window.HELPDESK_GRAPH;
    const [technicianItems, ticketItems, messageItems, casZaznamyItems] = await Promise.all([
      graph.listTechnicians(),
      graph.listTickets(),
      graph.listAllMessages(),
      graph.listAllTimeEntries(),
    ]);

    const TECHNICI = technicianItems.map(mapTechnik);

    const spravyPodlaCisla = {};
    for (const mi of messageItems) {
      const cislo = mi.fields && mi.fields.TiketCislo;
      if (!cislo) continue;
      (spravyPodlaCisla[cislo] = spravyPodlaCisla[cislo] || []).push(mapSprava(mi, TECHNICI));
    }
    for (const cislo in spravyPodlaCisla) spravyPodlaCisla[cislo].sort((a, b) => a.cas - b.cas);

    // Súčet odpracovaných minút podľa čísla tiketu (štopka aj ručné zadanie zapisujú
    // do rovnakého CasZaznamy zoznamu, appka ich len sčíta).
    const casPodlaCisla = {};
    for (const ci of casZaznamyItems) {
      const cislo = ci.fields && ci.fields.TiketCislo;
      if (!cislo) continue;
      casPodlaCisla[cislo] = (casPodlaCisla[cislo] || 0) + (Number(ci.fields.Minuty) || 0);
    }

    // Prílohy tiketu — jedno volanie na tiket. Ak Graph attachments endpoint v tomto
    // tenante nefunguje (plán, Riziko #1), zlyhanie sa potichu premení na prázdny zoznam,
    // aby to nezhodilo celé načítanie dát.
    const prilohyPodlaId = {};
    await Promise.all(
      ticketItems.map(async (ti) => {
        try {
          prilohyPodlaId[ti.id] = mapPrilohy(await graph.listAttachments(window.HELPDESK_CONFIG.LIST_ID.TICKETY, ti.id));
        } catch (e) {
          prilohyPodlaId[ti.id] = [];
        }
      })
    );

    const TIKETY = ticketItems.map((ti) => mapTiket(ti, TECHNICI, spravyPodlaCisla, prilohyPodlaId, casPodlaCisla));

    // Zoznam kategórií/podkategórií rozšírime o hodnoty reálne použité na tiketoch —
    // vlastné kategórie/podkategórie pridané cez "+ Nová možnosť" (ktorékoľvek technikom)
    // sa takto prirodzene "zapamätajú" pre všetkých pri ďalšom prihlásení, bez potreby
    // osobitného zoznamu kategórií v SharePointe.
    const KATEGORIE_VSETKY = Array.from(new Set([...KATEGORIE, ...TIKETY.map((t) => t.kategoria).filter(Boolean)]));
    const PODKATEGORIE_VSETKY = {};
    for (const k of KATEGORIE_VSETKY) {
      const zaklad = PODKATEGORIE[k] || ["Iné"];
      const pouzite = TIKETY.filter((t) => t.kategoria === k).map((t) => t.podkategoria).filter(Boolean);
      PODKATEGORIE_VSETKY[k] = Array.from(new Set([...zaklad, ...pouzite]));
    }

    return { TECHNICI, SLA, STAVY, PRIORITY, KATEGORIE: KATEGORIE_VSETKY, PODKATEGORIE: PODKATEGORIE_VSETKY, TIKETY };
  }

  window.loadHelpdeskData = loadHelpdeskData;
  window.computeNextTermin = computeNextTermin;
  window.mapPatchNaSharePoint = mapPatchNaSharePoint;
})();
