/* app.jsx — hlavná aplikácia helpdesku PROPLUSCO */

const ACCENTS = {
  blue:   { a: "#0f6cbd", h: "#115ea3", p: "#0c3b5e", tl: "#e8f1fb", td: "#0c2c45" },
  teal:   { a: "#0e7a6b", h: "#0c6b5d", p: "#08493f", tl: "#e3f3f0", td: "#0a2e29" },
  indigo: { a: "#4f46e5", h: "#4338ca", p: "#3730a3", tl: "#ecebfd", td: "#222046" },
  violet: { a: "#8764b8", h: "#7857a8", p: "#5c4286", tl: "#f1ecf8", td: "#2b2140" },
  orange: { a: "#c2410c", h: "#9a3412", p: "#7c2d12", tl: "#fdeee4", td: "#3a1e0e" },
};

const TWEAK_DEFAULTS = /*EDITMODE-BEGIN*/{
  "accent": "blue",
  "dark": false,
  "density": "regular"
}/*EDITMODE-END*/;

function applyTheme(t) {
  const root = document.documentElement;
  root.setAttribute("data-theme", t.dark ? "dark" : "light");
  const ac = ACCENTS[t.accent] || ACCENTS.blue;
  root.style.setProperty("--accent", ac.a);
  root.style.setProperty("--accent-hover", ac.h);
  root.style.setProperty("--accent-press", ac.p);
  root.style.setProperty("--accent-tint", t.dark ? ac.td : ac.tl);
  // hustota
  const dens = { compact: { fs: "13px", pad: "8px" }, regular: { fs: "14px", pad: "12px" }, comfy: { fs: "15px", pad: "16px" } }[t.density] || {};
  document.body.style.fontSize = dens.fs;
  root.style.setProperty("--row-pad", dens.pad);
}

/* ---------- toast ---------- */
function Toast({ toast }) {
  if (!toast) return null;
  const icons = { success: "checkCircle", info: "mail", warn: "warning" };
  const farby = { success: "var(--green)", info: "var(--accent)", warn: "var(--p-vysoka)" };
  return (
    <div style={{
      position: "fixed", bottom: 22, left: "50%", transform: "translateX(-50%)", zIndex: 200,
      display: "flex", alignItems: "center", gap: 10, padding: "11px 16px", borderRadius: "var(--radius)",
      background: "var(--surface)", border: "1px solid var(--stroke)", boxShadow: "var(--shadow-lg)",
      fontSize: 13.5, fontWeight: 600, color: "var(--text)", animation: "hd-fade .2s ease", maxWidth: "90vw",
    }}>
      <span style={{ color: farby[toast.kind], display: "inline-flex" }}><Icon name={icons[toast.kind]} size={18} /></span>
      {toast.text}
    </div>
  );
}

/* ---------- prihlásenie / načítavanie ---------- */
function CentrovanaSprava({ text }) {
  return (
    <div style={{ height: "100vh", display: "flex", alignItems: "center", justifyContent: "center", color: "var(--text-2)", fontSize: 14, fontWeight: 600, background: "var(--bg)" }}>
      {text}
    </div>
  );
}

function LoginScreen({ onLogin, error }) {
  const [busy, setBusy] = useState(false);
  const klik = async () => {
    setBusy(true);
    try { await onLogin(); } catch (e) { setBusy(false); }
  };
  return (
    <div style={{ height: "100vh", display: "flex", alignItems: "center", justifyContent: "center", background: "var(--bg)" }}>
      <div style={{ textAlign: "center", padding: 32, maxWidth: 360 }}>
        <div style={{ width: 52, height: 52, borderRadius: 13, background: "var(--accent)", display: "flex", alignItems: "center", justifyContent: "center", color: "#fff", margin: "0 auto 18px", boxShadow: "var(--shadow-md)" }}>
          <Icon name="mail" size={26} />
        </div>
        <div style={{ fontSize: 18, fontWeight: 700, marginBottom: 4 }}>Helpdesk PROPLUSCO</div>
        <div style={{ fontSize: 13, color: "var(--text-2)", marginBottom: 20 }}>Prihlás sa firemným Microsoft kontom.</div>
        <Btn kind="primary" icon="person" onClick={klik} disabled={busy} full>{busy ? "Prihlasujem…" : "Prihlásiť sa cez Microsoft"}</Btn>
        {error && <div style={{ marginTop: 14, fontSize: 12.5, color: "var(--red)" }}>{error}</div>}
      </div>
    </div>
  );
}

/* ---------- top bar ---------- */
function TopBar({ jeAdmin, ja, onRefresh, refreshing, t, setTweak, obrazovka, setObrazovka, onLogout }) {
  const nav = [
    { id: "kom", label: "Komunikácia", icon: "mail" },
    { id: "stat", label: "Štatistika", icon: "chart" },
  ];
  if (jeAdmin) nav.push({ id: "admin", label: "Správa tiketov", icon: "settings" });
  return (
    <header style={{
      display: "flex", alignItems: "center", gap: 16, padding: "0 16px", height: 56, flex: "0 0 auto",
      background: "var(--surface)", borderBottom: "1px solid var(--stroke)", zIndex: 10,
    }}>
      <div style={{ display: "flex", alignItems: "center", gap: 11 }}>
        <div style={{ width: 34, height: 34, borderRadius: 9, background: "var(--accent)", display: "flex", alignItems: "center", justifyContent: "center", color: "#fff", boxShadow: "var(--shadow-sm)" }}>
          <Icon name="mail" size={19} />
        </div>
        <div style={{ lineHeight: 1.15 }}>
          <div style={{ fontSize: 15, fontWeight: 700, letterSpacing: "-.01em" }}>Helpdesk</div>
          <div style={{ fontSize: 11, color: "var(--text-3)", fontWeight: 600 }}>PROPLUSCO spol. s r. o.</div>
        </div>
      </div>

      <nav className="hd-nav" style={{ display: "flex", gap: 2, marginLeft: 10 }}>
        {nav.map((n, i) => {
          const aktiv = n.id === obrazovka;
          const klik = n.id === "admin" ? undefined : () => setObrazovka(n.id);
          return (
            <button key={n.id} onClick={klik} title={n.id === "admin" ? n.label + " (ukážka)" : n.label} style={{
              display: "inline-flex", alignItems: "center", gap: 7, padding: "8px 13px", borderRadius: "var(--radius-sm)",
              border: "none", background: aktiv ? "var(--accent-tint)" : "transparent", color: aktiv ? "var(--accent)" : "var(--text-2)",
              fontSize: 13.5, fontWeight: 600, transition: "background .12s",
              opacity: n.id === "admin" ? .6 : 1,
            }} onMouseEnter={(e) => { if (!aktiv) e.currentTarget.style.background = "var(--surface-3)"; }} onMouseLeave={(e) => { if (!aktiv) e.currentTarget.style.background = "transparent"; }}>
              <Icon name={n.icon} size={16} /> <span className="hd-nav-label">{n.label}</span>
            </button>
          );
        })}
      </nav>

      <div style={{ marginLeft: "auto", display: "flex", alignItems: "center", gap: 4 }}>
        <button onClick={onRefresh} title="Obnoviť dáta" style={{
          display: "inline-flex", alignItems: "center", justifyContent: "center", width: 34, height: 34, borderRadius: "var(--radius-sm)",
          border: "none", background: "transparent", color: "var(--text-2)",
        }} onMouseEnter={(e) => e.currentTarget.style.background = "var(--surface-3)"} onMouseLeave={(e) => e.currentTarget.style.background = "transparent"}>
          <span style={{ display: "inline-flex", animation: refreshing ? "hd-spin .6s linear" : "none" }}><Icon name="refresh" size={17} /></span>
        </button>
        <IconBtn name={t.dark ? "sun" : "moon"} title={t.dark ? "Svetlý režim" : "Tmavý režim"} onClick={() => setTweak("dark", !t.dark)} size={17} />
        <div style={{ width: 1, height: 24, background: "var(--stroke)", margin: "0 6px" }} />
        <div style={{ display: "flex", alignItems: "center", gap: 9, paddingRight: 4 }}>
          <Avatar meno={ja.meno} farba={ja.farba} size={32} />
          <div className="hd-user" style={{ lineHeight: 1.2 }}>
            <div style={{ fontSize: 12.5, fontWeight: 700 }}>{ja.meno}</div>
            <div style={{ fontSize: 11, color: "var(--text-3)", fontWeight: 600 }}>{ja.rola === "Admin" ? "Administrátor" : "Technik"}</div>
          </div>
          <IconBtn name="close" title="Odhlásiť sa" onClick={onLogout} size={16} />
        </div>
      </div>
    </header>
  );
}

/* ====================== HLAVNÁ APP ====================== */
function App({ initialData, ja, reloadData }) {
  const [t, setTweak] = useTweaks(TWEAK_DEFAULTS);
  useEffect(() => { applyTheme(t); }, [t.accent, t.dark, t.density]);

  const { TECHNICI } = initialData;
  const jeAdmin = ja.rola === "Admin";

  const [tikety, setTikety] = useState(() => initialData.TIKETY);
  // Po refreshi (reloadData) Root pošle nové initialData — premietni ich do lokálneho stavu.
  useEffect(() => { setTikety(initialData.TIKETY); }, [initialData]);
  // Nech window.HELPDESK_DATA/HELPDESK_STATS vždy zodpovedajú aktuálnemu (aj optimisticky
  // upravenému) zoznamu tiketov — stats.jsx číta len z window.HELPDESK_STATS.
  useEffect(() => {
    window.HELPDESK_DATA = { ...window.HELPDESK_DATA, TIKETY: tikety, TECHNICI };
    window.computeHelpdeskStats();
  }, [tikety, TECHNICI]);

  const [vybrane, setVybrane] = useState(() => (initialData.TIKETY[0] || {}).cislo);
  const [now, setNow] = useState(Date.now());
  const [detailOpen, setDetailOpen] = useState(true);
  const [mobileView, setMobileView] = useState("list"); // list | conv
  const [refreshing, setRefreshing] = useState(false);
  const [obrazovka, setObrazovka] = useState("kom"); // kom | stat
  const [toast, setToast] = useState(null);
  const toastTimer = useRef(null);

  // tmrTik — odpočet SLA každú sekundu
  useEffect(() => {
    const id = setInterval(() => setNow(Date.now()), 1000);
    return () => clearInterval(id);
  }, []);

  // Poznámka k poradiu: `tiket` môže byť undefined (prázdny SharePoint) — všetky hooky
  // nižšie sa ale volajú VŽDY, bez ohľadu na to (Rules of Hooks). Chýbajúci tiket sa rieši
  // až v samotnom JSX na konci, nie skorým "return" uprostred komponenty.
  const tiket = tikety.find((x) => x.cislo === vybrane) || tikety[0];

  const flash = useCallback((text, kind = "success") => {
    setToast({ text, kind });
    if (toastTimer.current) clearTimeout(toastTimer.current);
    toastTimer.current = setTimeout(() => setToast(null), 3200);
  }, []);

  // Optimistická lokálna zmena + zápis do SharePointu na pozadí. Pri zlyhaní sa lokálna
  // zmena vráti späť a zobrazí sa chybový toast (namiesto tichého rozídenia sa appky od SharePointu).
  const patchTiket = useCallback((cislo, patch) => {
    const predchadzajuci = tikety.find((x) => x.cislo === cislo);
    if (!predchadzajuci) return;
    const patchObj = typeof patch === "function" ? patch(predchadzajuci) : patch;
    setTikety((arr) => arr.map((x) => (x.cislo === cislo ? { ...x, ...patchObj } : x)));
    const fields = window.mapPatchNaSharePoint(patchObj, TECHNICI);
    window.HELPDESK_GRAPH.patchTicket(predchadzajuci._spItemId, fields).catch((e) => {
      setTikety((arr) => arr.map((x) => (x.cislo === cislo ? predchadzajuci : x)));
      flash("Zápis do SharePointu zlyhal: " + e.message, "warn");
    });
  }, [tikety, TECHNICI, flash]);

  const onVybrat = (cislo) => { setVybrane(cislo); setMobileView("conv"); };

  // Odoslanie/poznámka NIE JE optimistická (vytvára novú položku + nahráva prílohy) —
  // počká na SharePoint, kým sa správa zobrazí, aby nevznikli duplicitné/rozídené ID.
  const pridajSpravu = async (typ, text, prilohy) => {
    const zoznamPrilohNaZobrazenie = (prilohy || []).map((p) => ({ nazov: p.nazov, velkost: p.velkost, typ: p.typ }));
    const jeOdpoved = typ === "Odpoveď zákazníkovi";
    const fields = {
      Title: tiket.cislo,
      TiketCislo: tiket.cislo,
      TypSpravy: typ,
      Text: text,
      AutorLookupId: ja.personLookupId,
    };
    const vytvorenaPolozka = await window.HELPDESK_GRAPH.createMessage(fields);
    for (const p of prilohy || []) {
      if (p.file) await window.HELPDESK_GRAPH.uploadAttachment(window.HELPDESK_CONFIG.LIST_ID.KOMUNIKACIA, vytvorenaPolozka.id, p.file);
    }

    // SLA reset platí pri OBOCH typoch správ (odpoveď aj interná poznámka) — presne ako
    // v pôvodnom systéme (frmOdpoved.OnSuccess bežal rovnako pre btnSend aj btnNote).
    // Zmena stavu na "V riešení" nižšie je ale len pri odpovedi zákazníkovi.
    const novaTerminPatch = { termin: window.computeNextTermin(tiket.termin, tiket.priorita), eskalovany: false };
    await window.HELPDESK_GRAPH.patchTicket(tiket._spItemId, window.mapPatchNaSharePoint(novaTerminPatch, TECHNICI));

    const sprava = { id: vytvorenaPolozka.id, typ, autor: ja.meno, cas: Date.now(), text, prilohy: zoznamPrilohNaZobrazenie };
    setTikety((arr) => arr.map((x) => {
      if (x.cislo !== tiket.cislo) return x;
      const novyStav = jeOdpoved && ["Nový", "Priradený"].includes(x.stav) ? "V riešení" : x.stav;
      return { ...x, ...novaTerminPatch, komunikacia: [...x.komunikacia, sprava], stav: novyStav };
    }));
  };

  const actions = {
    zmenaStavu: (v) => { patchTiket(tiket.cislo, { stav: v, vyriesene: v === "Vyriešený" ? Date.now() : undefined }); flash("Stav zmenený na „" + v + "“", "info"); },
    zmenaPriority: (v) => { patchTiket(tiket.cislo, { priorita: v }); flash("Priorita nastavená na „" + v + "“", "info"); },
    zmenaKategorie: (v) => { const { PODKATEGORIE } = window.HELPDESK_DATA; const prve = (PODKATEGORIE[v] || ["Iné"])[0]; patchTiket(tiket.cislo, { kategoria: v, podkategoria: prve }); },
    zmenaPodkategorie: (v) => { patchTiket(tiket.cislo, { podkategoria: v }); },
    // Nová kategória/podkategória zadaná používateľom cez "+ Nová možnosť" v Selecte —
    // pridá sa do zoznamu možností v tejto appke (naprieč tiketami, kým appka beží).
    // Trvalo sa "zapamätá" prirodzene aj naprieč reloadmi/inými technikmi, lebo dropdown
    // vždy zobrazuje aj hodnoty reálne použité na už uložených tiketoch (viď data.jsx).
    pridatKategoriu: (v) => {
      const d = window.HELPDESK_DATA;
      if (!d.KATEGORIE.includes(v)) d.KATEGORIE = [...d.KATEGORIE, v];
      if (!d.PODKATEGORIE[v]) d.PODKATEGORIE = { ...d.PODKATEGORIE, [v]: ["Iné"] };
    },
    pridatPodkategoriu: (kategoria, v) => {
      const d = window.HELPDESK_DATA;
      const zoznam = d.PODKATEGORIE[kategoria] || [];
      if (!zoznam.includes(v)) d.PODKATEGORIE = { ...d.PODKATEGORIE, [kategoria]: [...zoznam, v] };
    },
    priradit: (meno) => { patchTiket(tiket.cislo, { technik: meno, stav: meno && tiket.stav === "Nový" ? "Priradený" : tiket.stav }); flash(meno ? "Tiket priradený: " + meno : "Tiket uvoľnený", "info"); },
    prevziat: () => { patchTiket(tiket.cislo, { technik: ja.meno, stav: "Priradený" }); flash("Prevzali ste tiket " + tiket.cislo, "success"); },
    uvolnit: () => { patchTiket(tiket.cislo, { technik: null, stav: "Nový" }); flash("Tiket uvoľnený", "info"); },
    vyriesit: () => { patchTiket(tiket.cislo, { stav: "Vyriešený", vyriesene: Date.now(), eskalovany: false }); flash("Tiket označený ako vyriešený ✓", "success"); },
    zatvorit: () => { patchTiket(tiket.cislo, { stav: "Zatvorený" }); flash("Tiket zatvorený", "info"); },
    znovuOtvorit: () => { patchTiket(tiket.cislo, { stav: "V riešení", vyriesene: undefined }); flash("Tiket znovu otvorený", "info"); },
    zaznamCasu: (minuty) => {
      const cisloTiketu = tiket.cislo;
      window.HELPDESK_GRAPH.createTimeEntry({
        Title: cisloTiketu + " " + new Date().toLocaleString("sk-SK"),
        TiketCislo: cisloTiketu,
        TechnikLookupId: ja.personLookupId,
        Minuty: minuty,
        Datum: new Date().toISOString(),
      })
        .then(() => {
          setTikety((arr) => arr.map((x) => (x.cislo === cisloTiketu ? { ...x, celkovyCasMinut: (x.celkovyCasMinut || 0) + minuty } : x)));
          flash("Zaznamenaný čas: " + minuty + " min", "success");
        })
        .catch((e) => flash("Zápis času zlyhal: " + e.message, "warn"));
    },
  };

  const onOdoslat = (text, prilohy) => pridajSpravu("Odpoveď zákazníkovi", text, prilohy).then(() =>
    flash("Odpoveď odoslaná zákazníkovi" + (prilohy.length ? " (" + prilohy.length + " príloh)" : ""), "success")
  );
  const onPoznamka = (text, prilohy) => pridajSpravu("Interná poznámka", text, prilohy).then(() =>
    flash("Interná poznámka uložená", "info")
  );

  const onRefresh = async () => {
    setRefreshing(true);
    try { await reloadData(); } finally { setRefreshing(false); setNow(Date.now()); }
  };

  const onLogout = () => { window.HELPDESK_AUTH.logout(); };

  return (
    <div style={{ display: "flex", flexDirection: "column", height: "100vh" }}>
      <TopBar jeAdmin={jeAdmin} ja={ja} onRefresh={onRefresh} refreshing={refreshing} t={t} setTweak={setTweak} obrazovka={obrazovka} setObrazovka={setObrazovka} onLogout={onLogout} />

      {!tiket ? (
        <CentrovanaSprava text="V SharePointe zatiaľ nie sú žiadne tikety." />
      ) : obrazovka === "stat" ? <StatsScreen /> : (
      <div className={"hd-workspace" + (mobileView === "conv" ? " hd-show-conv" : "")} style={{ flex: 1, minHeight: 0, display: "grid", gridTemplateRows: "minmax(0, 1fr)", gridTemplateColumns: detailOpen ? "360px minmax(0,1fr) 320px" : "360px minmax(0,1fr)" }}>
        <TicketList tikety={tikety} vybranyCislo={tiket.cislo} onVybrat={onVybrat} now={now} jaMeno={ja.meno} />
        <Conversation tiket={tiket} technici={TECHNICI} now={now} onOdoslat={onOdoslat} onPoznamka={onPoznamka}
          detailOpen={detailOpen} onToggleDetail={() => setDetailOpen((v) => !v)} onBack={() => setMobileView("list")} />
        {detailOpen && (
          <DetailsPanel tiket={tiket} technici={TECHNICI} jeAdmin={jeAdmin} jaMeno={ja.meno} now={now} actions={actions} onClose={() => setDetailOpen(false)} />
        )}
      </div>
      )}

      <Toast toast={toast} />

      <TweaksPanel>
        <TweakSection label="Vzhľad" />
        <TweakColor label="Akcentová farba" value={ACCENTS[t.accent].a}
          options={Object.keys(ACCENTS).map((k) => ACCENTS[k].a)}
          onChange={(hex) => { const key = Object.keys(ACCENTS).find((k) => ACCENTS[k].a === hex); if (key) setTweak("accent", key); }} />
        <TweakToggle label="Tmavý režim" value={t.dark} onChange={(v) => setTweak("dark", v)} />
        <TweakRadio label="Hustota" value={t.density} options={["compact", "regular", "comfy"]} onChange={(v) => setTweak("density", v)} />
        <TweakSection label="Panely" />
        <TweakToggle label="Detail tiketu" value={detailOpen} onChange={(v) => setDetailOpen(v)} />
      </TweaksPanel>
    </div>
  );
}

/* ====================== ROOT: prihlásenie + načítanie dát ======================
   Nahrádza pôvodné priame ReactDOM.render(<App/>) — appka sa vykreslí až po úspešnom
   prihlásení a načítaní reálnych dát zo SharePointu. */
function Root() {
  const [status, setStatus] = useState("checking"); // checking | loggedOut | loading | error | ready
  const [errorMsg, setErrorMsg] = useState("");
  const [data, setData] = useState(null);
  const [ja, setJa] = useState(null);
  const accountRef = useRef(null);

  const nacitajData = useCallback(async () => {
    setStatus("loading");
    try {
      const loaded = await window.loadHelpdeskData();
      // Párovanie podľa mena, nie e-mailu — Graph v tomto tenante vracia Person pole "Konto"
      // ako obyčajný reťazec s celým menom, nie objekt s e-mailom (viď plán, Riziko #2).
      const menoPrihlaseneho = (accountRef.current.name || "").toLowerCase();
      const jaTechnik = loaded.TECHNICI.find((x) => (x.meno || "").toLowerCase() === menoPrihlaseneho);
      if (!jaTechnik) {
        setErrorMsg("Prihlásený účet (" + accountRef.current.name + ", " + accountRef.current.username + ") sa nenašiel v zozname Technici (porovnáva sa podľa mena). Požiadaj administrátora o pridanie alebo skontroluj, či sa meno v Entra ID zhoduje s poľom Konto v SharePointe.");
        setStatus("error");
        return;
      }
      // Nastaviť window.HELPDESK_DATA SYNCHRÓNNE pred prvým vykreslením <App> — DetailsPanel
      // a ďalšie komponenty ho čítajú priamo pri renderi (nie v useEffect), takže by inak
      // pri prvom renderi videli undefined (presne tento pád spôsobil chybu "reading 'STAVY'").
      window.HELPDESK_DATA = loaded;
      window.computeHelpdeskStats();
      setData(loaded);
      setJa(jaTechnik);
      setStatus("ready");
    } catch (e) {
      setErrorMsg(e.message || String(e));
      setStatus("error");
    }
  }, []);

  useEffect(() => {
    (async () => {
      await window.HELPDESK_AUTH.ensureReady();
      const acc = window.HELPDESK_AUTH.getAccount();
      if (acc) {
        accountRef.current = acc;
        nacitajData();
      } else {
        setStatus("loggedOut");
      }
    })();
  }, [nacitajData]);

  const onLogin = async () => {
    const acc = await window.HELPDESK_AUTH.login();
    accountRef.current = acc;
    await nacitajData();
  };

  if (status === "checking") return <CentrovanaSprava text="Načítavam…" />;
  if (status === "loggedOut") return <LoginScreen onLogin={onLogin} />;
  if (status === "loading") return <CentrovanaSprava text="Načítavam tikety zo SharePointu…" />;
  if (status === "error") return <LoginScreen onLogin={onLogin} error={errorMsg} />;

  return <App initialData={data} ja={ja} reloadData={nacitajData} />;
}

ReactDOM.createRoot(document.getElementById("root")).render(<Root />);
