(function registerPzuPropertyPolicyParsers(globalScope) {
  "use strict";

  const registry = globalScope.PolicyPdfParserRegistry;
  const helpers = globalScope.PolicyPdfParserHelpers;
  if (!registry || !helpers) throw new Error("Najpierw wczytaj wspólny silnik importu polis PDF.");

  const { normalizeLine, normalizeForDetection, firstMatch, toIsoDate, cleanPremium } = helpers;

  
  
  
  const PRODUCT_DEFINITIONS = [
    {
      key: "uprawy",
      headerPattern: /POLISA UBEZPIECZENIA PZU UPRAWY/,
      product: "Uprawy",
      registration: "Rolne",
      buildRiskSummary: buildCropsRiskSummary,
    },
    {
      key: "gospodarstwo",
      headerPattern: /POLISA UBEZPIECZENIA PZU GOSPODARSTWO ROLNE/,
      product: "Gospodarstwo rolne",
      registration: "Rolne",
      buildRiskSummary: buildFarmRiskSummary,
    },
    {
      key: "nnw-sport",
      headerPattern: /POLISA UBEZPIECZENIA NASTEPSTW NIESZCZESLIWYCH WYPADKOW[\s\S]{0,80}?PZU SPORT/,
      product: "NNW Sport",
      registration: "Inne",
      buildRiskSummary: buildAccidentRiskSummary,
    },
    {
      key: "nnw",
      headerPattern: /POLISA UBEZPIECZENIA NASTEPSTW NIESZCZESLIWYCH WYPADKOW/,
      product: "NNW",
      registration: "Inne",
      buildRiskSummary: buildAccidentRiskSummary,
    },
    {
      key: "oc-medyczna",
      headerPattern: /ODPOWIEDZIALNOSCI CYWILNEJ PIELEGNIARKI, POLOZN/,
      product: "OC zawodowa medyczna",
      registration: "Firma",
      buildRiskSummary: (allText, generic) => buildLiabilityRiskSummary(allText, generic, "OC pielęgniarki/położnej/fizjoterapeuty"),
    },
    {
      key: "oc-przewoznika",
      headerPattern: /ODPOWIEDZIALNOSCI CYWILNEJ PRZEWOZNIKA DROGOWEGO/,
      product: "OC przewoźnika",
      registration: "Firma",
      buildRiskSummary: (allText, generic) => buildLiabilityRiskSummary(allText, generic, "OC przewoźnika drogowego"),
    },
    {
      key: "oc-zawodowa",
      headerPattern: /POLISA UBEZPIECZENIA ODPOWIEDZIALNOSCI CYWILNEJ ZAWODOWEJ/,
      product: "OC zawodowa",
      registration: "Firma",
      buildRiskSummary: (allText, generic) => buildLiabilityRiskSummary(allText, generic, "OC zawodowa"),
    },
    {
      key: "oc-ogolna",
      headerPattern: /POLISA UBEZPIECZENIA ODPOWIEDZIALNOSCI CYWILNEJ OGOLNEJ/,
      product: "OC działalności",
      registration: "Firma",
      buildRiskSummary: (allText, generic) => buildLiabilityRiskSummary(allText, generic, "OC działalności"),
    },
    {
      key: "ogien",
      headerPattern: /POLISA UBEZPIECZENIA OD OGNIA I INNYCH ZYWIOLOW/,
      product: "Ogień i żywioły",
      registration: "Firma",
      buildRiskSummary: (allText, generic) => buildPropertyRiskSummary(allText, generic, "Ogień i inne żywioły"),
    },
    {
      key: "mienie-all-risk",
      headerPattern: /POLISA UBEZPIECZENIA MIENIA OD WSZYSTKICH RYZYK/,
      product: "Mienie od wszystkich ryzyk",
      registration: "Firma",
      buildRiskSummary: (allText, generic) => buildPropertyRiskSummary(allText, generic, "Mienie od wszystkich ryzyk"),
    },
    {
      key: "doradca",
      headerPattern: /POLISA UBEZPIECZENIA PZU DORADCA/,
      product: "PZU Doradca",
      registration: "Firma",
      buildRiskSummary: (allText, generic) => buildPropertyRiskSummary(allText, generic, "PZU Doradca"),
    },
  ];

  function matchProductDefinition(detectionText) {
    return PRODUCT_DEFINITIONS.find(({ headerPattern }) => headerPattern.test(detectionText)) || null;
  }

  function findGuaranteeSum(allText) {
    return firstMatch(allText, [
      /Suma gwarancyjna[^0-9\n]{0,120}?([0-9][0-9  ]{2,14}(?:[.,][0-9]{1,2})?)\s*(?:zł|PLN)/i,
      /Suma gwarancyjna\s*\n[^\n]{0,80}?([0-9][0-9  ]{2,14}(?:[.,][0-9]{1,2})?)\s*(?:zł|PLN)/i,
    ]).replace(/\s+/g, " ");
  }

  function mergeRiskParts(...parts) {
    const seen = new Set();
    const merged = [];
    for (const part of parts.flatMap((value) => String(value || "").split(" • "))) {
      const cleaned = normalizeLine(part);
      const key = normalizeForDetection(cleaned);
      if (!cleaned || seen.has(key)) continue;
      seen.add(key);
      merged.push(cleaned);
    }
    return merged.join(" • ").slice(0, 400);
  }

  function buildLiabilityRiskSummary(allText, genericSummary, label) {
    const sum = findGuaranteeSum(allText);
    const base = genericSummary || label;
    if (!sum || /suma/i.test(base)) return base;
    return `${base} (suma ${sum} zł)`;
  }

  function buildAccidentRiskSummary(allText, genericSummary) {
    const sum = firstMatch(allText, [
      /trwałego uszczerbku na zdrowiu(?:[^\n]{0,40}?Wariant\s*\d+)?\s*([0-9][0-9  ]{2,10})\s*(?:zł|PLN)/i,
      /Suma ubezpieczenia[^0-9\n]{0,80}?([0-9][0-9  ]{2,10})\s*(?:zł|PLN)/i,
    ]).replace(/\s+/g, " ");
    const accidentLabel = sum
      ? `Następstwa nieszczęśliwych wypadków (suma ${sum} zł)`
      : "Następstwa nieszczęśliwych wypadków";
    const otherParts = String(genericSummary || "")
      .split(" • ")
      .filter((part) => !/NASTEPSTW|NNW/.test(normalizeForDetection(part)));
    return mergeRiskParts(accidentLabel, ...otherParts);
  }

  function buildCropsRiskSummary(allText) {
    const scopeTokens = [
      ["Pakiet Wiosna", /PAKIET WIOSNA/],
      ["Pakiet Jesień", /PAKIET JESIEN/],
      ["Grad", /\bGRAD\b/],
      ["Ogień", /\bOGIEN\s*\(/],
      ["Przymrozki wiosenne", /PRZYMROZKI WIOSENNE/],
      ["Ujemne skutki przezimowania", /UJEMNE SKUTKI PRZEZIMOWANIA/],
      ["Powódź", /\bPOWODZ\b/],
      ["Deszcz nawalny", /DESZCZ NAWALNY/],
      ["Huragan", /\bHURAGAN\b/],
    ];
    const cropsSection = allText.split(/Składka łączna/i)[0];
    const detectionSection = normalizeForDetection(cropsSection);
    const labels = scopeTokens
      .filter(([, pattern]) => pattern.test(detectionSection))
      .map(([label]) => label);
    return ["Uprawy rolne", ...labels].join(" • ");
  }

  function buildFarmRiskSummary(allText) {
    const sections = [
      ["OC rolnika", /ODPOWIEDZIALNOSCI CYWILNEJ ROLNIKOW/],
      ["Budynki rolnicze", /UBEZPIECZENIE BUDYNKOW WCHODZACYCH W SKLAD GOSPODARSTWA ROLNEGO|BUDYNKI ROLNICZE/],
      ["Mienie ruchome", /MIENIE RUCHOME W GOSPODARSTWIE/],
      ["NNW", /NASTEPSTW NIESZCZESLIWYCH WYPADKOW/],
      ["OC w życiu prywatnym", /OC W ZYCIU PRYWATNYM|ODPOWIEDZIALNOSC CYWILNA W ZYCIU PRYWATNYM/],
    ];
    const detectionSection = normalizeForDetection(allText.split(/Warunki ubezpieczenia/i)[0]);
    const labels = sections
      .filter(([, pattern]) => pattern.test(detectionSection))
      .map(([label]) => label);
    return labels.join(" • ") || "Gospodarstwo rolne";
  }

  function buildPropertyRiskSummary(allText, genericSummary, label) {
    const subjectTokens = [
      ["budynki/lokale", /BUDYNKI,\s*(?:BUDOWLE,\s*)?LOKALE|BUDYNKI,\s*LOKALE,\s*BUDOWLE|BUDYNEK LUB LOKAL/],
      ["maszyny i wyposażenie", /MASZYNY,\s*WYPOSAZENIE|MASZYNY I URZADZENIA/],
      ["środki obrotowe", /SRODKI OBROTOWE/],
      ["sprzęt elektroniczny", /SPRZET ELEKTRONICZNY/],
      ["nakłady inwestycyjne", /NAKLADY INWESTYCYJNE/],
      ["mienie osób trzecich", /MIENIE OSOB TRZECICH/],
    ];
    const detectionSection = normalizeForDetection(allText.split(/Warunki ubezpieczenia/i)[0]);
    const labels = subjectTokens
      .filter(([, pattern]) => pattern.test(detectionSection))
      .map(([subject]) => subject);
    const sum = firstMatch(allText, [
      /Suma ubezpieczenia[^0-9\n]{0,80}?([0-9][0-9  ]{2,14}(?:[.,][0-9]{1,2})?)\s*(?:zł|PLN)/i,
    ]).replace(/\s+/g, " ");
    return mergeRiskParts(sum ? `${label} (suma ${sum} zł)` : label, ...labels, genericSummary || "");
  }

  function getPolicyHolderSection(lines) {
    const startIndex = lines.findIndex((line) => (
      /^\d*\s*UBEZPIECZAJACY\b/.test(normalizeForDetection(line))
    ));
    if (startIndex < 0) return [];
    const endIndex = lines.findIndex((line, index) => (
      index > startIndex
      && /^\d*\s*(?:UBEZPIECZONY\b|LOKALIZACJA\s*:|MIEJSCE UBEZPIECZENIA\s*:)/.test(normalizeForDetection(line))
    ));
    return lines.slice(startIndex, endIndex > startIndex ? endIndex : startIndex + 6);
  }

  function findClientName(holderLines) {
    if (holderLines.length === 0) return "";
    const inline = firstMatch(holderLines[0], [
      /Ubezpieczający\s*(?:\/\s*Policyholder)?\s*:\s*([^\n]+)/i,
    ]).replace(/\s*(?:PESEL|NIP|REGON)\s*:.*$/i, "").trim();
    if (inline) return inline;
    const nameParts = [];
    for (const line of holderLines.slice(1)) {
      if (/^(PESEL|NIP|REGON|ADRES|E-?MAIL|TELEFON)\b/i.test(normalizeForDetection(line))) break;
      const candidate = normalizeLine(line);
      if (candidate) nameParts.push(candidate);
    }
    return nameParts.join(" ");
  }

  function findContact(holderText) {
    const rawEmail = firstMatch(holderText, [/E-?mail\s*:\s*([^\n]+?)(?=\s+Telefon\s*:|$)/i]);
    const rawPhone = firstMatch(holderText, [/Telefon\s*:\s*([^\n]+)/i]);
    const email = /@/.test(rawEmail) && !/NIEUSTALON|ODMOW/i.test(normalizeForDetection(rawEmail))
      ? rawEmail
      : "";
    const phoneDigits = rawPhone.replace(/\D/g, "");
    const phone = phoneDigits.length >= 7 && !/NIEUSTALON|ODMOW/i.test(normalizeForDetection(rawPhone))
      ? rawPhone.replace(/[()\s-]+/g, "")
      : "";
    return [
      phone ? `Telefon: ${phone}` : "",
      email ? `E-mail: ${email}` : "",
    ].filter(Boolean).join("\n");
  }

  function findInsurancePeriod(allText) {
    
    
    const match = allText.match(
      /Okres ubezpieczenia[^:\n]{0,40}:\s*od[^0-9\n]{0,12}(\d{2}\.\d{2}\.\d{4})(?:\s*r\.)?(?:\s*godz\.\s*\d{1,2}:\d{2})?[^0-9]{0,20}?do[^0-9\n]{0,12}(\d{2}\.\d{2}\.\d{4})(?:\s*r\.)?/i,
    );
    return match ? [toIsoDate(match[1]), toIsoDate(match[2])] : ["", ""];
  }

  function parsePzuPropertyPolicy({ lines, allText, detectionText }) {
    const definition = matchProductDefinition(detectionText);
    const holderLines = getPolicyHolderSection(lines);
    const holderText = holderLines.join("\n");
    const insurancePeriod = findInsurancePeriod(allText);
    const policy = {
      clientName: findClientName(holderLines),
      identityNumber: firstMatch(holderText, [/(?:REGON|PESEL|NIP)\s*:\s*([0-9][0-9 .-]{7,18})/i]).replace(/\D/g, ""),
      contact: findContact(holderText),
      policyNumber: firstMatch(allText, [/Numer polisy\s+([0-9A-Z/-]{6,})/i]),
      registration: definition?.registration || "Inne",
      clientAddress: helpers.findClientAddress(holderText),
      validFrom: insurancePeriod[0],
      validUntil: insurancePeriod[1],
      premium: cleanPremium(firstMatch(allText, [
        /Składka łączna[^:\n0-9]{0,40}:?\s*([0-9][0-9 .,' ]*)\s*(?:zł|PLN)/i,
      ])),
      riskSummary: definition
        ? definition.buildRiskSummary(allText, helpers.findRiskSummary(allText))
        : helpers.findRiskSummary(allText),
    };
    const missingRequiredFields = ["clientName", "policyNumber", "validUntil"]
      .filter((fieldName) => !policy[fieldName]);
    if (missingRequiredFields.length > 0) {
      const error = new Error(`Nie udało się pewnie odczytać danych klienta, numeru polisy lub okresu z polisy PZU ${definition?.product || "majątkowej"}.`);
      error.code = "POLICY_FIELDS_MISSING";
      error.insurer = "PZU";
      error.missingFields = missingRequiredFields;
      throw error;
    }
    return {
      product: definition?.product || "",
      policy,
      missingOptionalFields: ["identityNumber", "validFrom", "premium"]
        .filter((fieldName) => !policy[fieldName]),
    };
  }

  registry.register({
    id: "pzu-majatek",
    insurer: "PZU",
    product: "Majątek, OC, NNW, rolne",
    detect: ({ detectionText }) => /POWSZECHNY ZAKLAD UBEZPIECZEN/.test(detectionText)
      && !/PZU WOJAZER/.test(detectionText)
      && matchProductDefinition(detectionText) !== null,
    parse: parsePzuPropertyPolicy,
  });
})(globalThis);
