(function registerHestiaBusinessPolicyParser(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, cleanPremium } = helpers;

  
  
  function findBusinessClientName(holderLines) {
    const headerIndex = holderLines.findIndex((line) => (
      /^UBEZPIECZAJACY\s*\/\s*UBEZPIECZONY\s*:/.test(normalizeForDetection(line))
    ));
    if (headerIndex < 0) {
      return firstMatch(holderLines.join("\n"), [/Ubezpieczający\s*:\s*([^,\n]{3,180})/i]);
    }
    const headerLine = normalizeLine(holderLines[headerIndex]).replace(/^.*?Ubezpieczony\s*:\s*/i, "");
    const parts = [headerLine.split(",")[0].trim()];
    if (!headerLine.includes(",")) {
      for (let index = headerIndex + 1; index < holderLines.length; index += 1) {
        const line = normalizeLine(holderLines[index]);
        if (!line || /^(?:NIP|REGON|PESEL|ADRES|RODZAJ|KLASY|OKRES)\b/.test(normalizeForDetection(line))) break;
        parts.push(line.split(",")[0].trim());
        if (line.includes(",")) break;
      }
    }
    return parts.filter(Boolean).join(" ").slice(0, 180);
  }

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

  function findIdentityNumber(holderText) {
    const regon = firstMatch(holderText, [/REGON\s*:\s*([0-9][0-9 .-]{6,19})/i]).replace(/\D/g, "");
    if (regon) return regon;
    return firstMatch(holderText, [/(?:PESEL|NIP)\s*:\s*([0-9][0-9 .-]{7,18})/i]).replace(/\D/g, "");
  }

  function findInsurancePeriod(allText) {
    const combined = allText.match(
      /(?:^|\n)Od\s*:?\s*(\d{4}-\d{2}-\d{2})(?:\s+\d{1,2}:\d{2})?\s+do\s*:?\s*(\d{4}-\d{2}-\d{2})(?:\s+\d{1,2}:\d{2})?/i,
    );
    if (combined) return [combined[1], combined[2]];
    return [
      firstMatch(allText, [/(?:^|\n)Od\s*:?\s*(\d{4}-\d{2}-\d{2})(?:\s+\d{1,2}:\d{2})?/i]),
      firstMatch(allText, [/(?:^|\n)Do\s*:?\s*(\d{4}-\d{2}-\d{2})(?:\s+\d{1,2}:\d{2})?/i]),
    ];
  }

  
  
  
  
  const SUBJECT_DEFINITIONS = [
    ["Budynki/lokale", /^BUDYNKI,\s*BUDOWLE,\s*LOKALE/],
    ["Maszyny i wyposażenie", /^MASZYNY,\s*WYPOSAZENIE/],
    ["Sprzęt elektroniczny", /^SPRZET ELEKTRONICZNY/],
    ["Środki obrotowe", /^SRODKI OBROTOWE/],
    ["Nakłady inwestycyjne", /^NAKLADY INWESTYCYJNE/],
    ["Mienie osób trzecich", /^MIENIE OSOB TRZECICH/],
    ["Wartości pieniężne", /^WARTOSCI PIENIEZNE/],
    ["Szyby", /^SZYBY OD STLUCZENIA|^SZYBY\b/],
  ];
  const ROW_END_PATTERN = /^(?:LICZBA SZKOD|FRANSZYZ|UMOWE UBEZPIECZENIA|OGOLNE WARUNKI|KLAUZUL|PLATNOSC|OC (?:DZIALALNOSCI|ZAWODOWE)|UBEZPIECZENIE (?:MIENIA|SPRZETU)|BIZNES ASSISTANCE|SKLADKA LACZNA|TRESC KLAUZUL)/;

  function findPropertyTableRisks(allText) {
    const lines = allText.split("\n");
    const normalizedLines = lines.map(helpers.normalizeForDetection);
    const risks = [];
    for (let index = 0; index < lines.length; index += 1) {
      const definition = SUBJECT_DEFINITIONS.find(([, pattern]) => pattern.test(normalizedLines[index]));
      if (!definition || risks.some(([label]) => label === definition[0])) continue;
      const rowLines = [lines[index]];
      for (let offset = 1; offset <= 8 && index + offset < lines.length; offset += 1) {
        const nextNormalized = normalizedLines[index + offset];
        if (ROW_END_PATTERN.test(nextNormalized)) break;
        if (SUBJECT_DEFINITIONS.some(([, pattern]) => pattern.test(nextNormalized))) break;
        rowLines.push(lines[index + offset]);
        
        if (/[0-9]\s*PLN\s*$/.test(lines[index + offset])) break;
      }
      const amounts = [...rowLines.join(" ").matchAll(/([0-9][0-9  ]*(?:[.,][0-9]{1,2})?)\s*PLN/g)];
      const amount = amounts.length > 1 ? amounts.at(-1)[1].replace(/\s+/g, " ").trim() : "";
      risks.push([definition[0], amount]);
    }
    return risks
      .map(([label, amount]) => (amount ? `${label} ${amount} zł` : label))
      .join(" • ");
  }

  
  function findSectionPremium(allText, headerPattern) {
    const lines = allText.split("\n");
    const normalizedLines = lines.map(helpers.normalizeForDetection);
    const headerIndex = normalizedLines.findIndex((line) => headerPattern.test(line));
    if (headerIndex < 0) return "";
    for (let index = headerIndex; index < Math.min(lines.length, headerIndex + 12); index += 1) {
      if (index > headerIndex && /^(?:KLAUZULE PRODUKTOWE|PLATNOSC)/.test(normalizedLines[index])) break;
      const amount = lines[index].match(/Składka\s*:\s*([0-9][0-9  ]*(?:[.,][0-9]{1,2})?)\s*PLN/i);
      if (amount) return amount[1].replace(/\s+/g, " ").trim();
    }
    return "";
  }

  function findAssistanceRisks(allText) {
    const risks = [];
    for (const line of allText.split("\n")) {
      const normalized = helpers.normalizeForDetection(line);
      if (!/^BIZNES ASSISTANCE/.test(normalized)) continue;
      const label = /OCHRONA PRAWNA/.test(normalized) ? "Ochrona prawna" : "Assistance";
      if (risks.some(([existing]) => existing === label)) continue;
      const amounts = [...line.matchAll(/([0-9][0-9  ]*(?:[.,][0-9]{1,2})?)\s*PLN/g)];
      risks.push([label, amounts.length > 0 ? amounts.at(-1)[1].replace(/\s+/g, " ").trim() : ""]);
    }
    return risks.map(([label, amount]) => (amount ? `${label} ${amount} zł` : label)).join(" • ");
  }

  function findBusinessRiskSummary(allText, premium) {
    const liabilityRisk = [
      [/OC zawodowe/i, "OC zawodowe", /^OC ZAWODOWE/],
      [/OC działalności gospodarczej/i, "OC działalności", /^OC DZIALALNOSCI GOSPODARCZEJ/],
      [/Ubezpieczenie sprzętu elektronicznego/i, "Sprzęt elektroniczny", /^UBEZPIECZENIE SPRZETU ELEKTRONICZNEGO/],
    ].find(([pattern]) => pattern.test(allText));
    const propertyRisks = /Ubezpieczenie mienia/i.test(allText) ? findPropertyTableRisks(allText) : "";
    const assistanceRisks = findAssistanceRisks(allText);
    const parts = [];
    if (liabilityRisk) {
      
      
      const sectionPremium = findSectionPremium(allText, liabilityRisk[2])
        || (!propertyRisks && !assistanceRisks ? premium : "");
      parts.push(sectionPremium ? `${liabilityRisk[1]} ${sectionPremium} zł` : liabilityRisk[1]);
    }
    if (propertyRisks) parts.push(propertyRisks);
    if (assistanceRisks) parts.push(assistanceRisks);
    if (parts.length === 0) return helpers.findRiskSummary(allText);
    return parts.join(" • ").slice(0, 400);
  }

  function parseHestiaBusinessPolicy({ lines, allText }) {
    const holderLines = getPolicyHolderSection(lines);
    const holderText = holderLines.join("\n");
    const insurancePeriod = findInsurancePeriod(allText);
    const premium = cleanPremium(firstMatch(allText, [
      /Do zapłaty\s*:\s*([0-9][0-9 .,'\u00a0]*)\s*PLN/i,
    ]));
    const policy = {
      clientName: findBusinessClientName(holderLines),
      identityNumber: findIdentityNumber(holderText),
      contact: "",
      policyNumber: firstMatch(allText, [
        /Polisa ubezpieczenia majątkowego ERGO Biznes\s+nr\s+([0-9A-Z/-]{6,})/i,
      ]),
      registration: "Firma",
      clientAddress: helpers.findClientAddress(holderText),
      validFrom: insurancePeriod[0],
      validUntil: insurancePeriod[1],
      premium,
      riskSummary: findBusinessRiskSummary(allText, premium),
    };
    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 ERGO Biznes.");
      error.code = "POLICY_FIELDS_MISSING";
      error.insurer = "Hestia";
      error.missingFields = missingRequiredFields;
      throw error;
    }
    return {
      policy,
      missingOptionalFields: ["identityNumber", "validFrom", "premium"]
        .filter((fieldName) => !policy[fieldName]),
    };
  }

  registry.register({
    id: "hestia-biznes",
    insurer: "Hestia",
    product: "Firma",
    detect: ({ detectionText }) => /POLISA UBEZPIECZENIA MAJATKOWEGO ERGO BIZNES\s+NR\s+[0-9A-Z/-]+/.test(detectionText)
      && /ERGO HESTIA/.test(detectionText),
    parse: parseHestiaBusinessPolicy,
  });
})(globalThis);
