










import { createPublicKey, verify } from "node:crypto";


export const TOLERANCJA_ZEGARA_MS = 5 * 60 * 1000;
const DZIEN_MS = 24 * 60 * 60 * 1000;
const DATA_WZORZEC = /^\d{4}-\d{2}-\d{2}$/;
export const PRZYPISANY_KLUCZ_PUBLICZNY_LICENCJI = "MCowBQYDK2VwAyEA5nZOZ9ez4cqS4aDTkMdBGxo5fVQP9YM0t3/KS27u3NM=";

export function dataLokalna(czas) {
  try {
    return new Intl.DateTimeFormat("sv-SE", { timeZone: "Europe/Warsaw" }).format(czas);
  } catch {
    return new Date(czas).toISOString().slice(0, 10);
  }
}

function czasZDaty(data) {
  return DATA_WZORZEC.test(String(data || "")) ? Date.parse(`${data}T00:00:00Z`) : Number.NaN;
}

export function roznicaDni(dataOd, dataDo) {
  const od = czasZDaty(dataOd);
  const do_ = czasZDaty(dataDo);
  if (!Number.isFinite(od) || !Number.isFinite(do_)) return null;
  return Math.round((do_ - od) / DZIEN_MS);
}


export function odczytajPodpisanyDokument(
  { dokument, podpis } = {},
  kluczPubliczny = PRZYPISANY_KLUCZ_PUBLICZNY_LICENCJI,
) {
  if (!dokument || !podpis || !kluczPubliczny) return null;
  let klucz;
  try {
    klucz = createPublicKey({
      key: Buffer.from(String(kluczPubliczny), "base64"),
      format: "der",
      type: "spki",
    });
  } catch {
    return null;
  }
  let podpisPoprawny = false;
  try {
    podpisPoprawny = verify(
      null,
      Buffer.from(String(dokument), "utf8"),
      klucz,
      Buffer.from(String(podpis), "base64"),
    );
  } catch {
    return null;
  }
  if (!podpisPoprawny) return null;
  try {
    const tresc = JSON.parse(Buffer.from(String(dokument), "base64").toString("utf8"));
    return tresc && typeof tresc === "object" && !Array.isArray(tresc) ? tresc : null;
  } catch {
    return null;
  }
}

export function odczytajPodpisanaLicencje(
  podpisanyDokument = {},
  kluczPubliczny = PRZYPISANY_KLUCZ_PUBLICZNY_LICENCJI,
) {
  const tresc = odczytajPodpisanyDokument(podpisanyDokument, kluczPubliczny);
  if (!tresc || typeof tresc !== "object" || Array.isArray(tresc) || tresc.format !== 1) return null;
  if (!tresc.login || typeof tresc.login !== "string") return null;
  if (tresc.wazneDo && !DATA_WZORZEC.test(String(tresc.wazneDo))) return null;
  return tresc;
}




export function najpozniejszaZnanaChwila(znaczniki = []) {
  let najpozniejsza = 0;
  for (const znacznik of znaczniki) {
    const czas = znacznik instanceof Date ? znacznik.getTime() : Date.parse(String(znacznik || ""));
    if (Number.isFinite(czas) && czas > najpozniejsza) najpozniejsza = czas;
  }
  return najpozniejsza;
}

export function czyZegarCofniety({ teraz, znanaChwila, tolerancja = TOLERANCJA_ZEGARA_MS } = {}) {
  if (!Number.isFinite(znanaChwila) || znanaChwila <= 0) return false;
  return teraz < znanaChwila - tolerancja;
}

 
export function ocenStanLicencji({
  licencja = null,
  teraz = Date.now(),
  znanaChwila = 0,
  ostatnieSprawdzenieUdane = true,
} = {}) {
  if (!licencja) {
    return {
      stan: "brak",
      tylkoOdczyt: true,
      wymagaSprawdzenia: true,
      wazneDo: "",
      dniDoKonca: null,
      komunikat: "Zaloguj się, żeby korzystać z programu.",
    };
  }

  
  
  if (czyZegarCofniety({ teraz, znanaChwila })) {
    return {
      stan: "zegar-cofniety",
      tylkoOdczyt: !ostatnieSprawdzenieUdane,
      wymagaSprawdzenia: true,
      wazneDo: String(licencja.wazneDo || ""),
      dniDoKonca: null,
      komunikat: ostatnieSprawdzenieUdane
        ? "Data w komputerze została cofnięta. Licencja została sprawdzona ponownie."
        : "Data w komputerze nie zgadza się z rzeczywistą. Połącz się z internetem, żeby potwierdzić licencję.",
    };
  }

  if (licencja.programWlaczony === false) {
    return {
      stan: "wylaczona",
      tylkoOdczyt: true,
      wymagaSprawdzenia: true,
      wazneDo: String(licencja.wazneDo || ""),
      dniDoKonca: null,
      komunikat: "Dostęp do programu został wstrzymany. Skontaktuj się z autorem programu.",
    };
  }

  const wazneDo = String(licencja.wazneDo || "");
  
  
  const dzisiaj = dataLokalna(Math.max(teraz, znanaChwila || 0));
  if (!wazneDo) {
    return {
      stan: "aktywna",
      tylkoOdczyt: false,
      wymagaSprawdzenia: false,
      wazneDo: "",
      dniDoKonca: null,
      komunikat: "Licencja bez terminu.",
    };
  }

  const dniDoKonca = roznicaDni(dzisiaj, wazneDo);
  if (dniDoKonca !== null && dniDoKonca >= 0) {
    
    const sprawdzPo = DATA_WZORZEC.test(String(licencja.sprawdzPo || "")) ? licencja.sprawdzPo : wazneDo;
    return {
      stan: "aktywna",
      tylkoOdczyt: false,
      wymagaSprawdzenia: dzisiaj > sprawdzPo,
      wazneDo,
      dniDoKonca,
      komunikat: dniDoKonca <= 14
        ? `Licencja kończy się ${wazneDo}. Zostało ${dniDoKonca} dni.`
        : `Licencja ważna do ${wazneDo}.`,
    };
  }

  
  
  const karencjaDni = Number.isFinite(Number(licencja.karencjaDni)) ? Math.max(0, Number(licencja.karencjaDni)) : 0;
  const dniPoKoncu = Math.abs(dniDoKonca ?? 0);
  if (dniPoKoncu <= karencjaDni) {
    return {
      stan: "karencja",
      tylkoOdczyt: false,
      wymagaSprawdzenia: true,
      wazneDo,
      dniDoKonca,
      komunikat: `Licencja skończyła się ${wazneDo}. Program działa jeszcze ${karencjaDni - dniPoKoncu + 1} dni.`,
    };
  }
  return {
    stan: "wygasla",
    tylkoOdczyt: true,
    wymagaSprawdzenia: true,
    wazneDo,
    dniDoKonca,
    komunikat: `Licencja skończyła się ${wazneDo}. Program pokazuje dane, ale nie zapisuje zmian.`,
  };
}
