/* admin.jsx — "Správa tiketov": prieskumníkové prehľadávanie všetkých tiketov podľa
   roku/mesiaca (vľavo strom, vpravo tabuľka) + export do Excelu (CSV s BOM, aby sa
   diakritika v slovenskom Exceli zobrazovala správne) so všetkými údajmi na vyhodnotenie.
   Na rozdiel od Komunikácie (len aktívne/vlastné tikety) tu vidno úplne všetko vrátane
   dávno vyriešených a zatvorených tiketov. */

const AD_MESIACE = ["Január", "Február", "Marec", "Apríl", "Máj", "Jún", "Júl", "August", "September", "Október", "November", "December"];

// Všetky stĺpce pre export — širšia sada než tabuľka na obrazovke, nech je exportovaný
// súbor naozaj kompletný podklad na vyhodnocovanie.
const AD_COLS_EXPORT = [
  { k: "cislo", l: "Číslo tiketu", g: (t) => t.cislo },
  { k: "predmet", l: "Predmet", g: (t) => t.predmet },
  { k: "stav", l: "Stav", g: (t) => t.stav },
  { k: "priorita", l: "Priorita", g: (t) => t.priorita },
  { k: "kategoria", l: "Kategória", g: (t) => t.kategoria },
  { k: "podkategoria", l: "Téma", g: (t) => t.podkategoria },
  { k: "ziadatelMeno", l: "Žiadateľ", g: (t) => t.ziadatelMeno },
  { k: "ziadatelEmail", l: "E-mail žiadateľa", g: (t) => t.ziadatelEmail },
  { k: "zakaznik", l: "Firma", g: (t) => t.zakaznik },
  { k: "tykaSa", l: "Zákazník (koho sa týka)", g: (t) => (t.tykaSa || []).join(", ") },
  { k: "technik", l: "Priradený technik", g: (t) => t.technik || "" },
  { k: "zdroj", l: "Zdroj", g: (t) => t.zdroj },
  { k: "vytvorene", l: "Vytvorené", g: (t) => fmtDateTime(t.vytvorene) },
  { k: "termin", l: "Termín SLA", g: (t) => (t.termin ? fmtDateTime(t.termin) : "") },
  { k: "vyriesene", l: "Vyriešené", g: (t) => (t.vyriesene ? fmtDateTime(t.vyriesene) : "") },
  { k: "eskalovany", l: "Eskalovaný", g: (t) => (t.eskalovany ? "Áno" : "Nie") },
  { k: "casMin", l: "Odpracovaný čas (min)", g: (t) => t.celkovyCasMinut || 0 },
  { k: "poctSprav", l: "Počet správ vo vlákne", g: (t) => (t.komunikacia || []).length },
];

// Kompaktnejšia sada pre náhľad na obrazovke — zvyšok je vidieť v exportovanom súbore.
const AD_COLS_TABLE = ["cislo", "predmet", "ziadatelMeno", "zakaznik", "stav", "priorita", "technik", "vytvorene", "vyriesene", "eskalovany"];

function adCsvBunka(v) {
  const s = String(v == null ? "" : v);
  return /[";\r\n]/.test(s) ? '"' + s.replace(/"/g, '""') + '"' : s;
}

function adExportCsv(riadky, nazovSuboru) {
  const hlavicka = AD_COLS_EXPORT.map((c) => c.l).join(";");
  const telo = riadky.map((t) => AD_COLS_EXPORT.map((c) => adCsvBunka(c.g(t))).join(";")).join("\r\n");
  const csv = "﻿" + hlavicka + "\r\n" + telo; // BOM — diakritika v Exceli bez toho vyzerá rozbito
  const blob = new Blob([csv], { type: "text/csv;charset=utf-8;" });
  const url = URL.createObjectURL(blob);
  const a = document.createElement("a");
  a.href = url; a.download = nazovSuboru;
  document.body.appendChild(a); a.click(); document.body.removeChild(a);
  URL.revokeObjectURL(url);
}

/* ---------- ľavý strom: Všetky tikety › rok › mesiac (ako v prieskumníku súborov) ---------- */
function AdTreeNode({ label, pocet, hlbka, aktivny, otvoreny, maDeti, onClick, onToggle }) {
  return (
    <div>
      <button onClick={onClick} style={{
        display: "flex", alignItems: "center", gap: 5, width: "100%", padding: "6px 8px",
        paddingLeft: 8 + hlbka * 18, border: "none", borderRadius: "var(--radius-sm)", textAlign: "left",
        background: aktivny ? "var(--accent-tint)" : "transparent", color: aktivny ? "var(--accent)" : "var(--text)",
        fontSize: 13, fontWeight: aktivny ? 700 : 500,
      }}>
        {maDeti ? (
          <span onClick={(e) => { e.stopPropagation(); onToggle(); }} style={{ display: "inline-flex", flex: "0 0 auto", transform: otvoreny ? "rotate(90deg)" : "none", transition: "transform .12s", color: "var(--text-3)" }}>
            <Icon name="chevron" size={12} />
          </span>
        ) : <span style={{ width: 12, flex: "0 0 auto" }} />}
        <span style={{ flex: 1, minWidth: 0, overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }}>{label}</span>
        <span style={{ flex: "0 0 auto", fontSize: 11, color: aktivny ? "var(--accent)" : "var(--text-3)", fontVariantNumeric: "tabular-nums" }}>{pocet}</span>
      </button>
    </div>
  );
}

function AdTree({ strom, spolu, vybrane, setVybrane }) {
  const [otvoreneRoky, setOtvoreneRoky] = useState(() => new Set(strom.length ? [strom[0].rok] : []));
  const prepnut = (rok) => setOtvoreneRoky((s) => { const n = new Set(s); n.has(rok) ? n.delete(rok) : n.add(rok); return n; });

  return (
    <div style={{ display: "flex", flexDirection: "column", gap: 1, padding: 6, overflowY: "auto" }}>
      <AdTreeNode label="Všetky tikety" pocet={spolu} hlbka={0} maDeti={false}
        aktivny={vybrane === null} onClick={() => setVybrane(null)} onToggle={() => {}} />
      {strom.map((r) => (
        <React.Fragment key={r.rok}>
          <AdTreeNode label={String(r.rok)} pocet={r.pocet} hlbka={0} maDeti={true}
            otvoreny={otvoreneRoky.has(r.rok)}
            aktivny={!!vybrane && vybrane.rok === r.rok && vybrane.mesiac == null}
            onClick={() => setVybrane({ rok: r.rok, mesiac: null })}
            onToggle={() => prepnut(r.rok)} />
          {otvoreneRoky.has(r.rok) && r.mesiace.map((m) => (
            <AdTreeNode key={m.mesiac} label={AD_MESIACE[m.mesiac]} pocet={m.pocet} hlbka={1} maDeti={false}
              aktivny={!!vybrane && vybrane.rok === r.rok && vybrane.mesiac === m.mesiac}
              onClick={() => setVybrane({ rok: r.rok, mesiac: m.mesiac })} onToggle={() => {}} />
          ))}
        </React.Fragment>
      ))}
    </div>
  );
}

// Hodnota "" (prázdny reťazec) = "Všetky", "__none__" = položky bez hodnoty (nepridelený
// technik / bez firmy) — vlastná hodnota, nie "", nech sa dá odlíšiť od "filter vypnutý".
const AD_BEZ_HODNOTY = "__none__";

function AdFiltraSelect({ label, value, onChange, options }) {
  return (
    <label style={{ display: "inline-flex", alignItems: "center", gap: 5, fontSize: 12.5 }}>
      <span style={{ color: "var(--text-3)" }}>{label}:</span>
      <select className="hd-admin-filter" value={value} onChange={(e) => onChange(e.target.value)} style={{
        padding: "5px 8px", fontSize: 12.5, borderRadius: "var(--radius-sm)", border: "1px solid var(--stroke-strong)",
        background: value ? "var(--accent-tint)" : "var(--surface)", color: value ? "var(--accent)" : "var(--text)",
        fontWeight: value ? 700 : 500, fontFamily: "inherit", maxWidth: 160,
      }}>
        <option value="">Všetky</option>
        {options.map((o) => <option key={o.v} value={o.v}>{o.l}</option>)}
      </select>
    </label>
  );
}

// Checkbox s podporou "indeterminate" (časť riadkov označená) — React nemá `indeterminate`
// ako JSX atribút, dá sa nastaviť len priamo na DOM uzol.
function AdCheckbox({ checked, indeterminate, onChange, title }) {
  const ref = useRef(null);
  useEffect(() => { if (ref.current) ref.current.indeterminate = !!indeterminate; }, [indeterminate]);
  return <input ref={ref} type="checkbox" checked={checked} onChange={onChange} title={title} onClick={(e) => e.stopPropagation()} style={{ width: 15, height: 15, cursor: "pointer" }} />;
}

// Priama úprava stavu z tabuľky, bez nutnosti otvoriť detail tiketu. onClick na <select>
// zastaví probublanie ku <tr onClick> (ktorý inak otvára detail) — natívny klik na select,
// ktorým sa otvára rozbaľovací zoznam, je vlastný "click" event skôr, než sa zvolí možnosť.
function AdStavPicker({ stav, options, onChange, disabled }) {
  return (
    <span style={{ display: "inline-flex", alignItems: "center", gap: 5 }} onClick={(e) => e.stopPropagation()}>
      <StatusDot stav={stav} />
      <select value={stav} onChange={(e) => onChange(e.target.value)} disabled={disabled} style={{
        border: "none", background: "transparent", color: "var(--text)", fontSize: 12.5, fontFamily: "inherit",
        fontWeight: 500, cursor: disabled ? "default" : "pointer", padding: 0,
      }}>
        {options.map((s) => <option key={s} value={s}>{s}</option>)}
      </select>
    </span>
  );
}

// Priame priradenie technika z tabuľky — rovnaký dôvod ako AdStavPicker vyššie.
function AdTechnikPicker({ meno, technici, onChange, disabled }) {
  return (
    <select value={meno || ""} onChange={(e) => onChange(e.target.value || null)} disabled={disabled} onClick={(e) => e.stopPropagation()} style={{
      border: "none", background: "transparent", color: meno ? "var(--text)" : "var(--text-3)", fontSize: 12.5, fontFamily: "inherit",
      fontWeight: 500, cursor: disabled ? "default" : "pointer", padding: 0, maxWidth: 140,
    }}>
      <option value="">— (nepridelený)</option>
      {technici.map((t) => <option key={t.meno} value={t.meno}>{t.meno}</option>)}
    </select>
  );
}

/* ---------- hlavná obrazovka ---------- */
function AdminScreen({ tikety, technici, onOtvorDetail, onPatch, flash }) {
  const [vybrane, setVybrane] = useState(null); // null = všetko, {rok, mesiac:null|číslo}
  const [hladaj, setHladaj] = useState("");
  const [sort, setSort] = useState({ k: "vytvorene", smer: -1 });
  // Označené tikety pre hromadné akcie (Set čísel tiketov) — zámerne prežíva zmenu filtra/
  // stromu (rovnaké správanie ako výber súborov v prieskumníku): technik si môže napr.
  // prejsť viac mesiacov a priebežne označovať, bez toho, aby mu prepnutie filtra výber zrušilo.
  const [oznacene, setOznacene] = useState(() => new Set());
  const prepnutOznacenie = (cislo) => setOznacene((s) => { const n = new Set(s); n.has(cislo) ? n.delete(cislo) : n.add(cislo); return n; });
  const zrusitVyber = () => setOznacene(new Set());
  // Filtre v stĺpcoch (Excel-like) — nezávislé od stromu vľavo (obdobie) a od voľného
  // hľadania, dajú sa ľubovoľne kombinovať. "" = daný stĺpec sa nefiltruje.
  const [colFiltre, setColFiltre] = useState({ stav: "", priorita: "", technik: "", zakaznik: "", eskalovany: "" });
  const nastavFilter = (k, v) => setColFiltre((f) => ({ ...f, [k]: v }));
  const vycistitFiltre = () => setColFiltre({ stav: "", priorita: "", technik: "", zakaznik: "", eskalovany: "" });
  const aktivnychFiltrov = Object.values(colFiltre).filter(Boolean).length;

  // Možnosti dropdownov — zámerne zo VŠETKÝCH tiketov (nie z aktuálne zúženého výberu), nech
  // pri kombinovaní filtrov nezmiznú hodnoty, ktoré má zmysel ešte vybrať. Stav/Priorita majú
  // pevné poradie z window.HELPDESK_STATICKE (rovnaké ako všade inde v appke), Firma je voľný
  // text technikov (rozširovaný cez "+ Nová možnosť"), preto zoradená abecedne.
  const staticke = window.HELPDESK_STATICKE || {};
  const stavOpts = (staticke.STAVY || []).map((v) => ({ v, l: v }));
  const prioritaOpts = (staticke.PRIORITY || []).map((v) => ({ v, l: v }));
  const technikOpts = useMemo(() => [
    { v: AD_BEZ_HODNOTY, l: "— (nepridelený)" },
    ...(technici || []).map((t) => ({ v: t.meno, l: t.meno })),
  ], [technici]);
  const zakaznikOpts = useMemo(() => [
    { v: AD_BEZ_HODNOTY, l: "— (bez firmy)" },
    ...Array.from(new Set(tikety.map((t) => t.zakaznik).filter(Boolean))).sort((a, b) => a.localeCompare(b, "sk")).map((v) => ({ v, l: v })),
  ], [tikety]);
  const eskalovanyOpts = [{ v: "ano", l: "Áno" }, { v: "nie", l: "Nie" }];

  const strom = useMemo(() => {
    const roky = {};
    tikety.forEach((t) => {
      if (!t.vytvorene) return;
      const d = new Date(t.vytvorene);
      const r = d.getFullYear(), m = d.getMonth();
      roky[r] = roky[r] || {};
      roky[r][m] = (roky[r][m] || 0) + 1;
    });
    return Object.keys(roky).map(Number).sort((a, b) => b - a).map((r) => ({
      rok: r,
      pocet: Object.values(roky[r]).reduce((s, x) => s + x, 0),
      mesiace: Object.keys(roky[r]).map(Number).sort((a, b) => b - a).map((m) => ({ mesiac: m, pocet: roky[r][m] })),
    }));
  }, [tikety]);

  const filtrovane = useMemo(() => {
    let arr = tikety;
    if (vybrane) {
      arr = arr.filter((t) => {
        if (!t.vytvorene) return false;
        const d = new Date(t.vytvorene);
        if (d.getFullYear() !== vybrane.rok) return false;
        if (vybrane.mesiac != null && d.getMonth() !== vybrane.mesiac) return false;
        return true;
      });
    }
    if (colFiltre.stav) arr = arr.filter((t) => t.stav === colFiltre.stav);
    if (colFiltre.priorita) arr = arr.filter((t) => t.priorita === colFiltre.priorita);
    if (colFiltre.technik) arr = arr.filter((t) => (colFiltre.technik === AD_BEZ_HODNOTY ? !t.technik : t.technik === colFiltre.technik));
    if (colFiltre.zakaznik) arr = arr.filter((t) => (colFiltre.zakaznik === AD_BEZ_HODNOTY ? !t.zakaznik : t.zakaznik === colFiltre.zakaznik));
    if (colFiltre.eskalovany) arr = arr.filter((t) => (colFiltre.eskalovany === "ano" ? !!t.eskalovany : !t.eskalovany));
    const q = hladaj.trim().toLowerCase();
    if (q) arr = arr.filter((t) => t.cislo.toLowerCase().includes(q) || t.predmet.toLowerCase().includes(q) || (t.ziadatelMeno || "").toLowerCase().includes(q) || (t.zakaznik || "").toLowerCase().includes(q));
    return arr;
  }, [tikety, vybrane, colFiltre, hladaj]);

  const zoradene = useMemo(() => {
    const col = AD_COLS_EXPORT.find((c) => c.k === sort.k);
    return [...filtrovane].sort((a, b) => {
      // pre dátumové/číselné stĺpce triediť podľa surovej hodnoty (nie formátovaného textu)
      const raw = (t) => (sort.k === "vytvorene" ? t.vytvorene : sort.k === "termin" ? t.termin : sort.k === "vyriesene" ? t.vyriesene : sort.k === "casMin" ? (t.celkovyCasMinut || 0) : col.g(t));
      const av = raw(a), bv = raw(b);
      if (av == null && bv == null) return 0;
      if (av == null) return 1; if (bv == null) return -1;
      if (typeof av === "number" && typeof bv === "number") return (av - bv) * sort.smer;
      return String(av).localeCompare(String(bv), "sk") * sort.smer;
    });
  }, [filtrovane, sort]);

  const zoradVedla = (k) => setSort((s) => ({ k, smer: s.k === k ? -s.smer : 1 }));

  const nazovExportu = () => {
    if (!vybrane) return "tikety_vsetko.csv";
    if (vybrane.mesiac == null) return "tikety_" + vybrane.rok + ".csv";
    return "tikety_" + vybrane.rok + "-" + String(vybrane.mesiac + 1).padStart(2, "0") + ".csv";
  };

  const oznacenie = !vybrane ? "Všetky tikety" : vybrane.mesiac == null ? "Rok " + vybrane.rok : AD_MESIACE[vybrane.mesiac] + " " + vybrane.rok;

  // "Vybrať všetko" sa vzťahuje na AKTUÁLNE zobrazený (vyfiltrovaný) výber, nie na úplne
  // všetky tikety appky — inak by jeden klik označil aj tikety, ktoré technik ani nevidí.
  const vsetkyViditelneOznacene = zoradene.length > 0 && zoradene.every((t) => oznacene.has(t.cislo));
  const niektoreViditelneOznacene = !vsetkyViditelneOznacene && zoradene.some((t) => oznacene.has(t.cislo));
  const prepnutVsetky = () => setOznacene((s) => {
    const n = new Set(s);
    if (vsetkyViditelneOznacene) zoradene.forEach((t) => n.delete(t.cislo));
    else zoradene.forEach((t) => n.add(t.cislo));
    return n;
  });

  const oznaceneTikety = useMemo(() => tikety.filter((t) => oznacene.has(t.cislo)), [tikety, oznacene]);
  const sklonTiketov = (n) => (n === 1 ? "tiket" : n >= 2 && n <= 4 ? "tikety" : "tiketov");

  // Hromadné akcie — rovnaká logika výpočtu patchu ako jednotlivá zmena na technickej strane
  // (window.vypocitajPatchZmenyStavu/Priradenia, zdieľané cez data.jsx), len aplikovaná na
  // všetky označené tikety naraz. onPatch = patchTiket z app.jsx: optimistická zmena + zápis
  // do SharePointu na pozadí, so zabudovaným rollbackom pri zlyhaní zápisu jedného tiketu.
  const hromadnaZmenaStavu = (novyStav) => {
    if (!onPatch || !novyStav || !oznaceneTikety.length) return;
    oznaceneTikety.forEach((t) => {
      const { patch, udalost } = window.vypocitajPatchZmenyStavu(t, novyStav);
      onPatch(t.cislo, patch, udalost);
    });
    // Zámerne "N tiketov: text", nie "text pri N tiketoch" — count + text za dvojbodkou sa
    // nemusí zhodovať v páde s číslovkou (slovenčina má pre "pri" lokál, čo by pri
    // dynamickom počte vyžadovalo riešiť aj skloňovanie "tiket/tikete/tiketoch").
    if (flash) flash(oznaceneTikety.length + " " + sklonTiketov(oznaceneTikety.length) + ": stav zmenený na „" + novyStav + "“", "info");
    zrusitVyber();
  };
  const hromadnePriradenie = (meno) => {
    if (!onPatch || !oznaceneTikety.length) return;
    oznaceneTikety.forEach((t) => {
      const { patch, udalost } = window.vypocitajPatchPriradenia(t, meno || null);
      onPatch(t.cislo, patch, udalost);
    });
    if (flash) flash(oznaceneTikety.length + " " + sklonTiketov(oznaceneTikety.length) + ": " + (meno ? "priradený technik " + meno : "technik uvoľnený"), "info");
    zrusitVyber();
  };

  return (
    <div style={{ flex: 1, minHeight: 0, display: "grid", gridTemplateColumns: "220px minmax(0,1fr)", background: "var(--bg)" }}>
      <aside style={{ borderRight: "1px solid var(--stroke)", background: "var(--surface)", overflowY: "auto" }}>
        <div style={{ padding: "12px 12px 4px", fontSize: 11, fontWeight: 700, color: "var(--text-3)", textTransform: "uppercase", letterSpacing: ".4px" }}>Podľa obdobia</div>
        <AdTree strom={strom} spolu={tikety.length} vybrane={vybrane} setVybrane={setVybrane} />
      </aside>

      <div style={{ display: "flex", flexDirection: "column", minWidth: 0, overflow: "hidden" }}>
        <div style={{ display: "flex", alignItems: "center", gap: 12, padding: "14px 20px", borderBottom: "1px solid var(--stroke)", flexWrap: "wrap" }}>
          <div style={{ minWidth: 0 }}>
            <div style={{ fontSize: 15, fontWeight: 700 }}>{oznacenie}</div>
            <div style={{ fontSize: 12, color: "var(--text-3)" }}>{zoradene.length} {zoradene.length === 1 ? "tiket" : zoradene.length < 5 ? "tikety" : "tiketov"}</div>
          </div>
          <div style={{ marginLeft: "auto", display: "flex", alignItems: "center", gap: 8 }}>
            <input value={hladaj} onChange={(e) => setHladaj(e.target.value)} placeholder="Hľadať v tomto výbere…" style={{
              width: 220, padding: "7px 10px", fontSize: 13, borderRadius: "var(--radius-sm)", border: "1px solid var(--stroke-strong)",
              background: "var(--surface-2)", color: "var(--text)", fontFamily: "inherit",
            }} />
            <Btn kind="primary" icon="file" onClick={() => adExportCsv(zoradene, nazovExportu())} disabled={!zoradene.length}>Export do Excelu</Btn>
          </div>
        </div>

        <div style={{ display: "flex", alignItems: "center", gap: 14, padding: "10px 20px", borderBottom: "1px solid var(--stroke)", flexWrap: "wrap", overflowX: "auto", background: "var(--surface-2)" }}>
          <span style={{ display: "inline-flex", alignItems: "center", gap: 5, fontSize: 12, fontWeight: 700, color: "var(--text-3)", textTransform: "uppercase", letterSpacing: ".3px", flex: "0 0 auto" }}>
            <Icon name="filter" size={13} /> Filtre
          </span>
          <AdFiltraSelect label="Stav" value={colFiltre.stav} onChange={(v) => nastavFilter("stav", v)} options={stavOpts} />
          <AdFiltraSelect label="Priorita" value={colFiltre.priorita} onChange={(v) => nastavFilter("priorita", v)} options={prioritaOpts} />
          <AdFiltraSelect label="Technik" value={colFiltre.technik} onChange={(v) => nastavFilter("technik", v)} options={technikOpts} />
          <AdFiltraSelect label="Firma" value={colFiltre.zakaznik} onChange={(v) => nastavFilter("zakaznik", v)} options={zakaznikOpts} />
          <AdFiltraSelect label="Eskalovaný" value={colFiltre.eskalovany} onChange={(v) => nastavFilter("eskalovany", v)} options={eskalovanyOpts} />
          {aktivnychFiltrov > 0 && (
            <button onClick={vycistitFiltre} style={{
              display: "inline-flex", alignItems: "center", gap: 5, padding: "5px 10px", fontSize: 12.5, fontWeight: 600,
              border: "1px solid var(--stroke-strong)", borderRadius: "var(--radius-sm)", background: "var(--surface)", color: "var(--text-2)",
            }}>
              <Icon name="close" size={12} /> Vyčistiť filtre ({aktivnychFiltrov})
            </button>
          )}
        </div>

        {oznacene.size > 0 && (
          <div style={{ display: "flex", alignItems: "center", gap: 12, padding: "9px 20px", borderBottom: "1px solid var(--stroke)", flexWrap: "wrap", background: "var(--accent-tint)" }}>
            <span style={{ fontSize: 12.5, fontWeight: 700, color: "var(--accent)" }}>
              {oznacene.size} {sklonTiketov(oznacene.size)} označených
            </span>
            <label style={{ display: "inline-flex", alignItems: "center", gap: 5, fontSize: 12.5 }}>
              <span style={{ color: "var(--text-2)" }}>Priradiť technika:</span>
              <select value="" onChange={(e) => hromadnePriradenie(e.target.value === AD_BEZ_HODNOTY ? null : e.target.value)} disabled={!onPatch} style={{
                padding: "5px 8px", fontSize: 12.5, borderRadius: "var(--radius-sm)", border: "1px solid var(--stroke-strong)",
                background: "var(--surface)", color: "var(--text)", fontFamily: "inherit",
              }}>
                <option value="" disabled>Vybrať…</option>
                <option value={AD_BEZ_HODNOTY}>— (uvoľniť)</option>
                {(technici || []).map((t) => <option key={t.meno} value={t.meno}>{t.meno}</option>)}
              </select>
            </label>
            <label style={{ display: "inline-flex", alignItems: "center", gap: 5, fontSize: 12.5 }}>
              <span style={{ color: "var(--text-2)" }}>Zmeniť stav:</span>
              <select value="" onChange={(e) => hromadnaZmenaStavu(e.target.value)} disabled={!onPatch} style={{
                padding: "5px 8px", fontSize: 12.5, borderRadius: "var(--radius-sm)", border: "1px solid var(--stroke-strong)",
                background: "var(--surface)", color: "var(--text)", fontFamily: "inherit",
              }}>
                <option value="" disabled>Vybrať…</option>
                {stavOpts.map((o) => <option key={o.v} value={o.v}>{o.l}</option>)}
              </select>
            </label>
            <Btn icon="file" onClick={() => adExportCsv(oznaceneTikety, "tikety_vybrane.csv")}>Exportovať vybrané</Btn>
            <button onClick={zrusitVyber} style={{
              marginLeft: "auto", display: "inline-flex", alignItems: "center", gap: 5, padding: "5px 10px", fontSize: 12.5, fontWeight: 600,
              border: "1px solid var(--stroke-strong)", borderRadius: "var(--radius-sm)", background: "var(--surface)", color: "var(--text-2)",
            }}>
              <Icon name="close" size={12} /> Zrušiť výber
            </button>
          </div>
        )}

        <div style={{ flex: 1, minHeight: 0, overflow: "auto" }}>
          {!zoradene.length ? (
            <div style={{ padding: 40, textAlign: "center", color: "var(--text-3)", fontSize: 13 }}>V tomto výbere nie sú žiadne tikety.</div>
          ) : (
            <table style={{ width: "100%", borderCollapse: "collapse", fontSize: 12.5 }}>
              <thead>
                <tr style={{ position: "sticky", top: 0, background: "var(--surface)", zIndex: 1 }}>
                  <th style={{ padding: "9px 8px 9px 12px", borderBottom: "1px solid var(--stroke)", width: 32 }}>
                    <AdCheckbox checked={vsetkyViditelneOznacene} indeterminate={niektoreViditelneOznacene} onChange={prepnutVsetky} title="Označiť/zrušiť všetky zobrazené" />
                  </th>
                  {AD_COLS_TABLE.map((k) => {
                    const col = AD_COLS_EXPORT.find((c) => c.k === k);
                    return (
                      <th key={k} onClick={() => zoradVedla(k)} style={{
                        padding: "9px 12px", textAlign: "left", fontWeight: 700, fontSize: 11, color: "var(--text-3)",
                        textTransform: "uppercase", letterSpacing: ".3px", borderBottom: "1px solid var(--stroke)", cursor: "pointer", whiteSpace: "nowrap",
                      }}>
                        <span style={{ display: "inline-flex", alignItems: "center", gap: 4 }}>
                          {col.l}
                          {sort.k === k && <Icon name={sort.smer === 1 ? "chevronDown" : "chevron"} size={11} style={{ transform: sort.smer === 1 ? "rotate(180deg)" : "rotate(90deg)" }} />}
                        </span>
                      </th>
                    );
                  })}
                  <th style={{ borderBottom: "1px solid var(--stroke)", width: 32 }} />
                </tr>
              </thead>
              <tbody>
                {zoradene.map((t) => (
                  <tr key={t.cislo} className="hd-admin-row" onClick={onOtvorDetail ? () => onOtvorDetail(t.cislo) : undefined}
                    title={onOtvorDetail ? "Otvoriť detail tiketu" : undefined}
                    style={{ borderBottom: "1px solid var(--stroke)", cursor: onOtvorDetail ? "pointer" : "default" }}>
                    <td style={{ padding: "8px 8px 8px 12px" }}>
                      <AdCheckbox checked={oznacene.has(t.cislo)} onChange={() => prepnutOznacenie(t.cislo)} title="Označiť tiket" />
                    </td>
                    <td style={{ padding: "8px 12px", fontWeight: 700, color: "var(--accent)", whiteSpace: "nowrap" }}>{t.cislo}</td>
                    <td style={{ padding: "8px 12px", maxWidth: 320, overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }}>{t.predmet}</td>
                    <td style={{ padding: "8px 12px", whiteSpace: "nowrap" }}>{t.ziadatelMeno}</td>
                    <td style={{ padding: "8px 12px", whiteSpace: "nowrap", color: "var(--text-2)" }}>{t.zakaznik || "—"}</td>
                    <td style={{ padding: "8px 12px" }}>
                      <AdStavPicker stav={t.stav} options={staticke.STAVY || [t.stav]} disabled={!onPatch}
                        onChange={(v) => { const { patch, udalost } = window.vypocitajPatchZmenyStavu(t, v); onPatch(t.cislo, patch, udalost); }} />
                    </td>
                    <td style={{ padding: "8px 12px" }}><PriorityBadge priorita={t.priorita} small /></td>
                    <td style={{ padding: "8px 12px", whiteSpace: "nowrap" }}>
                      <AdTechnikPicker meno={t.technik} technici={technici || []} disabled={!onPatch}
                        onChange={(meno) => { const { patch, udalost } = window.vypocitajPatchPriradenia(t, meno); onPatch(t.cislo, patch, udalost); }} />
                    </td>
                    <td style={{ padding: "8px 12px", whiteSpace: "nowrap", fontVariantNumeric: "tabular-nums", color: "var(--text-2)" }}>{fmtDateTime(t.vytvorene)}</td>
                    <td style={{ padding: "8px 12px", whiteSpace: "nowrap", fontVariantNumeric: "tabular-nums", color: "var(--text-2)" }}>{t.vyriesene ? fmtDateTime(t.vyriesene) : "—"}</td>
                    <td style={{ padding: "8px 12px" }}>{t.eskalovany ? <span style={{ color: "var(--red)", display: "inline-flex", alignItems: "center", gap: 4, fontWeight: 600 }}><Icon name="warning" size={13} /> Áno</span> : "—"}</td>
                    <td style={{ padding: "8px 12px", color: "var(--text-3)" }}><Icon name="chevron" size={14} /></td>
                  </tr>
                ))}
              </tbody>
            </table>
          )}
        </div>
      </div>
    </div>
  );
}

window.AdminScreen = AdminScreen;
