















import { readdir, readFile, stat } from "node:fs/promises";
import { basename, resolve, sep } from "node:path";
import { pathToFileURL } from "node:url";



const MAX_PDF_BYTES = 40 * 1024 * 1024;

export async function readPolicyParserFilesInProductionOrder(
  filesDirectory,
  startFilePath = resolve(filesDirectory, "start.htm"),
) {
  const parsersDirectory = resolve(filesDirectory, "vzhgqyjhppnpobjprzyl");
  const directoryName = basename(parsersDirectory);
  const directoryPattern = directoryName.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
  const startSource = await readFile(startFilePath, "utf8");
  const order = [
    ...startSource.matchAll(new RegExp(`${directoryPattern}/([A-Za-z0-9.-]+\\.js)`, "g")),
  ].map((match) => match[1]);
  const onDisk = (await readdir(parsersDirectory)).filter((name) => name.endsWith(".js"));
  const duplicate = order.find((name, index) => order.indexOf(name) !== index);
  const missingInHtml = onDisk.filter((name) => !order.includes(name));
  const missingOnDisk = order.filter((name) => !onDisk.includes(name));
  if (duplicate || missingInHtml.length > 0 || missingOnDisk.length > 0) {
    throw new Error("Kolejność parserów PDF w start.htm nie zgadza się z plikami programu.");
  }
  return order;
}



function evaluateVendorBundle(source, fileName) {
  const bundleModule = { exports: {} };
  const factory = new Function("module", "exports", `${source}\n//# sourceURL=${fileName}`);
  factory(bundleModule, bundleModule.exports);
  return bundleModule.exports;
}





function toSafeSegments(relativePath, attachmentsDirectoryName) {
  const segments = (Array.isArray(relativePath) ? relativePath : String(relativePath ?? "").split(/[\\/]+/))
    .map((segment) => String(segment ?? "").trim())
    .filter(Boolean);
  if (segments.length < 2) return null;
  if (segments[0] !== attachmentsDirectoryName) return null;
  for (const segment of segments) {
    if (segment === "." || segment === "..") return null;
    if (segment.includes("\0")) return null;
    if (/^[a-z]:$/i.test(segment)) return null;
  }
  if (!segments[segments.length - 1].toLocaleLowerCase("pl").endsWith(".pdf")) return null;
  return segments.slice(1);
}

export function createPolicyPdfReader({ attachmentsRoot, filesDirectory }) {
  const rootPath = resolve(attachmentsRoot);
  const attachmentsDirectoryName = basename(rootPath);
  let parsersPromise = null;
  
  
  let readQueue = Promise.resolve();

  async function loadParsers() {
    
    
    globalThis.DOMMatrix ||= class DOMMatrix {};
    globalThis.ImageData ||= class ImageData {};
    globalThis.Path2D ||= class Path2D {};

    const vendorDirectory = resolve(filesDirectory, "vendor");
    globalThis.pdfjsWorker = evaluateVendorBundle(
      await readFile(resolve(vendorDirectory, "pdf.worker.min.js"), "utf8"),
      "pdf.worker.min.js",
    );
    globalThis.pdfjsLib = evaluateVendorBundle(
      await readFile(resolve(vendorDirectory, "pdf.min.js"), "utf8"),
      "pdf.min.js",
    );

    
    await import(pathToFileURL(resolve(filesDirectory, "vrjeksrdppugqlwzhfab.js")));
    const parsersDirectory = resolve(filesDirectory, "vzhgqyjhppnpobjprzyl");
    for (const parserFile of await readPolicyParserFilesInProductionOrder(filesDirectory)) {
      await import(pathToFileURL(resolve(parsersDirectory, parserFile)));
    }
    if (typeof globalThis.PolicyPdfImporter?.importPolicyPdf !== "function") {
      throw new Error("Brak modułu odczytu PDF.");
    }
    return globalThis.PolicyPdfImporter;
  }

  function ensureParsers() {
    
    
    parsersPromise ||= loadParsers().catch((error) => {
      parsersPromise = null;
      throw error;
    });
    return parsersPromise;
  }

  function resolveAttachmentPath(relativePath) {
    const segments = toSafeSegments(relativePath, attachmentsDirectoryName);
    if (!segments) return "";
    const filePath = resolve(rootPath, ...segments);
    if (filePath !== rootPath && !filePath.startsWith(rootPath + sep)) return "";
    return filePath;
  }

  async function readOne(relativePath) {
    const path = Array.isArray(relativePath)
      ? relativePath.join("/")
      : String(relativePath ?? "");
    const filePath = resolveAttachmentPath(relativePath);
    if (!filePath) return { path, status: "invalid" };

    let fileStat = null;
    try {
      fileStat = await stat(filePath);
    } catch {
      
      
      
      return { path, status: "notFound" };
    }
    if (!fileStat.isFile()) return { path, status: "notFound" };
    if (fileStat.size > MAX_PDF_BYTES) return { path, status: "unreadable" };

    const importer = await ensureParsers();
    try {
      const bytes = await readFile(filePath);
      const parsed = await importer.importPolicyPdf(new Blob([bytes], { type: "application/pdf" }));
      return { path, status: "parsed", parsed };
    } catch (error) {
      
      
      
      console.error("Nie udało się przeczytać PDF polisy:", error?.message || error);
      return { path, status: "unreadable", code: String(error?.code || "") };
    }
  }

  return {
    
    
    async readPolicyPdfs(relativePaths) {
      const paths = Array.isArray(relativePaths) ? relativePaths.slice(0, 40) : [];
      if (paths.length === 0) return [];
      const task = readQueue.then(async () => {
        const results = [];
        for (const relativePath of paths) {
          results.push(await readOne(relativePath));
        }
        return results;
      });
      readQueue = task.then(() => {}, () => {});
      return task;
    },
  };
}
