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

  function normalizePersonName(value) {
    return String(value ?? "")
      .toLocaleLowerCase("pl")
      .normalize("NFKD")
      .replace(/[\u0300-\u036f]/g, "")
      .replace(/ł/g, "l")
      .replace(/[^a-z0-9]+/g, " ")
      .replace(/\s+/g, " ")
      .trim();
  }

  function cleanPersonName(value) {
    return String(value ?? "").replace(/\s+/g, " ").trim();
  }

  function collapseRepeatedPersonName(value) {
    const personName = cleanPersonName(value);
    if (!personName) return "";

    const parts = personName.split(/\s*[,;|/]\s*/).map(cleanPersonName).filter(Boolean);
    if (
      parts.length > 1
      && parts.every((part) => normalizePersonName(part) === normalizePersonName(parts[0]))
    ) {
      return parts[0];
    }

    const words = personName.replace(/[,;|/]+/g, " ").split(/\s+/).filter(Boolean);
    if (words.length >= 4 && words.length % 2 === 0) {
      const midpoint = words.length / 2;
      const firstHalf = words.slice(0, midpoint).join(" ");
      const secondHalf = words.slice(midpoint).join(" ");
      if (normalizePersonName(firstHalf) === normalizePersonName(secondHalf)) return firstHalf;
    }
    return personName;
  }

  function getPersonNameKey(value) {
    const tokens = normalizePersonName(value).split(" ").filter(Boolean);
    if (tokens.length < 2) return "";
    return tokens.sort((first, second) => first.localeCompare(second, "pl")).join("\u0000");
  }

  function getPesel(value) {
    const digits = String(value ?? "").replace(/\D/g, "");
    return digits.length === 11 ? digits : "";
  }

  function isValidPesel(value) {
    const pesel = getPesel(value);
    if (!pesel) return false;
    const weights = [1, 3, 7, 9, 1, 3, 7, 9, 1, 3];
    const checksum = weights.reduce((sum, weight, index) => (
      sum + (Number(pesel[index]) * weight)
    ), 0);
    return (10 - (checksum % 10)) % 10 === Number(pesel[10]);
  }

  function isMissingIdentity(value) {
    const normalized = String(value ?? "").trim().toLocaleLowerCase("pl");
    return !normalized || /^(?:-|brak|nie podano|nie ustalono|n\/?a)$/.test(normalized);
  }

  function normalizeVehicleIdentifier(value) {
    const identifier = String(value ?? "").replace(/[^A-Z0-9]/gi, "").toUpperCase();
    return identifier.length >= 5 ? identifier : "";
  }

  function normalizeVehicleRegistration(value) {
    const registration = String(value ?? "").replace(/[^A-Z0-9]/gi, "").toUpperCase();
    return /^(?=.*\d)[A-Z0-9]{4,12}$/.test(registration) ? registration : "";
  }

  function normalizeFirstRegistrationDate(value) {
    const rawValue = String(value ?? "").trim();
    let year;
    let month;
    let day;
    const isoMatch = rawValue.match(/^(\d{4})-(\d{1,2})-(\d{1,2})$/);
    const polishMatch = rawValue.match(/^(\d{1,2})[./-](\d{1,2})[./-](\d{4})$/);
    if (isoMatch) {
      [, year, month, day] = isoMatch.map(Number);
    } else if (polishMatch) {
      [, day, month, year] = polishMatch.map(Number);
    } else {
      return "";
    }
    const parsed = new Date(year, month - 1, day);
    if (
      parsed.getFullYear() !== year
      || parsed.getMonth() !== month - 1
      || parsed.getDate() !== day
    ) return "";
    const today = new Date();
    today.setHours(0, 0, 0, 0);
    if (parsed > today) return "";
    return `${String(year).padStart(4, "0")}-${String(month).padStart(2, "0")}-${String(day).padStart(2, "0")}`;
  }

  function getVehicleMatchScore(target, source) {
    const targetVin = normalizeVehicleIdentifier(target?.vin);
    const sourceVin = normalizeVehicleIdentifier(source?.vin);
    if (targetVin && sourceVin) return targetVin === sourceVin ? 2 : 0;

    const targetRegistration = normalizeVehicleRegistration(target?.registration);
    const sourceRegistration = normalizeVehicleRegistration(source?.registration);
    return targetRegistration && targetRegistration === sourceRegistration ? 1 : 0;
  }

  function findFirstRegistrationDateChanges(records) {
    const policyRecords = Array.isArray(records) ? records : [];
    
    
    
    const sourcesByVin = new Map();
    const sourcesByRegistration = new Map();
    const sourcesByRegistrationWithoutVin = new Map();
    const pushSource = (map, key, entry) => {
      if (!key) return;
      const list = map.get(key);
      if (list) list.push(entry);
      else map.set(key, [entry]);
    };
    for (const source of policyRecords) {
      const date = normalizeFirstRegistrationDate(source?.firstRegistrationDate);
      if (!date) continue;
      const entry = { id: String(source?.id ?? ""), date };
      const vin = normalizeVehicleIdentifier(source?.vin);
      const registration = normalizeVehicleRegistration(source?.registration);
      if (vin) pushSource(sourcesByVin, vin, entry);
      if (registration) {
        pushSource(sourcesByRegistration, registration, entry);
        if (!vin) pushSource(sourcesByRegistrationWithoutVin, registration, entry);
      }
    }

    const changes = [];
    for (const target of policyRecords) {
      const targetId = String(target?.id ?? "");
      if (!targetId || normalizeFirstRegistrationDate(target?.firstRegistrationDate)) continue;

      const targetVin = normalizeVehicleIdentifier(target?.vin);
      const targetRegistration = normalizeVehicleRegistration(target?.registration);
      let bestScore = 0;
      let bestCandidates = [];
      if (targetVin) {
        
        const vinMatches = (sourcesByVin.get(targetVin) || []).filter((entry) => entry.id !== targetId);
        if (vinMatches.length > 0) {
          bestScore = 2;
          bestCandidates = vinMatches;
        } else if (targetRegistration) {
          
          bestCandidates = (sourcesByRegistrationWithoutVin.get(targetRegistration) || []).filter((entry) => entry.id !== targetId);
          if (bestCandidates.length > 0) bestScore = 1;
        }
      } else if (targetRegistration) {
        bestCandidates = (sourcesByRegistration.get(targetRegistration) || []).filter((entry) => entry.id !== targetId);
        if (bestCandidates.length > 0) bestScore = 1;
      }
      if (bestCandidates.length === 0) continue;

      const dates = new Set(bestCandidates.map((candidate) => candidate.date));
      if (dates.size !== 1) continue;

      const [firstRegistrationDate] = dates;
      changes.push(Object.freeze({
        targetId,
        firstRegistrationDate,
        matchType: bestScore === 2 ? "vin" : "registration",
        sourceIds: Object.freeze(bestCandidates.map((candidate) => candidate.id)),
      }));
    }
    return changes.sort((first, second) => first.targetId.localeCompare(second.targetId, "pl"));
  }

  function findMissingIdentityRecords(records) {
    const uniqueIds = new Set();
    return (Array.isArray(records) ? records : [])
      .filter((policy) => {
        const id = String(policy?.id ?? "");
        if (!id || uniqueIds.has(id) || !isMissingIdentity(policy?.identityNumber)) return false;
        uniqueIds.add(id);
        return true;
      })
      .sort((first, second) => {
        const firstName = normalizePersonName(first?.clientName) || "\uffff";
        const secondName = normalizePersonName(second?.clientName) || "\uffff";
        return firstName.localeCompare(secondName, "pl")
          || String(first?.policyNumber ?? "").localeCompare(String(second?.policyNumber ?? ""), "pl");
      })
      .map((policy) => Object.freeze({ targetId: String(policy.id) }));
  }

  function findReviewCandidates(records) {
    const policyRecords = Array.isArray(records) ? records : [];
    const groups = new Map();
    for (const policy of policyRecords) {
      if (!policy?.id) continue;
      const nameKey = getPersonNameKey(policy.clientName);
      if (!nameKey) continue;
      if (!groups.has(nameKey)) groups.set(nameKey, []);
      groups.get(nameKey).push(policy);
    }

    const candidates = [];
    for (const [nameKey, group] of groups) {
      if (group.length < 2) continue;
      const targets = group.filter((policy) => isMissingIdentity(policy.identityNumber));
      if (targets.length === 0) continue;

      const sourcesByPesel = new Map();
      for (const policy of group) {
        const pesel = getPesel(policy.identityNumber);
        if (!pesel) continue;
        if (!sourcesByPesel.has(pesel)) sourcesByPesel.set(pesel, []);
        sourcesByPesel.get(pesel).push(String(policy.id));
      }

      for (const target of targets) {
        for (const [pesel, sourceIds] of sourcesByPesel) {
          candidates.push(Object.freeze({
            nameKey,
            targetId: String(target.id),
            pesel,
            sourceIds: Object.freeze([...sourceIds]),
          }));
        }
      }
    }

    return candidates.sort((first, second) => {
      const firstTarget = policyRecords.find((policy) => String(policy?.id) === first.targetId);
      const secondTarget = policyRecords.find((policy) => String(policy?.id) === second.targetId);
      return normalizePersonName(firstTarget?.clientName)
        .localeCompare(normalizePersonName(secondTarget?.clientName), "pl");
    });
  }

  function getRecordFreshness(record) {
    const updatedAt = Number(record?.updatedAt);
    if (Number.isFinite(updatedAt) && updatedAt > 0) return updatedAt;
    const createdAt = Number(record?.createdAt);
    return Number.isFinite(createdAt) && createdAt > 0 ? createdAt : 0;
  }

  function findNameUnificationChanges(records) {
    const policyRecords = Array.isArray(records) ? records : [];
    const groups = new Map();
    const effectiveNames = new Map();
    const changesById = new Map();

    for (const policy of policyRecords) {
      const id = String(policy?.id ?? "");
      const currentName = cleanPersonName(policy?.clientName);
      const effectiveName = collapseRepeatedPersonName(currentName);
      effectiveNames.set(policy, effectiveName);
      if (id && currentName && effectiveName && currentName !== effectiveName) {
        changesById.set(id, {
          targetId: id,
          pesel: getPesel(policy?.identityNumber),
          nameKey: getPersonNameKey(effectiveName),
          currentName,
          canonicalName: effectiveName,
        });
      }

      const pesel = getPesel(policy?.identityNumber);
      const nameKey = getPersonNameKey(effectiveName);
      if (!id || !pesel || !nameKey) continue;
      const groupKey = `${pesel}\u0001${nameKey}`;
      if (!groups.has(groupKey)) groups.set(groupKey, { pesel, records: [] });
      groups.get(groupKey).records.push(policy);
    }

    for (const { pesel, records: group } of groups.values()) {
      if (group.length < 2) continue;

      const variants = new Map();
      for (const policy of group) {
        const clientName = effectiveNames.get(policy) || "";
        const variantKey = clientName;
        if (!clientName) continue;
        if (!variants.has(variantKey)) {
          variants.set(variantKey, {
            clientName,
            count: 0,
            freshness: 0,
          });
        }
        const variant = variants.get(variantKey);
        variant.count += 1;
        const freshness = getRecordFreshness(policy);
        if (freshness >= variant.freshness) {
          variant.clientName = clientName;
          variant.freshness = freshness;
        }
      }
      if (variants.size < 2) continue;

      const canonical = [...variants.values()].sort((first, second) => (
        second.count - first.count
        || second.freshness - first.freshness
        || first.clientName.localeCompare(second.clientName, "pl", { sensitivity: "base" })
      ))[0];

      for (const policy of group) {
        const currentName = effectiveNames.get(policy) || "";
        if (currentName === canonical.clientName) continue;
        const targetId = String(policy.id);
        changesById.set(targetId, {
          targetId,
          pesel,
          nameKey: getPersonNameKey(currentName),
          currentName: cleanPersonName(policy.clientName),
          canonicalName: canonical.clientName,
        });
      }
    }

    return [...changesById.values()].map((change) => Object.freeze(change)).sort((first, second) => (
      first.canonicalName.localeCompare(second.canonicalName, "pl", { sensitivity: "base" })
      || first.targetId.localeCompare(second.targetId, "pl")
    ));
  }

  globalScope.PolicyRecordOrganizer = Object.freeze({
    normalizePersonName,
    collapseRepeatedPersonName,
    getPersonNameKey,
    getPesel,
    isValidPesel,
    isMissingIdentity,
    normalizeVehicleIdentifier,
    normalizeVehicleRegistration,
    normalizeFirstRegistrationDate,
    findMissingIdentityRecords,
    findReviewCandidates,
    findNameUnificationChanges,
    findFirstRegistrationDateChanges,
  });
})(globalThis);
