(function registerHestiaHomePolicyParser(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 } = helpers;

  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 && /^MIEJSCE UBEZPIECZENIA$/.test(normalizeForDetection(line))
    ));
    return lines.slice(startIndex, endIndex > startIndex ? endIndex : startIndex + 8);
  }

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

  function findInsurancePeriod(allText) {
    const match = allText.match(
      /Okres ubezpieczenia\s+od\s+(\d{4}-\d{2}-\d{2})(?:\s+\d{1,2}:\d{2})?\s+do\s+(\d{4}-\d{2}-\d{2})(?:\s+\d{1,2}:\d{2})?/i,
    );
    return match ? [match[1], match[2]] : ["", ""];
  }

  function parseAmount(value) {
    const amount = Number(String(value ?? "").replace(/[\s\u00a0]/g, "").replace(",", "."));
    return Number.isFinite(amount) ? amount : null;
  }

  function formatAmount(value) {
    return new Intl.NumberFormat("pl-PL", { maximumFractionDigits: 2 }).format(value);
  }

  function findHomePremium(allText) {
    const lines = String(allText ?? "").split(/\r?\n/);
    const paymentStart = lines.findIndex((line) => /^PLATNOSCI\b/.test(normalizeForDetection(line)));
    const coverageText = lines.slice(0, paymentStart >= 0 ? paymentStart : lines.length).join("\n");
    const amounts = [...coverageText.matchAll(/RAZEM DO ZAPŁATY\s+([0-9][0-9\s\u00a0]*(?:[.,][0-9]{1,2})?)/gi)]
      .map((match) => parseAmount(match[1]))
      .filter((amount) => amount !== null);
    if (amounts.length === 0) return "";
    
    
    
    const total = amounts.reduce((sum, amount) => sum + amount, 0);
    const highest = Math.max(...amounts);
    if (amounts.length > 1 && Math.abs(highest * 2 - total) < 0.005) return formatAmount(highest);
    return formatAmount(total);
  }

  function findHomeRiskSummary(allText, totalPremium) {
    const allLines = String(allText ?? "").split(/\r?\n/).map(normalizeLine).filter(Boolean);
    const normalizedLines = allLines.map(normalizeForDetection);
    const firstTable = normalizedLines.findIndex((line) => /^PRODUKT UBEZPIECZENIOWY\b/.test(line));
    const paymentIndex = normalizedLines.findIndex((line, index) => index > firstTable && /^PLATNOSCI\b/.test(line));
    if (firstTable < 0) return helpers.findRiskSummary(allText);
    const endIndex = paymentIndex > firstTable ? paymentIndex : allLines.length;
    
    
    
    
    const rowStartPattern = /^(?:[\p{L} ]{0,40}\s)?\d+\s+\p{L}|^ODPOWIEDZIALNOSC CYWILNA\b|^UBEZPIECZENIA DODATKOWE\s+\d+\s+HOME ASSISTANCE/u;
    const rows = [];
    let current = null;
    for (let index = firstTable; index < endIndex; index += 1) {
      const normalized = normalizedLines[index];
      if (/^RAZEM DO ZAPLATY\b/.test(normalized)) {
        if (current) rows.push(current);
        current = null;
        continue;
      }
      if (rowStartPattern.test(normalized)) {
        
        
        
        const danglingLabel = current && !/[0-9]/.test(current.normalized.join(" ")) ? current : null;
        if (current && !danglingLabel) rows.push(current);
        current = {
          lines: [...(danglingLabel?.lines || []), allLines[index]],
          normalized: [...(danglingLabel?.normalized || []), normalized],
        };
      } else if (current && !/^PRODUKT UBEZPIECZENIOWY\b|^SUMA (?:UBEZPIECZENIA|GWARANCYJNA)/.test(normalized)) {
        current.lines.push(allLines[index]);
        current.normalized.push(normalized);
      }
    }
    if (current) rows.push(current);

    const risks = new Map();
    for (const row of rows) {
      const text = row.lines.join(" ");
      const normalized = row.normalized.join(" ");
      let label = "";
      if (/^ODPOWIEDZIALNOSC CYWILNA\b/.test(normalized)) label = "OC w życiu prywatnym";
      else if (/\bOC NAJEMCY\b/.test(normalized)) label = "OC Najemcy";
      else if (/^UBEZPIECZENIA DODATKOWE/.test(normalized) && /HOME ASSISTANCE/.test(normalized)) label = "Home Assistance";
      else if (/\bMIESZKANIE\b/.test(normalized) && /HOME ASSISTANCE/.test(normalized)) label = "Mieszkanie + Home Assistance";
      else if (/\bMIESZKANIE\b/.test(normalized)) label = "Mieszkanie";
      else if (/\bDOMEK LETNISKOWY\b/.test(normalized)) label = "Domek letniskowy";
      else if (/\bBUDYNKI GOSPODARCZE\b/.test(normalized)) label = "Budynki gospodarcze";
      else if (/\bDOM\b/.test(normalized)) label = "Dom";
      else if (/\bWYPOSAZENIE\b/.test(normalized)) label = "Wyposażenie";
      else if (/\bRZECZY OSOBISTE\b/.test(normalized)) label = "Rzeczy osobiste";
      else if (/\bARCHITEKTURA OGRODU\b/.test(normalized)) label = "Architektura ogrodu";
      else if (/\bSOS ASSISTANCE\b/.test(normalized)) label = "SOS Assistance";
      else if (/\bHOME ASSISTANCE\b/.test(normalized)) label = "Home Assistance";
      if (!label) continue;
      
      
      
      
      
      const amountLines = [...row.lines];
      while (amountLines.length > 1 && !/[0-9]/.test(amountLines.at(-1))) amountLines.pop();
      const trailingAmount = helpers.findRowTrailingAmount(amountLines.join(" "), totalPremium);
      const numericAmount = trailingAmount ? parseAmount(trailingAmount) : null;
      const previous = risks.get(label);
      if (numericAmount !== null) risks.set(label, (previous ?? 0) + numericAmount);
      else if (!risks.has(label)) risks.set(label, null);
    }
    return [...risks]
      .map(([label, amount]) => (amount === null ? label : `${label} ${formatAmount(amount)} zł`))
      .join(" • ")
      .slice(0, 400);
  }

  function parseHestiaHomePolicy({ lines, allText }) {
    const holderText = getPolicyHolderSection(lines).join("\n");
    const insurancePeriod = findInsurancePeriod(allText);
    const homePremium = findHomePremium(allText);
    const policy = {
      clientName: firstMatch(holderText || allText, [
        /Ubezpieczający(?:\s*\/\s*Ubezpieczony)?\s*\n([^\n,]{3,180})(?=\s*,\s*DATA URODZENIA\s*:|\n)/i,
      ]),
      identityNumber: findIdentityNumber(holderText),
      contact: "",
      policyNumber: firstMatch(allText, [
        /Polisa\s+E7\s+([0-9A-Z/-]{6,})/i,
      ]),
      registration: "Mieszkanie",
      clientAddress: helpers.findClientAddress(holderText),
      validFrom: insurancePeriod[0],
      validUntil: insurancePeriod[1],
      premium: homePremium,
      
      
      riskSummary: findHomeRiskSummary(allText, parseAmount(homePremium)) || 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 mieszkaniowej ERGO Hestii.");
      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-mieszkanie",
    insurer: "Hestia",
    product: "Mieszkanie",
    detect: ({ detectionText }) => /POLISA E7\s+[0-9A-Z/-]+/.test(detectionText)
      && /MIEJSCE UBEZPIECZENIA/.test(detectionText)
      && /ERGO HESTIA/.test(detectionText),
    parse: parseHestiaHomePolicy,
  });
})(globalThis);
