








import { mkdir, readFile, rename, writeFile } from "node:fs/promises";
import { dirname } from "node:path";

const MAX_BIEGOW_HISTORII = 20;
const MAX_ZDARZEN = 80;
const MAX_ETYKIETA = 120;

const IMPORT_DATA_RULES = Object.freeze({
  wynik: "result",
  trybPrzyrostowy: "boolean",
  dataOd: "date",
  nowychPolis: "number",
  zwroconoWpisow: "number",
  pobieraniePdf: "boolean",
  pdfPobrano: "number",
  pdfWKolejce: "number",
  kodBleduPdf: "code",
  pdfNiejednoznaczne: "number",
  mapowanieZrodlo: "number",
  mapowaniePoprawne: "number",
  mapowanieOdrzucone: "number",
  mapowanieNiewyjasnione: "number",
  czasSekund: "number",
  blad: "code",
  etap: "slug",
});

const EVENT_DATA_RULES = Object.freeze({
  "konto-utworzone": Object.freeze({}),
  "zmiana-nazwy-konta": Object.freeze({}),
  "paczka-pracownika": Object.freeze({}),
  "przydzial-polis-eksport": Object.freeze({ polis: "number" }),
  "paczka-centrali": Object.freeze({ polis: "number", zakres: "scope" }),
  "import-bazy-pracownika-pliki": Object.freeze({
    zalacznikiSkopiowane: "number",
    zalacznikiPonownieUzyte: "number",
    zalacznikiPrzemianowane: "number",
  }),
  "import-bazy-pracownika-staged": Object.freeze({
    polisWPaczce: "number",
    zalacznikiDoUtworzenia: "number",
    zalacznikiPonownieUzyte: "number",
    zalacznikiDoPrzemianowania: "number",
  }),
  "import-przydzialu-pliki": Object.freeze({
    zalacznikiSkopiowane: "number",
    zalacznikiPonownieUzyte: "number",
    zalacznikiPrzemianowane: "number",
  }),
  "import-przydzialu-staged": Object.freeze({
    polisWPaczce: "number",
    zalacznikiDoUtworzenia: "number",
    zalacznikiPonownieUzyte: "number",
    zalacznikiDoPrzemianowania: "number",
  }),
  "start-aplikacji": Object.freeze({ bootMs: "number" }),
  porzadkowanie: Object.freeze({
    dokonczono: "boolean",
    zaktualizowano: "number",
    poprawioneRodzaje: "number",
    poprawioneTowarzystwa: "number",
    uzupelnioneZPlikow: "number",
    rozdzieloneKonta: "number",
    powiazaneKonta: "number",
    uzupelnioneNipy: "number",
    pominieto: "number",
    odrzucono: "number",
  }),
  "import-reczny-pdf": Object.freeze({
    plikow: "number",
    dodano: "number",
    podpietoPdf: "number",
    uzupelniono: "number",
    duplikaty: "number",
    konfliktyTu: "number",
    bledy: "number",
  }),
  "scalanie-importu": Object.freeze({
    zrodlo: "slug",
    dodane: "number",
    zaktualizowane: "number",
    pdfPodpiete: "number",
    pdfNieudane: "number",
    niejednoznaczne: "number",
    zapisNieudany: "boolean",
  }),
  "rozruch-frontu": Object.freeze({
    licencjaMs: "number",
    bazaZPlikowMs: "number",
    paczkiMs: "number",
    importyMs: "number",
    poZalogowaniuRazemMs: "number",
  }),
});

function sanitizeLabel(value, maxLength = MAX_ETYKIETA) {
  return String(value ?? "").replace(/\s+/g, " ").trim().slice(0, maxLength);
}

function sanitizeValue(value, rule) {
  if (rule === "number") {
    return typeof value === "number" && Number.isFinite(value)
      ? Math.max(0, Math.trunc(value * 100) / 100)
      : undefined;
  }
  if (rule === "boolean") return typeof value === "boolean" ? value : undefined;
  const text = sanitizeLabel(value);
  if (!text) return undefined;
  if (rule === "date") return /^\d{4}-\d{2}-\d{2}$/.test(text) ? text : undefined;
  if (rule === "code") return /^[A-Z0-9_-]{1,48}$/.test(text) ? text : undefined;
  if (rule === "slug") return /^[a-z0-9-]{1,40}$/.test(text) ? text : undefined;
  if (rule === "result") return ["sukces", "brak-nowych", "blad"].includes(text) ? text : undefined;
  if (rule === "scope") return ["wybrane", "wszystko"].includes(text) ? text : undefined;
  return undefined;
}

function sanitizeEventData(data, rules) {
  const result = {};
  if (!data || typeof data !== "object" || Array.isArray(data) || !rules) return result;
  for (const [key, rule] of Object.entries(rules)) {
    const cleanValue = sanitizeValue(data[key], rule);
    if (cleanValue !== undefined) result[key] = cleanValue;
  }
  return result;
}

export function createDiagnostykaStore({ storagePath, appVersion = "" }) {
  let statePromise = null;
  let writeQueue = Promise.resolve();

  async function readState() {
    if (!statePromise) {
      statePromise = readFile(storagePath, "utf8")
        .then((raw) => {
          const parsed = JSON.parse(raw);
          return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : {};
        })
        .catch(() => ({}));
    }
    return statePromise;
  }

  
  
  function withWrite(mutator) {
    writeQueue = writeQueue
      .catch(() => {})
      .then(async () => {
        const state = await readState();
        mutator(state);
        state.wersjaAplikacji = appVersion || state.wersjaAplikacji || "";
        state.zaktualizowano = new Date().toISOString();
        await mkdir(dirname(storagePath), { recursive: true }).catch(() => {});
        const temporaryPath = `${storagePath}.tmp`;
        await writeFile(temporaryPath, `${JSON.stringify(state, null, 2)}\n`, "utf8");
        await rename(temporaryPath, storagePath);
      });
    return writeQueue.catch((error) => {
      console.error("Diagnostyka: nie udało się zapisać pliku.", error?.message || error);
    });
  }

  
  
  
  function zapiszBiegImportu(klucz, dane) {
    const cleanKey = sanitizeLabel(klucz, 60)
      .split(":")[0]
      .toLocaleLowerCase("en")
      .replace(/[^a-z0-9-]/g, "")
      .slice(0, 40);
    if (!cleanKey) return Promise.resolve();
    const wpis = {
      kiedy: new Date().toISOString(),
      wersja: appVersion || "",
      ...sanitizeEventData(dane, IMPORT_DATA_RULES),
    };
    return withWrite((state) => {
      if (!state.importyPortfeli || typeof state.importyPortfeli !== "object") state.importyPortfeli = {};
      const sekcja = state.importyPortfeli[cleanKey] && typeof state.importyPortfeli[cleanKey] === "object"
        ? state.importyPortfeli[cleanKey]
        : {};
      sekcja.ostatniBieg = wpis;
      sekcja.historia = [wpis, ...(Array.isArray(sekcja.historia) ? sekcja.historia : [])].slice(0, MAX_BIEGOW_HISTORII);
      state.importyPortfeli[cleanKey] = sekcja;
    });
  }

  
  
  function zapiszZdarzenie(rodzaj, dane) {
    const cleanKind = sanitizeLabel(rodzaj, 40);
    const rules = EVENT_DATA_RULES[cleanKind];
    if (!rules) return Promise.resolve(false);
    const wpis = {
      kiedy: new Date().toISOString(),
      rodzaj: cleanKind,
      wersja: appVersion || "",
      ...sanitizeEventData(dane, rules),
    };
    return withWrite((state) => {
      state.zdarzenia = [wpis, ...(Array.isArray(state.zdarzenia) ? state.zdarzenia : [])].slice(0, MAX_ZDARZEN);
    }).then(() => true);
  }

  async function odczytaj() {
    
    try {
      const parsed = JSON.parse(await readFile(storagePath, "utf8"));
      return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : {};
    } catch {
      return {};
    }
  }

  return { zapiszBiegImportu, zapiszZdarzenie, odczytaj };
}
