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

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

  const {
    normalizeLine,
    normalizeForDetection,
    firstMatch,
    normalizeVehicleIdentifier,
    findVehicleMakeAndModel,
    findFirstRegistrationDate,
    findVehicleExtraDetails,
    findClientAddress,
    findRiskSummary,
    cleanPremium,
  } = helpers;

  function isPolicyHolderRoleLine(line) {
    const normalized = normalizeForDetection(line);
    return /^UBEZPIECZAJACY(?:\s*,\s*(?:UZYTKOWNIK|UBEZPIECZONY(?:\s*\/\s*WLASCICIEL)?)|\s*\/\s*POLICY HOLDER)?\s*:?\s*$/.test(normalized);
  }

  function isLikelyClientName(line) {
    const candidate = normalizeLine(line);
    if (!candidate || candidate.length > 180) return false;
    return !/^(\$\{QR_CODE\}|DANE\b|UBEZPIECZAJ|PESEL\b|NIP\b|REGON\b|ADRES\b|SIEDZIBA\b|TELEFON\b|E-?MAIL\b|POLISA\b|WNIOSEK\b|SKLADKA\b|OKRES\b|PLATNOSC\b)/.test(normalizeForDetection(candidate));
  }

  function findClientName(lines) {
    const roleIndex = lines.findIndex(isPolicyHolderRoleLine);
    if (roleIndex >= 0) {
      const isBilingualTravelPolicy = /POLICY HOLDER/.test(normalizeForDetection(lines[roleIndex]));
      if (isBilingualTravelPolicy) {
        const nameParts = [];
        for (let index = roleIndex + 1; index < Math.min(lines.length, roleIndex + 10); index += 1) {
          const normalized = normalizeForDetection(lines[index]);
          if (/^(OSOBY UBEZPIECZONE|PERSONS INSURED|OKRES UBEZPIECZENIA|POLICY PERIOD)\b/.test(normalized)) break;
          if (isLikelyClientName(lines[index])) nameParts.push(normalizeLine(lines[index]));
          else if (nameParts.length > 0) break;
        }
        if (nameParts.length > 0) return nameParts.join(" ");
      } else {
        let clientHeaderIndex = -1;
        for (let index = roleIndex - 1; index >= Math.max(0, roleIndex - 10); index -= 1) {
          if (/^DANE KLIENTA\b/.test(normalizeForDetection(lines[index]))) {
            clientHeaderIndex = index;
            break;
          }
        }
        if (clientHeaderIndex >= 0) {
          const nameParts = lines
            .slice(clientHeaderIndex + 1, roleIndex)
            .filter(isLikelyClientName)
            .map(normalizeLine);
          if (nameParts.length > 0) return nameParts.join(" ");
        }
        for (let index = roleIndex - 1; index >= Math.max(0, roleIndex - 8); index -= 1) {
          if (isLikelyClientName(lines[index])) return normalizeLine(lines[index]);
        }
      }
    }

    const joinedText = lines.join("\n");
    return firstMatch(joinedText, [
      /(?:^|\n)UBEZPIECZAJĄCY(?:\s*,\s*UBEZPIECZONY(?:\s*\/\s*WŁAŚCICIEL)?)?\s*:[^\S\r\n]*([^\n]+?)(?=[^\S\r\n]+(?:PESEL|NIP|REGON)\s*:|$)/im,
      /(?:^|\n)([^\n]{3,180})\nUBEZPIECZAJĄCY(?:\s*,\s*UBEZPIECZONY(?:\s*\/\s*WŁAŚCICIEL)?)?\s*:/im,
      /UBEZPIECZAJĄCY\s*\/\s*POLICY HOLDER\s*:?\s*\n([^\n]{3,180})/im,
    ]);
  }

  function getClientSectionText(lines) {
    const roleIndex = lines.findIndex(isPolicyHolderRoleLine);
    return roleIndex >= 0
      ? lines.slice(roleIndex, Math.min(lines.length, roleIndex + 15)).join("\n")
      : lines.slice(0, Math.min(lines.length, 35)).join("\n");
  }

  function findIdentityNumber(lines) {
    return firstMatch(getClientSectionText(lines), [
      /(?:PESEL(?:\s*\/\s*Personal Identification Number)?|NIP|REGON)\s*:\s*([0-9][0-9 .-]{7,18})/i,
    ]).replace(/[^0-9]/g, "");
  }

  function findInsurancePeriod(allText) {
    const labelledPeriod = allText.match(
      /(?:^|\s)OD\s*:\s*(\d{4}-\d{2}-\d{2})(?:\s+godz\.\s*\d{1,2}:\d{2})?\s+DO\s*:\s*(\d{4}-\d{2}-\d{2})(?:\s+godz\.\s*\d{1,2}:\d{2})?/i,
    );
    if (labelledPeriod) return [labelledPeriod[1], labelledPeriod[2]];
    const tablePeriod = allText.match(
      /(?:^|\s)(\d{4}-\d{2}-\d{2})(?:\s+godz\.\s*\d{1,2}:\d{2})?\s*-\s*(\d{4}-\d{2}-\d{2})(?:\s|$)/i,
    );
    return tablePeriod ? [tablePeriod[1], tablePeriod[2]] : ["", ""];
  }

  function findTotalPremium(allText) {
    return cleanPremium(firstMatch(allText, [
      /SKŁADKA\s+ŁĄCZNA(?:\s*\/\s*TOTAL PREMIUM)?\s*([0-9][0-9 .,'\u00a0]*)\s*zł/i,
      /([0-9][0-9 .,'\u00a0]*)\s*zł\s+SKŁADKA\s+ŁĄCZNA/i,
      /SKŁADKA\s+RAZEM\s*([0-9][0-9 .,'\u00a0]*)\s*zł/i,
      /Kwota\s*:\s*([0-9][0-9 .,'\u00a0]*)\s*zł\s+Forma\s+płatności\s*:/i,
    ]));
  }

  function findVin(allText) {
    return normalizeVehicleIdentifier(firstMatch(allText, [
      /Numer identyfikacyjny\s*\(VIN\)\s*:\s*([A-Z0-9][A-Z0-9 -]{3,23})/i,
      /(?:Nr|Numer)\s+(?:VIN|nadwozia|podwozia)\s*:\s*([A-Z0-9][A-Z0-9 -]{3,23})/i,
      /\bVIN\s*:\s*([A-Z0-9][A-Z0-9 -]{3,23})/i,
    ]));
  }

  function findRegistration(allText) {
    return firstMatch(allText, [
      /(?:NUMER|NR)\s+REJESTRACYJNY\s*:\s*([A-Z0-9][A-Z0-9 -]{3,11})/i,
      /NR\s+REJ\.?\s*:\s*([A-Z0-9][A-Z0-9 -]{3,11})/i,
    ]).replace(/\s+/g, "").toLocaleUpperCase("pl");
  }

  function isWartaPolicy(detectionText) {
    return /\bWARTA\b/.test(detectionText)
      && /(TUIR WARTA|WNIOSEK-POLISA|POLISA WARTA)/.test(detectionText);
  }

  function parse(context, {
    registrationLabel = "",
    requireVehicle = false,
    riskSummaryResolver = findRiskSummary,
  } = {}) {
    const { lines, allText } = context;
    const policyNumber = firstMatch(allText, [
      /WNIOSEK-POLISA(?:\s*\/\s*PROPOSAL-POLICY)?(?:\s+WARTA[^\n]*?)?\s+NR\s*:\s*([0-9A-Z][0-9A-Z/-]{5,})/i,
      
      /WNIOSEK-POLISA\s+SMARTBIZNES\s+NR\s*:\s*([0-9A-Z][0-9A-Z/-]{5,})/i,
      /WNIOSEK-POLISA\s+(?:WARTA\s+)?PAKIET\s+BIZNES\s+NR\s*:\s*([0-9A-Z][0-9A-Z/-]{5,})/i,
      /POLISA\s+WARTA[^\n]*?\s+NR\s*:\s*([0-9A-Z][0-9A-Z/-]{5,})/i,
    ]);
    const email = firstMatch(allText, [/E-?mail\s*:\s*([^\s\n,;]+@[^\s\n,;]+)/i]);
    const phone = firstMatch(allText, [
      /Telefon(?:\s+komórkowy)?(?:\s*\/\s*Mobile phone)?\s*:\s*([+]?[0-9][0-9 ()-]{6,20})/i,
    ]).replace(/[()\s-]+/g, "");
    const insurancePeriod = findInsurancePeriod(allText);
    const registration = registrationLabel || findRegistration(allText);
    const policy = {
      clientName: findClientName(lines),
      identityNumber: findIdentityNumber(lines),
      contact: [phone ? `Telefon: ${phone}` : "", email ? `E-mail: ${email}` : ""].filter(Boolean).join("\n"),
      policyNumber,
      registration,
      ...findVehicleMakeAndModel(allText),
      vin: findVin(allText),
      firstRegistrationDate: findFirstRegistrationDate(allText),
      ...findVehicleExtraDetails(allText),
      clientAddress: findClientAddress(getClientSectionText(lines)),
      validFrom: insurancePeriod[0],
      validUntil: insurancePeriod[1],
      premium: findTotalPremium(allText),
      riskSummary: riskSummaryResolver(allText),
    };
    const requiredFields = ["clientName", "policyNumber", "validUntil"];
    if (requireVehicle) requiredFields.push("registration");
    const missingRequiredFields = requiredFields.filter((fieldName) => !policy[fieldName]);
    if (missingRequiredFields.length > 0) {
      const error = new Error("Nie udało się pewnie odczytać wymaganych danych z polisy Warty.");
      error.code = "POLICY_FIELDS_MISSING";
      error.insurer = "Warta";
      error.missingFields = missingRequiredFields;
      throw error;
    }
    return {
      policy,
      missingOptionalFields: ["identityNumber", "validFrom", "premium", "riskSummary"]
        .filter((fieldName) => !policy[fieldName]),
    };
  }

  globalScope.WartaPolicyParserCommon = Object.freeze({ isWartaPolicy, parse });
})(globalThis);
