







(() => {
  const nativeSetTimeout = globalThis.setTimeout.bind(globalThis);
  const nativeClearTimeout = globalThis.clearTimeout.bind(globalThis);
  let backgroundTimerWorker = null;
  
  
  
  
  let backgroundTimerWorkerReady = false;
  const pendingTimeouts = new Map();
  let nextBackgroundTimerId = 1;

  function startBackgroundTimerWorker() {
    if (backgroundTimerWorker || backgroundTimerWorkerReady) return;
    try {
      const source = "postMessage('boot');onmessage=(e)=>{const d=e.data;setTimeout(()=>postMessage(d.id),d.ms)}";
      backgroundTimerWorker = new Worker(URL.createObjectURL(new Blob([source], { type: "text/javascript" })));
      backgroundTimerWorker.onmessage = (event) => {
        if (event.data === "boot") {
          backgroundTimerWorkerReady = true;
          return;
        }
        fireBackgroundTimeout(event.data);
      };
      backgroundTimerWorker.onerror = () => {
        
        backgroundTimerWorker = null;
        backgroundTimerWorkerReady = false;
      };
    } catch {
      backgroundTimerWorker = null;
      backgroundTimerWorkerReady = false;
    }
  }

  
  
  startBackgroundTimerWorker();
  document.addEventListener("visibilitychange", () => {
    if (!document.hidden && !backgroundTimerWorkerReady) {
      if (backgroundTimerWorker) {
        
        try { backgroundTimerWorker.terminate(); } catch {   }
        backgroundTimerWorker = null;
      }
      startBackgroundTimerWorker();
    }
  });

  function fireBackgroundTimeout(timerId) {
    const entry = pendingTimeouts.get(timerId);
    if (!entry) return;
    pendingTimeouts.delete(timerId);
    nativeClearTimeout(entry.backupHandle);
    entry.callback(...entry.args);
  }

  globalThis.setTimeout = (callback, delayMs = 0, ...args) => {
    if (typeof callback !== "function" || !(delayMs >= 250) || !backgroundTimerWorkerReady || !backgroundTimerWorker) {
      return nativeSetTimeout(callback, delayMs, ...args);
    }
    
    
    
    
    const timerId = `bg-t${nextBackgroundTimerId++}`;
    const entry = { callback, args, backupHandle: 0 };
    pendingTimeouts.set(timerId, entry);
    entry.backupHandle = nativeSetTimeout(() => fireBackgroundTimeout(timerId), delayMs);
    try {
      backgroundTimerWorker.postMessage({ id: timerId, ms: delayMs });
    } catch {
      
    }
    return timerId;
  };
  globalThis.clearTimeout = (timerId) => {
    if (typeof timerId === "string") {
      const entry = pendingTimeouts.get(timerId);
      if (entry) {
        pendingTimeouts.delete(timerId);
        nativeClearTimeout(entry.backupHandle);
      }
      return;
    }
    nativeClearTimeout(timerId);
  };
})();

const LEGACY_STORAGE_KEY = "polisy-records-v1";
const THEME_KEY = "polisy-theme-v1";
const UI_SETTINGS_KEY = "polisy-ui-settings-v1";
const BOOT_THEME_KEY = "iseca-boot-theme-v1";
const APPEARANCE_DOCK_COLLAPSED_KEY = "sekagent-appearance-collapsed-v1";
const FILE_SETTINGS_DB = "polisy-file-settings-v1";
const FILE_SETTINGS_STORE = "settings";
const LEGACY_FILE_HANDLE_KEY = "active-data-file";
const LEGACY_DATA_FILE_SNAPSHOT_KEY = "active-data-file-snapshot";
const FILE_HANDLE_KEY = LEGACY_FILE_HANDLE_KEY;
const SETTINGS_FILE_HANDLE_KEY = "active-settings-file";
const ATTACHMENTS_DIRECTORY_HANDLE_KEY = "attachments-base-directory";
const APP_DIRECTORY_HANDLE_KEY = "app-base-directory";
const DATA_FILE_SNAPSHOT_KEY = LEGACY_DATA_FILE_SNAPSHOT_KEY;
const SETTINGS_FILE_SNAPSHOT_KEY = "active-settings-file-snapshot";
const BROWSER_FILE_CONNECTIONS_RESET_QUERY = "wyczysc-pamiec-bazy-polis";

const DATA_FILE_VERSION = 6;
const SETTINGS_FILE_VERSION = 4;
const DEFAULT_SETTINGS_FILE_NAME = "polisy-ustawienia.json";
const MAX_SETTINGS_FILE_SIZE = 5 * 1024 * 1024;
const ATTACHMENTS_DIRECTORY_NAME = "Zalaczniki";
const TRASH_RETENTION_DAYS = 30;
const DAY_IN_MILLISECONDS = 24 * 60 * 60 * 1000;
const RENEWAL_WINDOW_DAYS = 30;
const RENEWAL_PAST_DAYS = 14;
const DEFAULT_DATABASE_NAME = "Iseca";
const MAX_DATABASE_NAME_LENGTH = 40;
const DEFAULT_LOGO_SRC = "pliki/assets/iseca-logo-dark.png";
const DEFAULT_LOGO_LIGHT_SRC = "pliki/assets/iseca-logo-light.png";
const MAX_LOGO_FILE_SIZE = 2 * 1024 * 1024;
const MAX_INSURER_NAME_LENGTH = 60;
const MAX_INSURER_URL_LENGTH = 500;
const MAX_CALCULATOR_USERNAME_LENGTH = 120;
const MAX_CALCULATOR_PASSWORD_LENGTH = 256;
const SAVED_CALCULATOR_PASSWORD_MASK = "************";
const QUOTE_HISTORY_SNAPSHOT_KEY = "quote-history-v1";
const QUOTE_HISTORY_LIMIT = 200;
const QUOTE_HISTORY_RETENTION_DAYS = 30;
const QUOTE_PREMIUM_ENTRY_LIMIT_PER_INSURER = 100;
const QUOTE_PREMIUM_ENTRY_LIMIT = 700;
const QUOTE_OFFER_DISCLAIMER = "Niniejsze zestawienie ma charakter wyłącznie informacyjny i nie stanowi oferty w rozumieniu art. 66 § 1 Kodeksu cywilnego. Przedstawione składki i zakresy ochrony są kalkulacją wstępną i mogą ulec zmianie po weryfikacji danych przez ubezpieczyciela. Wiążące są postanowienia zawartej umowy, polisy, Ogólnych Warunków Ubezpieczenia oraz pozostałych dokumentów ubezpieczyciela.";
const AGENCY_PRINT_DETAILS_LIMITS = Object.freeze({
  name: 120,
  address: 240,
  email: 160,
  phone: 40,
});
const QUOTE_AUTOMATION_INSURER_IDS = new Set(["warta", "generali", "mtu", "trasti", "wiener", "compensa", "allianz"]);
const QUOTE_CANCELABLE_JOB_STATUSES = new Set([
  "queued",
  "running",
  "action_required",
  "input_required",
  "manual_required",
  "manual_ready",
]);



const QUOTE_RUNNING_JOB_STATUSES = new Set(["queued", "running", "action_required", "input_required"]);
const QUOTE_BRIDGE_REQUEST_TIMEOUT_MS = 8_000;
const QUOTE_JOB_REQUEST_TIMEOUT_MS = 10_000;
const QUOTE_START_REQUEST_TIMEOUT_MS = 15_000;
const QUOTE_CANCEL_REQUEST_TIMEOUT_MS = 22_000;
const ALLOWED_LOGO_TYPES = new Set(["image/png", "image/jpeg", "image/webp", "image/svg+xml"]);
const MAX_ATTACHMENT_FILE_SIZE = 25 * 1024 * 1024;
const MAX_POLICY_ATTACHMENTS_SIZE = 75 * 1024 * 1024;
const MAX_ATTACHMENT_RELATIVE_PATH_LENGTH = 180;
const MAX_ATTACHMENT_DIRECTORY_SEGMENT_LENGTH = 60;
const ALLOWED_ATTACHMENT_TYPES = new Set(["application/pdf", "image/jpeg", "image/png", "image/webp"]);



const IMPORTED_POLICY_FILLABLE_FIELDS = Object.freeze([
  "identityNumber",
  "contact",
  "insurer",
  "registration",
  "vehicleMake",
  "vehicleModel",
  "vehicleType",
  "productionYear",
  "fuelType",
  "seats",
  "grossWeight",
  "vin",
  "firstRegistrationDate",
  "engineCapacity",
  "enginePower",
  "mileage",
  "driverLicenseDate",
  "clientAddress",
  "clientPostalCode",
  "issueDate",
  "validFrom",
  "validUntil",
  "premium",
  "riskSummary",
]);
const IMPORTED_POLICY_LEGACY_MANUAL_FLAGS = Object.freeze({
  registration: "registrationManuallyEdited",
  riskSummary: "riskSummaryManuallyEdited",
  premium: "premiumManuallyEdited",
  validFrom: "validFromManuallyEdited",
});



const TERMINATION_PDF_TEMPLATE_URLS = Object.freeze({
  koniec: "pliki/wypowiedzenieocdruk.pdf",
  automat: "pliki/wypowiedzenieautomat.pdf",
  nabywca: "pliki/wypowiedzenienabywcy.pdf",
});
const TERMINATION_PDF_TITLES = Object.freeze({
  koniec: "Wypowiedzenie OC",
  automat: "Wypowiedzenie OC automatycznie wznowionej umowy",
  nabywca: "Wypowiedzenie OC przez nabywcę pojazdu",
});
const TERMINATION_PDF_FIELD_NAMES = Object.freeze({
  dateAndCity: "Data i miejscowosc",
  clientName: "Imie Nazwisko",
  vehicle: "Pojazd",
  insurer: "Towarzystwo Ubezpieczeniowe",
  policyNumber: "Numer polisy",
  insurancePeriod: "Okres Ubezpieczenia",
});

const TERMINATION_CITY_KEY = "iseca-wypowiedzenie-miejscowosc-v1";
const ATTACHMENT_EXTENSION_TYPES = Object.freeze({
  pdf: "application/pdf",
  jpg: "image/jpeg",
  jpeg: "image/jpeg",
  png: "image/png",
  webp: "image/webp",
});



const DEFAULT_ATTACHMENT_CATEGORY = "Skan polisy";

const ATTACHMENT_PHOTOS_CATEGORY = "Zdjęcia pojazdu";
const ATTACHMENT_CATEGORY_PRESETS = Object.freeze([
  DEFAULT_ATTACHMENT_CATEGORY,
  ATTACHMENT_PHOTOS_CATEGORY,
  "Dokument sprzedaży",
  "Wyrejestrowanie pojazdu",
]);
const MAX_ATTACHMENT_CATEGORY_LENGTH = 40;
const RECORDS_PER_PAGE_OPTIONS = new Set([10, 25, 50, 100, 200]);



const DEFAULT_RECORDS_PER_PAGE = 100;
const MAX_CALENDAR_TASK_LENGTH = 300;
const MAX_CALENDAR_TASKS_PER_DAY = 100;


const POLICY_BUYER_TRANSFER_FEATURE_ENABLED = false;


const SHORT_DATE_FORMAT = new Intl.DateTimeFormat("pl-PL", { day: "2-digit", month: "2-digit", year: "numeric" });
const SHORT_DATE_TIME_FORMAT = new Intl.DateTimeFormat("pl-PL", {
  day: "2-digit",
  month: "2-digit",
  year: "numeric",
  hour: "2-digit",
  minute: "2-digit",
});
const WEEKDAY_NAME_FORMAT = new Intl.DateTimeFormat("pl-PL", { weekday: "long" });
const FULL_DATE_FORMAT = new Intl.DateTimeFormat("pl-PL", {
  weekday: "long",
  day: "numeric",
  month: "long",
  year: "numeric",
});
const MONTH_YEAR_FORMAT = new Intl.DateTimeFormat("pl-PL", { month: "long", year: "numeric" });
const USAGE_GUIDE_DURATION_MS = 10000;
const USAGE_GUIDE_FADE_MS = 650;
const USAGE_GUIDE_LABEL_CLEARANCE_PX = 32;
const USAGE_GUIDE_TARGETS = Object.freeze([
  { selector: "#radioPlayer", description: "Radio" },
  { selector: "#appearanceDock", description: "Wygląd" },
  { selector: "#todayDate" },
  { selector: "#quoteCalculatorButton" },
  { selector: "#renewalFilter" },
  { selector: "#settingsGear" },
  { selector: "#screenLockButton" },
  {
    selectors: [".hero", ".policy-grid--labels"],
    description: "Filtry polis",
    highlightClass: "usage-guide-highlight--group",
    highlightPadding: 6,
  },
  { selector: "#printPolicies" },
  { selector: "#importPolicies" },
  { selector: "#addPolicyButton" },
  { selector: '#policyRows button[data-action="open-client-profile"]' },
  { selector: '#policyRows button[data-action="open-vehicle-details"]' },
  { selector: '#policyRows button[data-action="open-premium-details"]' },
]);
const USAGE_GUIDE_ID_DESCRIPTIONS = Object.freeze({
  todayDate: "Kalendarz i zadania",
  quoteCalculatorButton: "Kalkulator składki",
  renewalFilter: "Polisy do odnowienia",
  settingsGear: "Ustawienia aplikacji",
  screenLockButton: "Szybka blokada ekranu",
  resolveDataIntegrity: "Rozwiązanie problemu z zapisem",
  dismissDataIntegrity: "Ukrycie komunikatu",
  dateFilterToggle: "Filtrowanie po dacie początku polisy",
  clearSearchFilters: "Czyszczenie wyszukiwania i filtrów",
  sortByClientName: "Sortowanie klientów",
  sortByInsurer: "Sortowanie towarzystw",
  sortByRegistration: "Sortowanie numerów i rodzajów polis",
  sortByStartDate: "Sortowanie dat rozpoczęcia",
  sortByDate: "Sortowanie dat zakończenia",
  sortByPremium: "Sortowanie składek",
  resetSorting: "Przywrócenie kolejności wpisów",
  printPolicies: "Drukowanie widocznych polis do PDF",
  toggleRenewedPolicies: "Ukrywanie i pokazywanie polis wznowionych",
  toggleInactivePolicies: "Ukrywanie i pokazywanie polis nieaktywnych",
  clearPolicyForm: "Czyszczenie formularza",
  renewalWindow30: "Odnowienia z 30 dni",
  renewalWindow60: "Odnowienia z 60 dni",
  renewalShowExpired: "Pokazywanie polis po terminie",
  importPolicies: "Wczytywanie polis PDF",
  addPolicyButton: "Dodawanie nowego wpisu",
  clearPendingAttachments: "Usuwanie wybranych załączników",
  scrollPageTop: "Przejście na górę strony",
  scrollPageBottom: "Przejście na dół strony",
  openDataFile: "Otwarcie innej bazy",
  backupDataFile: "Tworzenie kopii zapasowej",
  saveDataFile: "Zapis bazy do nowego pliku",
  openSettingsFile: "Otwarcie ustawień z pliku",
  saveSettingsFile: "Zapis ustawień do pliku",
  calendarPreviousMonth: "Poprzedni miesiąc",
  calendarNextMonth: "Następny miesiąc",
  calendarGoToToday: "Powrót do dzisiejszej daty",
  addCalendarTasks: "Dodawanie zadania do dnia",
  closeCalendar: "Zamknięcie kalendarza",
  closeCalendarFooter: "Zamknięcie kalendarza",
  calendarRenewalsHiddenRestore: "Przywrócenie ukrytych polis dnia",
  closeCalendarRenewed: "Zamknięcie okna wznowienia",
  cancelCalendarRenewed: "Zamknięcie okna wznowienia",
  calendarRenewedLater: "Wznowienie bez wskazywania nowej polisy",
});
const USAGE_GUIDE_ACTION_DESCRIPTIONS = Object.freeze({
  "search-related-policy": "Wyszukanie powiązanej polisy",
  "toggle-attachments": "Dodawanie i podgląd załączników",
  "add-attachments": "Dodawanie załączników",
  "download-attachments": "Pobieranie wszystkich załączników",
  "open-attachment": "Podgląd załącznika",
  "remove-attachment": "Usuwanie załącznika",
  "open-contact-details": "Pełny opis i dodatkowe informacje",
  "open-client-profile": "Karta klienta",
  "open-vehicle-details": "Dane pojazdu po nr rejestracyjnym",
  "open-premium-details": "Składka - ryzyka na polisie",
  edit: "Edycja wpisu",
  "cancel-edit": "Anulowanie edycji wpisu",
  delete: "Usuwanie wpisu",
  "open-termination": "Przygotowanie wypowiedzenia OC",
  renewed: "Oznaczenie polisy jako odnowionej",
  "not-renewed": "Oznaczenie polisy jako niewznowionej",
});

const DEFAULT_INSURER_SETTINGS = Object.freeze([
  { id: "hestia", name: "Hestia", url: "http://ihestia.ergohestia.pl/" },
  { id: "pzu", name: "PZU", url: "http://everest.pzu.pl/" },
  { id: "warta", name: "Warta", url: "https://eagent.warta.pl/" },
  { id: "generali", name: "Generali", url: "https://portal.generali.pl/" },
  { id: "allianz", name: "Allianz", url: "http://chuck.allianz.pl/" },
  { id: "tuz", name: "TUZ", url: "" },
  { id: "euroins", name: "Euroins", url: "" },
  { id: "tuw", name: "TUW", url: "" },
  { id: "lloyds", name: "Lloyds", url: "" },
  { id: "mtu", name: "MTU", url: "https://jupiter.ergohestia.pl/" },
  { id: "compensa", name: "Compensa", url: "https://cportal.compensa.pl/Portal" },
  { id: "direct", name: "Direct", url: "" },
  { id: "interrisk", name: "Interrisk", url: "" },
  { id: "link4", name: "Link4", url: "" },
  { id: "uniqa", name: "Uniqa", url: "" },
  { id: "wiener", name: "Wiener", url: "https://wienet.pl/" },
  { id: "trasti", name: "Trasti", url: "https://portal.trasti.pl/" },
]);
const INSURER_ID_ALIASES = Object.freeze({
  "ergo-hestia": "hestia",
  ergohestia: "hestia",
});
const REGISTRATION_SUGGESTIONS = ["Podróż", "Mieszkanie", "Życie", "Firma", "Inne"];
const PRINT_COLUMNS = [
  { key: "clientName", label: "Imię i nazwisko / nazwa", weight: 1.5 },
  { key: "identityNumber", label: "PESEL / NIP / REGON", weight: 1.12 },
  { key: "insurer", label: "Towarzystwo", weight: 1 },
  { key: "policyNumber", label: "Numer Polisy", weight: 1.18 },
  { key: "registration", label: "Nr Rej. / Rodzaj Polisy", weight: 1.16 },
  { key: "validFrom", label: "Od kiedy", weight: 0.84 },
  { key: "validUntil", label: "Do kiedy", weight: 0.84 },
  { key: "premium", label: "Składka", weight: 0.76 },
  { key: "contact", label: "Notatki", weight: 1.5 },
];

const elements = {
  card: document.querySelector(".policies-card"),
  form: document.querySelector("#policyForm"),
  addPolicyButton: document.querySelector("#addPolicyButton"),
  rows: document.querySelector("#policyRows"),
  search: document.querySelector("#policySearch"),
  dateFilterToggle: document.querySelector("#dateFilterToggle"),
  dateRangeFilter: document.querySelector("#dateRangeFilter"),
  dateFilterFrom: document.querySelector("#dateFilterFrom"),
  dateFilterTo: document.querySelector("#dateFilterTo"),
  clearSearchFilters: document.querySelector("#clearSearchFilters"),
  sortButton: document.querySelector("#sortByDate"),
  startDateSortButton: document.querySelector("#sortByStartDate"),
  premiumSortButton: document.querySelector("#sortByPremium"),
  clientNameSortButton: document.querySelector("#sortByClientName"),
  insurerSortButton: document.querySelector("#sortByInsurer"),
  registrationSortButton: document.querySelector("#sortByRegistration"),
  resetSortingButton: document.querySelector("#resetSorting"),
  renewalButton: document.querySelector("#renewalFilter"),
  renewalCount: document.querySelector("#renewalCount"),
  renewalWindow30: document.querySelector("#renewalWindow30"),
  renewalWindow60: document.querySelector("#renewalWindow60"),
  clientNameInput: document.querySelector("#clientName"),
  identityNumberInput: document.querySelector("#identityNumber"),
  insurerInput: document.querySelector("#insurer"),
  policyNumberInput: document.querySelector("#policyNumber"),
  registrationInput: document.querySelector("#registration"),
  validFromInput: document.querySelector("#validFrom"),
  startDateFormField: document.querySelector("#startDateFormField"),
  validUntilInput: document.querySelector("#validUntil"),
  premiumInput: document.querySelector("#premium"),
  contactInput: document.querySelector("#contact"),
  clearPolicyForm: document.querySelector("#clearPolicyForm"),
  importPolicies: document.querySelector("#importPolicies"),
  importPoliciesLabel: document.querySelector("#importPoliciesLabel"),
  policyImportInput: document.querySelector("#policyImportInput"),
  policyAttachmentInput: document.querySelector("#policyAttachmentInput"),
  recordAttachmentInput: document.querySelector("#recordAttachmentInput"),
  pendingAttachments: document.querySelector("#pendingAttachments"),
  pendingAttachmentList: document.querySelector("#pendingAttachmentList"),
  clearPendingAttachments: document.querySelector("#clearPendingAttachments"),
  printPolicies: document.querySelector("#printPolicies"),
  toggleRenewedPolicies: document.querySelector("#toggleRenewedPolicies"),
  toggleRenewedPoliciesLabel: document.querySelector("#toggleRenewedPoliciesLabel"),
  toggleInactivePolicies: document.querySelector("#toggleInactivePolicies"),
  toggleInactivePoliciesLabel: document.querySelector("#toggleInactivePoliciesLabel"),
  printOptionsDialog: document.querySelector("#printOptionsDialog"),
  closePrintOptions: document.querySelector("#closePrintOptions"),
  cancelPrintOptions: document.querySelector("#cancelPrintOptions"),
  confirmPrint: document.querySelector("#confirmPrint"),
  printVisibleCount: document.querySelector("#printVisibleCount"),
  selectAllPrintColumns: document.querySelector("#selectAllPrintColumns"),
  clearAllPrintColumns: document.querySelector("#clearAllPrintColumns"),
  terminationDateDialog: document.querySelector("#terminationDateDialog"),
  terminationDateForm: document.querySelector("#terminationDateForm"),
  terminationPolicyEndDate: document.querySelector("#terminationPolicyEndDate"),
  terminationSignatureDate: document.querySelector("#terminationSignatureDate"),
  terminationCity: document.querySelector("#terminationCity"),
  terminationBuyerField: document.querySelector("#terminationBuyerField"),
  terminationBuyerName: document.querySelector("#terminationBuyerName"),
  closeTerminationDate: document.querySelector("#closeTerminationDate"),
  cancelTerminationDate: document.querySelector("#cancelTerminationDate"),
  attachmentCategoryDialog: document.querySelector("#attachmentCategoryDialog"),
  attachmentCategoryForm: document.querySelector("#attachmentCategoryForm"),
  attachmentCategorySummary: document.querySelector("#attachmentCategorySummary"),
  attachmentCategoryOptions: document.querySelector("#attachmentCategoryOptions"),
  attachmentCategoryCustom: document.querySelector("#attachmentCategoryCustom"),
  closeAttachmentCategory: document.querySelector("#closeAttachmentCategory"),
  cancelAttachmentCategory: document.querySelector("#cancelAttachmentCategory"),
  attachmentTargetDialog: document.querySelector("#attachmentTargetDialog"),
  attachmentTargetForm: document.querySelector("#attachmentTargetForm"),
  attachmentTargetSummary: document.querySelector("#attachmentTargetSummary"),
  attachmentTargetSearch: document.querySelector("#attachmentTargetSearch"),
  attachmentTargetResults: document.querySelector("#attachmentTargetResults"),
  attachmentTargetCategoryOptions: document.querySelector("#attachmentTargetCategoryOptions"),
  attachmentTargetCategoryCustom: document.querySelector("#attachmentTargetCategoryCustom"),
  closeAttachmentTarget: document.querySelector("#closeAttachmentTarget"),
  cancelAttachmentTarget: document.querySelector("#cancelAttachmentTarget"),
  confirmAttachmentTarget: document.querySelector("#confirmAttachmentTarget"),
  contactDetailsDialog: document.querySelector("#contactDetailsDialog"),
  contactDetailsForm: document.querySelector("#contactDetailsForm"),
  contactDetailsClient: document.querySelector("#contactDetailsClient"),
  contactDetailsMeta: document.querySelector("#contactDetailsMeta"),
  contactDetailsText: document.querySelector("#contactDetailsText"),
  closeContactDetails: document.querySelector("#closeContactDetails"),
  cancelContactDetails: document.querySelector("#cancelContactDetails"),
  saveContactDetails: document.querySelector("#saveContactDetails"),
  vehicleDetailsDialog: document.querySelector("#vehicleDetailsDialog"),
  vehicleDetailsForm: document.querySelector("#vehicleDetailsForm"),
  vehicleDetailsEditCancel: document.querySelector("#vehicleDetailsEditCancel"),
  vehicleDetailsClient: document.querySelector("#vehicleDetailsClient"),
  vehicleDetailsMeta: document.querySelector("#vehicleDetailsMeta"),
  vehicleDetailsHistory: document.querySelector("#vehicleDetailsHistory"),
  closeVehicleDetails: document.querySelector("#closeVehicleDetails"),
  cancelVehicleDetails: document.querySelector("#cancelVehicleDetails"),
  saveVehicleDetails: document.querySelector("#saveVehicleDetails"),
  premiumDetailsDialog: document.querySelector("#premiumDetailsDialog"),
  premiumDetailsPremium: document.querySelector("#premiumDetailsPremium"),
  premiumDetailsClient: document.querySelector("#premiumDetailsClient"),
  premiumDetailsMeta: document.querySelector("#premiumDetailsMeta"),
  premiumDetailsRisks: document.querySelector("#premiumDetailsRisks"),
  closePremiumDetails: document.querySelector("#closePremiumDetails"),
  clientProfileDialog: document.querySelector("#clientProfileDialog"),
  clientProfileTitle: document.querySelector("#clientProfileTitle"),
  clientProfileSubtitle: document.querySelector("#clientProfileSubtitle"),
  clientProfileContent: document.querySelector("#clientProfileContent"),
  clientProfileSearchForm: document.querySelector("#clientProfileSearchForm"),
  clientProfileSearch: document.querySelector("#clientProfileSearch"),
  clientProfileOptions: document.querySelector("#clientProfileOptions"),
  closeClientProfile: document.querySelector("#closeClientProfile"),
  clientOptions: document.querySelector("#clientOptions"),
  brand: document.querySelector(".brand"),
  brandLogo: document.querySelector("#brandLogo"),
  brandName: document.querySelector("#brandName"),
  quoteCalculatorButton: document.querySelector("#quoteCalculatorButton"),
  quoteCalculatorDialog: document.querySelector("#quoteCalculatorDialog"),
  quoteCalculatorEyebrow: document.querySelector("#quoteCalculatorEyebrow"),
  quoteCalculatorTitle: document.querySelector("#quoteCalculatorTitle"),
  quoteCalculatorForm: document.querySelector("#quoteCalculatorForm"),
  closeQuoteCalculator: document.querySelector("#closeQuoteCalculator"),
  cancelQuoteCalculator: document.querySelector("#cancelQuoteCalculator"),
  stopQuoteCalculation: document.querySelector("#stopQuoteCalculation"),
  startManualQuoteCalculation: document.querySelector("#startManualQuoteCalculation"),
  startQuoteCalculation: document.querySelector("#startQuoteCalculation"),
  quoteRegistration: document.querySelector("#quoteRegistration"),
  quotePesel: document.querySelector("#quotePesel"),
  quoteCalculatorContent: document.querySelector("#quoteCalculatorContent"),
  quoteClientInfoPanel: document.querySelector("#quoteClientInfoPanel"),
  quoteClientInfoTitle: document.querySelector("#quoteClientInfoTitle"),
  quoteClientInfoSource: document.querySelector("#quoteClientInfoSource"),
  quoteClientInfoList: document.querySelector("#quoteClientInfoList"),
  quoteClientInfoNote: document.querySelector("#quoteClientInfoNote"),
  quoteClientInfoHint: document.querySelector("#quoteClientInfoHint"),
  quoteClientInfoActions: document.querySelector("#quoteClientInfoActions"),
  quoteClientInfoHistory: document.querySelector("#quoteClientInfoHistory"),
  quoteClientInfoEdit: document.querySelector("#quoteClientInfoEdit"),
  quoteClientCardOffer: document.querySelector("#quoteClientCardOffer"),
  quoteClientCardOfferSummary: document.querySelector("#quoteClientCardOfferSummary"),
  quoteClientCardName: document.querySelector("#quoteClientCardName"),
  quoteClientCardAdd: document.querySelector("#quoteClientCardAdd"),
  quoteCalculatorError: document.querySelector("#quoteCalculatorError"),
  quoteInsurerWarta: document.querySelector("#quoteInsurerWarta"),
  quoteInsurerMtu: document.querySelector("#quoteInsurerMtu"),
  quoteInsurerGenerali: document.querySelector("#quoteInsurerGenerali"),
  quoteInsurerTrasti: document.querySelector("#quoteInsurerTrasti"),
  quoteInsurerWiener: document.querySelector("#quoteInsurerWiener"),
  quoteInsurerCompensa: document.querySelector("#quoteInsurerCompensa"),
  quoteInsurerAllianz: document.querySelector("#quoteInsurerAllianz"),
  quoteBridgeBadge: document.querySelector("#quoteBridgeBadge"),
  quoteWartaCard: document.querySelector("#quoteWartaCard"),
  quoteWartaStatus: document.querySelector("#quoteWartaStatus"),
  quoteWartaDetail: document.querySelector("#quoteWartaDetail"),
  quoteWartaManualRepair: document.querySelector("#quoteWartaManualRepair"),
  quoteMtuCard: document.querySelector("#quoteMtuCard"),
  quoteMtuStatus: document.querySelector("#quoteMtuStatus"),
  quoteMtuDetail: document.querySelector("#quoteMtuDetail"),
  quoteMtuManualRepair: document.querySelector("#quoteMtuManualRepair"),
  quoteGeneraliCard: document.querySelector("#quoteGeneraliCard"),
  quoteGeneraliStatus: document.querySelector("#quoteGeneraliStatus"),
  quoteGeneraliDetail: document.querySelector("#quoteGeneraliDetail"),
  quoteGeneraliManualRepair: document.querySelector("#quoteGeneraliManualRepair"),
  quoteTrastiCard: document.querySelector("#quoteTrastiCard"),
  quoteTrastiStatus: document.querySelector("#quoteTrastiStatus"),
  quoteTrastiDetail: document.querySelector("#quoteTrastiDetail"),
  quoteTrastiManualRepair: document.querySelector("#quoteTrastiManualRepair"),
  quoteWienerCard: document.querySelector("#quoteWienerCard"),
  quoteWienerStatus: document.querySelector("#quoteWienerStatus"),
  quoteWienerDetail: document.querySelector("#quoteWienerDetail"),
  quoteWienerManualRepair: document.querySelector("#quoteWienerManualRepair"),
  quoteCompensaCard: document.querySelector("#quoteCompensaCard"),
  quoteCompensaStatus: document.querySelector("#quoteCompensaStatus"),
  quoteCompensaDetail: document.querySelector("#quoteCompensaDetail"),
  quoteCompensaManualRepair: document.querySelector("#quoteCompensaManualRepair"),
  quoteAllianzCard: document.querySelector("#quoteAllianzCard"),
  quoteAllianzStatus: document.querySelector("#quoteAllianzStatus"),
  quoteAllianzDetail: document.querySelector("#quoteAllianzDetail"),
  quoteAllianzManualRepair: document.querySelector("#quoteAllianzManualRepair"),
  quoteInsurersEmpty: document.querySelector("#quoteInsurersEmpty"),
  quoteProgress: document.querySelector("#quoteProgress"),
  quoteProgressTitle: document.querySelector("#quoteProgressTitle"),
  quoteProgressDetail: document.querySelector("#quoteProgressDetail"),
  quoteResults: document.querySelector("#quoteResults"),
  quoteResultsSummary: document.querySelector("#quoteResultsSummary"),
  quoteResultsList: document.querySelector("#quoteResultsList"),
  quotePrintOffer: document.querySelector("#quotePrintOffer"),
  quotePrintDialog: document.querySelector("#quotePrintDialog"),
  closeQuotePrint: document.querySelector("#closeQuotePrint"),
  cancelQuotePrint: document.querySelector("#cancelQuotePrint"),
  confirmQuotePrint: document.querySelector("#confirmQuotePrint"),
  quotePrintAgencyWarning: document.querySelector("#quotePrintAgencyWarning"),
  quotePrintAgencyEdit: document.querySelector("#quotePrintAgencyEdit"),
  quotePrintSelectionSummary: document.querySelector("#quotePrintSelectionSummary"),
  quotePrintSelectAll: document.querySelector("#quotePrintSelectAll"),
  quotePrintClearAll: document.querySelector("#quotePrintClearAll"),
  quotePrintOptionsList: document.querySelector("#quotePrintOptionsList"),
  quoteArchive: document.querySelector("#quoteArchive"),
  quoteArchiveList: document.querySelector("#quoteArchiveList"),
  settingsGear: document.querySelector("#settingsGear"),
  screenLockButton: document.querySelector("#screenLockButton"),
  settingsDialog: document.querySelector("#settingsDialog"),
  closeSettings: document.querySelector("#closeSettings"),
  cancelSettings: document.querySelector("#cancelSettings"),
  saveSettings: document.querySelector("#saveSettings"),
  settingsContent: document.querySelector(".settings-content"),
  settingsApplicationTab: document.querySelector("#settingsApplicationTab"),
  settingsUserTab: document.querySelector("#settingsUserTab"),
  settingsInterfaceTab: document.querySelector("#settingsInterfaceTab"),
  settingsPrintDetailsTab: document.querySelector("#settingsPrintDetailsTab"),
  settingsPrintDetailsPanel: document.querySelector("#settingsPrintDetailsPanel"),
  settingsAgencyTab: document.querySelector("#settingsAgencyTab"),
  settingsAgencyPanel: document.querySelector("#settingsAgencyPanel"),
  agencyPrintName: document.querySelector("#agencyPrintName"),
  agencyPrintAddress: document.querySelector("#agencyPrintAddress"),
  agencyPrintEmail: document.querySelector("#agencyPrintEmail"),
  agencyPrintPhone: document.querySelector("#agencyPrintPhone"),
  agencyAccountName: document.querySelector("#agencyAccountName"),
  agencyAccountNameSave: document.querySelector("#agencyAccountNameSave"),
  agencyAccountId: document.querySelector("#agencyAccountId"),
  agencyAccountStatus: document.querySelector("#agencyAccountStatus"),
  agencyPinCurrent: document.querySelector("#agencyPinCurrent"),
  agencyPinNew: document.querySelector("#agencyPinNew"),
  agencyPinRepeat: document.querySelector("#agencyPinRepeat"),
  agencyPinChange: document.querySelector("#agencyPinChange"),
  agencyPinStatus: document.querySelector("#agencyPinStatus"),
  agencyInsurersList: document.querySelector("#agencyInsurersList"),
  agencyInsurersSave: document.querySelector("#agencyInsurersSave"),
  agencyInsurersHint: document.querySelector("#agencyInsurersHint"),
  agencyInsurersStatus: document.querySelector("#agencyInsurersStatus"),
  agencyMembersSection: document.querySelector("#agencyMembersSection"),
  agencyAddMemberForm: document.querySelector("#agencyAddMemberForm"),
  agencyNewMemberId: document.querySelector("#agencyNewMemberId"),
  agencyNewMemberLabel: document.querySelector("#agencyNewMemberLabel"),
  agencyMembersError: document.querySelector("#agencyMembersError"),
  agencyMembersList: document.querySelector("#agencyMembersList"),
  agencyMembersEmpty: document.querySelector("#agencyMembersEmpty"),
  agencyAssignmentPanel: document.querySelector("#agencyAssignmentPanel"),
  agencyAssignmentTitle: document.querySelector("#agencyAssignmentTitle"),
  agencyAssignmentTarget: document.querySelector("#agencyAssignmentTarget"),
  agencyAssignmentClose: document.querySelector("#agencyAssignmentClose"),
  agencyAssignmentSummary: document.querySelector("#agencyAssignmentSummary"),
  agencyAssignmentChoose: document.querySelector("#agencyAssignmentChoose"),
  agencyAssignmentDownload: document.querySelector("#agencyAssignmentDownload"),
  agencyAssignmentStatus: document.querySelector("#agencyAssignmentStatus"),
  agencyAssignmentImportSection: document.querySelector("#agencyAssignmentImportSection"),
  agencyAssignmentImportControls: document.querySelector("#agencyAssignmentImportControls"),
  agencyAssignmentImportButton: document.querySelector("#agencyAssignmentImportButton"),
  agencyAssignmentImportFile: document.querySelector("#agencyAssignmentImportFile"),
  agencyAssignmentImportStatus: document.querySelector("#agencyAssignmentImportStatus"),
  agencyPairingPanel: document.querySelector("#agencyPairingPanel"),
  agencyPairingCode: document.querySelector("#agencyPairingCode"),
  agencyPairingSubmit: document.querySelector("#agencyPairingSubmit"),
  agencyPairingCodeDialog: document.querySelector("#agencyPairingCodeDialog"),
  agencyPairingCodeOutput: document.querySelector("#agencyPairingCodeOutput"),
  agencyPairingCodeCopy: document.querySelector("#agencyPairingCodeCopy"),
  agencyPairingCodeClose: document.querySelector("#agencyPairingCodeClose"),
  agencyGeneratorSection: document.querySelector("#agencyGeneratorSection"),
  agencyGenerateName: document.querySelector("#agencyGenerateName"),
  agencyGenerateButton: document.querySelector("#agencyGenerateButton"),
  agencyGenerateSeedEmpty: document.querySelector("#agencyGenerateSeedEmpty"),
  agencyGenerateSeedSelected: document.querySelector("#agencyGenerateSeedSelected"),
  agencyGenerateSeedPicker: document.querySelector("#agencyGenerateSeedPicker"),
  agencyGenerateSeedSummary: document.querySelector("#agencyGenerateSeedSummary"),
  agencyGenerateSeedChoose: document.querySelector("#agencyGenerateSeedChoose"),
  agencyGenerateAllowImports: document.querySelector("#agencyGenerateAllowImports"),
  agencyGenerateStatus: document.querySelector("#agencyGenerateStatus"),
  agencyPolicyPickerDialog: document.querySelector("#agencyPolicyPickerDialog"),
  agencyPolicyPickerContext: document.querySelector("#agencyPolicyPickerContext"),
  agencyPolicyPickerClose: document.querySelector("#agencyPolicyPickerClose"),
  agencyPolicyPickerSearch: document.querySelector("#agencyPolicyPickerSearch"),
  agencyPolicyPickerPeriod: document.querySelector("#agencyPolicyPickerPeriod"),
  agencyPolicyPickerFromField: document.querySelector("#agencyPolicyPickerFromField"),
  agencyPolicyPickerToField: document.querySelector("#agencyPolicyPickerToField"),
  agencyPolicyPickerFrom: document.querySelector("#agencyPolicyPickerFrom"),
  agencyPolicyPickerTo: document.querySelector("#agencyPolicyPickerTo"),
  agencyPolicyPickerSelectVisible: document.querySelector("#agencyPolicyPickerSelectVisible"),
  agencyPolicyPickerUnselectVisible: document.querySelector("#agencyPolicyPickerUnselectVisible"),
  agencyPolicyPickerClearAll: document.querySelector("#agencyPolicyPickerClearAll"),
  agencyPolicyPickerGroups: document.querySelector("#agencyPolicyPickerGroups"),
  agencyPolicyPickerEmpty: document.querySelector("#agencyPolicyPickerEmpty"),
  agencyPolicyPickerSummary: document.querySelector("#agencyPolicyPickerSummary"),
  agencyPolicyPickerCancel: document.querySelector("#agencyPolicyPickerCancel"),
  agencyPolicyPickerConfirm: document.querySelector("#agencyPolicyPickerConfirm"),
  agencyExportSection: document.querySelector("#agencyExportSection"),
  agencyExportButton: document.querySelector("#agencyExportButton"),
  agencyExportStatus: document.querySelector("#agencyExportStatus"),
  agencyExportInsurer: document.querySelector("#agencyExportInsurer"),
  agencyExportPeriod: document.querySelector("#agencyExportPeriod"),
  agencyExportFromField: document.querySelector("#agencyExportFromField"),
  agencyExportToField: document.querySelector("#agencyExportToField"),
  agencyExportFrom: document.querySelector("#agencyExportFrom"),
  agencyExportTo: document.querySelector("#agencyExportTo"),
  agencyExportClient: document.querySelector("#agencyExportClient"),
  agencyExportSummary: document.querySelector("#agencyExportSummary"),
  agencyExportReset: document.querySelector("#agencyExportReset"),
  agencyExportLastInfo: document.querySelector("#agencyExportLastInfo"),
  settingsApplicationPanel: document.querySelector("#settingsApplicationPanel"),
  settingsUserPanel: document.querySelector("#settingsUserPanel"),
  settingsInterfacePanel: document.querySelector("#settingsInterfacePanel"),
  addInsurerForm: document.querySelector("#addInsurerForm"),
  newInsurerName: document.querySelector("#newInsurerName"),
  newInsurerUrl: document.querySelector("#newInsurerUrl"),
  insurerSettingsError: document.querySelector("#insurerSettingsError"),
  insurerSettingsList: document.querySelector("#insurerSettingsList"),
  insurerSettingsEmpty: document.querySelector("#insurerSettingsEmpty"),
  insurerSettingsPopup: document.querySelector("#insurerSettingsPopup"),
  insurerSettingsPopupText: document.querySelector("#insurerSettingsPopupText"),
  entryOrganizerSummary: document.querySelector("#entryOrganizerSummary"),
  startEntryOrganizer: document.querySelector("#startEntryOrganizer"),
  deletedRecordsSummary: document.querySelector("#deletedRecordsSummary"),
  openDeletedRecords: document.querySelector("#openDeletedRecords"),
  deletedRecordsDialog: document.querySelector("#deletedRecordsDialog"),
  closeDeletedRecords: document.querySelector("#closeDeletedRecords"),
  closeDeletedRecordsFooter: document.querySelector("#closeDeletedRecordsFooter"),
  deletedRecordsCount: document.querySelector("#deletedRecordsCount"),
  deletedRecordsList: document.querySelector("#deletedRecordsList"),
  deletedRecordsEmpty: document.querySelector("#deletedRecordsEmpty"),
  deleteAllDeletedRecords: document.querySelector("#deleteAllDeletedRecords"),
  entryOrganizerWarningDialog: document.querySelector("#entryOrganizerWarningDialog"),
  entryOrganizerWarningConfirm: document.querySelector("#entryOrganizerWarningConfirm"),
  entryOrganizerWarningCancel: document.querySelector("#entryOrganizerWarningCancel"),
  entryOrganizerGroupList: document.querySelector("#entryOrganizerGroupList"),
  clientProfileMergePrimaryDialog: document.querySelector("#clientProfileMergePrimaryDialog"),
  clientProfileMergePrimaryCopy: document.querySelector("#clientProfileMergePrimaryCopy"),
  clientProfileMergePrimaryOptions: document.querySelector("#clientProfileMergePrimaryOptions"),
  clientProfileMergePrimaryCancel: document.querySelector("#clientProfileMergePrimaryCancel"),
  entryOrganizerDialog: document.querySelector("#entryOrganizerDialog"),
  entryOrganizerProgress: document.querySelector("#entryOrganizerProgress"),
  entryOrganizerTitle: document.querySelector("#entryOrganizerTitle"),
  entryOrganizerCopy: document.querySelector("#entryOrganizerCopy"),
  entryOrganizerTargetName: document.querySelector("#entryOrganizerTargetName"),
  entryOrganizerTargetLabel: document.querySelector("#entryOrganizerTargetLabel"),
  entryOrganizerTargetDetails: document.querySelector("#entryOrganizerTargetDetails"),
  entryOrganizerSourceLabel: document.querySelector("#entryOrganizerSourceLabel"),
  entryOrganizerMatchSource: document.querySelector("#entryOrganizerMatchSource"),
  entryOrganizerCandidatePesel: document.querySelector("#entryOrganizerCandidatePesel"),
  entryOrganizerCandidatePeselLabel: document.querySelector("#entryOrganizerCandidatePeselLabel"),
  entryOrganizerSourceRecords: document.querySelector("#entryOrganizerSourceRecords"),
  entryOrganizerManualSource: document.querySelector("#entryOrganizerManualSource"),
  entryOrganizerManualPesel: document.querySelector("#entryOrganizerManualPesel"),
  entryOrganizerManualError: document.querySelector("#entryOrganizerManualError"),
  closeEntryOrganizer: document.querySelector("#closeEntryOrganizer"),
  skipEntryOrganizerManualStage: document.querySelector("#skipEntryOrganizerManualStage"),
  rejectEntryOrganizerMatch: document.querySelector("#rejectEntryOrganizerMatch"),
  confirmEntryOrganizerMatch: document.querySelector("#confirmEntryOrganizerMatch"),
  lightThemeChoice: document.querySelector("#lightThemeChoice"),
  darkThemeChoice: document.querySelector("#darkThemeChoice"),
  standardFontSizeChoice: document.querySelector("#standardFontSizeChoice"),
  mediumFontSizeChoice: document.querySelector("#mediumFontSizeChoice"),
  largeFontSizeChoice: document.querySelector("#largeFontSizeChoice"),
  appearanceDock: document.querySelector("#appearanceDock"),
  collapseAppearanceDock: document.querySelector("#collapseAppearanceDock"),
  expandAppearanceDock: document.querySelector("#expandAppearanceDock"),
  closeAppearanceDock: document.querySelector("#closeAppearanceDock"),
  appearanceThemeToggle: document.querySelector("#appearanceThemeToggle"),
  appearanceFontSizeChoices: [...document.querySelectorAll("[data-appearance-font-size]")],
  showAppearanceDockSetting: document.querySelector("#showAppearanceDockSetting"),
  showStartDateInputSetting: document.querySelector("#showStartDateInputSetting"),
  showUsageGuideSetting: document.querySelector("#showUsageGuideSetting"),
  wartaUsernameSetting: document.querySelector("#wartaUsernameSetting"),
  wartaPasswordSetting: document.querySelector("#wartaPasswordSetting"),
  toggleWartaPassword: document.querySelector("#toggleWartaPassword"),
  clearWartaCredentials: document.querySelector("#clearWartaCredentials"),
  clearWartaNavigationPath: document.querySelector("#clearWartaNavigationPath"),
  downloadWartaNavigationPath: document.querySelector("#downloadWartaNavigationPath"),
  restoreWartaNavigationPath: document.querySelector("#restoreWartaNavigationPath"),
  importWartaNavigationPath: document.querySelector("#importWartaNavigationPath"),
  wartaNavigationPathInput: document.querySelector("#wartaNavigationPathInput"),
  wartaCredentialHint: document.querySelector("#wartaCredentialHint"),
  wartaNavigationHint: document.querySelector("#wartaNavigationHint"),
  wartaAutomationStatus: document.querySelector("#wartaAutomationStatus"),
  
  
  wartaPortfolioRecordsButton: document.querySelector("#wartaPortfolioRecordsButton"),
  wartaPortfolioRecordField: document.querySelector(".warta-portfolio-record-field"),
  wartaPortfolioRecordSelect: document.querySelector("#wartaPortfolioRecordSelect"),
  wartaPortfolioImportButton: document.querySelector("#wartaPortfolioImportButton"),
  wartaPortfolioImportStatus: document.querySelector("#wartaPortfolioImportStatus"),
  wartaPortfolioPdfOptions: document.querySelector("#wartaPortfolioPdfOptions"),
  wartaPortfolioDownloadPdfs: document.querySelector("#wartaPortfolioDownloadPdfs"),
  pzuPortfolioOpenButton: document.querySelector("#pzuPortfolioOpenButton"),
  pzuPortfolioImportButton: document.querySelector("#pzuPortfolioImportButton"),
  pzuPortfolioImportStatus: document.querySelector("#pzuPortfolioImportStatus"),
  pzuPortfolioPdfOptions: document.querySelector("#pzuPortfolioPdfOptions"),
  pzuPortfolioDownloadPdfs: document.querySelector("#pzuPortfolioDownloadPdfs"),
  pzuUsernameSetting: document.querySelector("#pzuUsernameSetting"),
  pzuPasswordSetting: document.querySelector("#pzuPasswordSetting"),
  togglePzuPassword: document.querySelector("#togglePzuPassword"),
  clearPzuCredentials: document.querySelector("#clearPzuCredentials"),
  pzuCredentialHint: document.querySelector("#pzuCredentialHint"),
  inslyUsernameSetting: document.querySelector("#inslyUsernameSetting"),
  inslyPasswordSetting: document.querySelector("#inslyPasswordSetting"),
  toggleInslyPassword: document.querySelector("#toggleInslyPassword"),
  clearInslyCredentials: document.querySelector("#clearInslyCredentials"),
  inslyCredentialHint: document.querySelector("#inslyCredentialHint"),
  inslyPortfolioOpenButton: document.querySelector("#inslyPortfolioOpenButton"),
  inslyPortfolioImportButton: document.querySelector("#inslyPortfolioImportButton"),
  inslyPortfolioImportStatus: document.querySelector("#inslyPortfolioImportStatus"),
  inslyPortfolioCard: document.querySelector("#inslyPortfolioCard"),
  inslyPortfolioPdfOptions: document.querySelector("#inslyPortfolioPdfOptions"),
  inslyPortfolioDownloadPdfs: document.querySelector("#inslyPortfolioDownloadPdfs"),
  generaliUsernameSetting: document.querySelector("#generaliUsernameSetting"),
  generaliPasswordSetting: document.querySelector("#generaliPasswordSetting"),
  toggleGeneraliPassword: document.querySelector("#toggleGeneraliPassword"),
  clearGeneraliCredentials: document.querySelector("#clearGeneraliCredentials"),
  clearGeneraliNavigationPath: document.querySelector("#clearGeneraliNavigationPath"),
  downloadGeneraliNavigationPath: document.querySelector("#downloadGeneraliNavigationPath"),
  restoreGeneraliNavigationPath: document.querySelector("#restoreGeneraliNavigationPath"),
  importGeneraliNavigationPath: document.querySelector("#importGeneraliNavigationPath"),
  generaliNavigationPathInput: document.querySelector("#generaliNavigationPathInput"),
  generaliCredentialHint: document.querySelector("#generaliCredentialHint"),
  generaliNavigationHint: document.querySelector("#generaliNavigationHint"),
  generaliAutomationStatus: document.querySelector("#generaliAutomationStatus"),
  mtuUsernameSetting: document.querySelector("#mtuUsernameSetting"),
  mtuPasswordSetting: document.querySelector("#mtuPasswordSetting"),
  toggleMtuPassword: document.querySelector("#toggleMtuPassword"),
  clearMtuCredentials: document.querySelector("#clearMtuCredentials"),
  clearMtuNavigationPath: document.querySelector("#clearMtuNavigationPath"),
  downloadMtuNavigationPath: document.querySelector("#downloadMtuNavigationPath"),
  restoreMtuNavigationPath: document.querySelector("#restoreMtuNavigationPath"),
  importMtuNavigationPath: document.querySelector("#importMtuNavigationPath"),
  mtuNavigationPathInput: document.querySelector("#mtuNavigationPathInput"),
  mtuCredentialHint: document.querySelector("#mtuCredentialHint"),
  mtuNavigationHint: document.querySelector("#mtuNavigationHint"),
  mtuAutomationStatus: document.querySelector("#mtuAutomationStatus"),
  mtuPortfolioImportButton: document.querySelector("#mtuPortfolioImportButton"),
  mtuPortfolioManualRepair: document.querySelector("#mtuPortfolioManualRepair"),
  mtuPortfolioImportStatus: document.querySelector("#mtuPortfolioImportStatus"),
  mtuPortfolioDownloadPdfs: document.querySelector("#mtuPortfolioDownloadPdfs"),
  mtuPortfolioPdfOptions: document.querySelector(".mtu-portfolio-pdf-options"),
  mtuPortfolioReportDialog: document.querySelector("#mtuPortfolioReportDialog"),
  closeMtuPortfolioReport: document.querySelector("#closeMtuPortfolioReport"),
  confirmMtuPortfolioReport: document.querySelector("#confirmMtuPortfolioReport"),
  mtuPortfolioReportAdded: document.querySelector("#mtuPortfolioReportAdded"),
  mtuPortfolioReportEnriched: document.querySelector("#mtuPortfolioReportEnriched"),
  mtuPortfolioReportWarning: document.querySelector("#mtuPortfolioReportWarning"),
  mtuPortfolioReportPdfs: document.querySelector("#mtuPortfolioReportPdfs"),
  mtuPortfolioReportPdfInfo: document.querySelector("#mtuPortfolioReportPdfInfo"),
  hestiaAutomationStatus: document.querySelector("#hestiaAutomationStatus"),
  hestiaUsernameSetting: document.querySelector("#hestiaUsernameSetting"),
  hestiaPasswordSetting: document.querySelector("#hestiaPasswordSetting"),
  toggleHestiaPassword: document.querySelector("#toggleHestiaPassword"),
  clearHestiaCredentials: document.querySelector("#clearHestiaCredentials"),
  hestiaCredentialHint: document.querySelector("#hestiaCredentialHint"),
  hestiaPortfolioImportButton: document.querySelector("#hestiaPortfolioImportButton"),
  hestiaPortfolioManualRepair: document.querySelector("#hestiaPortfolioManualRepair"),
  hestiaPortfolioImportStatus: document.querySelector("#hestiaPortfolioImportStatus"),
  hestiaPortfolioDownloadPdfs: document.querySelector("#hestiaPortfolioDownloadPdfs"),
  hestiaPortfolioPdfOptions: document.querySelector("#hestiaPortfolioPdfOptions"),
  hestiaPortfolioReportDialog: document.querySelector("#hestiaPortfolioReportDialog"),
  closeHestiaPortfolioReport: document.querySelector("#closeHestiaPortfolioReport"),
  confirmHestiaPortfolioReport: document.querySelector("#confirmHestiaPortfolioReport"),
  hestiaPortfolioReportAdded: document.querySelector("#hestiaPortfolioReportAdded"),
  hestiaPortfolioReportEnriched: document.querySelector("#hestiaPortfolioReportEnriched"),
  hestiaPortfolioReportWarning: document.querySelector("#hestiaPortfolioReportWarning"),
  hestiaPortfolioReportPdfs: document.querySelector("#hestiaPortfolioReportPdfs"),
  hestiaPortfolioReportPdfInfo: document.querySelector("#hestiaPortfolioReportPdfInfo"),
  wienerPortfolioImportButton: document.querySelector("#wienerPortfolioImportButton"),
  wienerPortfolioManualRepair: document.querySelector("#wienerPortfolioManualRepair"),
  wienerPortfolioImportStatus: document.querySelector("#wienerPortfolioImportStatus"),
  wienerPortfolioDownloadPdfs: document.querySelector("#wienerPortfolioDownloadPdfs"),
  wienerPortfolioPdfOptions: document.querySelector("#wienerPortfolioPdfOptions"),
  wienerPortfolioReportDialog: document.querySelector("#wienerPortfolioReportDialog"),
  closeWienerPortfolioReport: document.querySelector("#closeWienerPortfolioReport"),
  confirmWienerPortfolioReport: document.querySelector("#confirmWienerPortfolioReport"),
  wienerPortfolioReportAdded: document.querySelector("#wienerPortfolioReportAdded"),
  wienerPortfolioReportEnriched: document.querySelector("#wienerPortfolioReportEnriched"),
  wienerPortfolioReportWarning: document.querySelector("#wienerPortfolioReportWarning"),
  wienerPortfolioReportPdfs: document.querySelector("#wienerPortfolioReportPdfs"),
  wienerPortfolioReportPdfInfo: document.querySelector("#wienerPortfolioReportPdfInfo"),
  generaliPortfolioImportButton: document.querySelector("#generaliPortfolioImportButton"),
  generaliPortfolioManualRepair: document.querySelector("#generaliPortfolioManualRepair"),
  generaliPortfolioImportStatus: document.querySelector("#generaliPortfolioImportStatus"),
  generaliPortfolioDownloadPdfs: document.querySelector("#generaliPortfolioDownloadPdfs"),
  generaliPortfolioPdfOptions: document.querySelector("#generaliPortfolioPdfOptions"),
  generaliPortfolioReportDialog: document.querySelector("#generaliPortfolioReportDialog"),
  closeGeneraliPortfolioReport: document.querySelector("#closeGeneraliPortfolioReport"),
  confirmGeneraliPortfolioReport: document.querySelector("#confirmGeneraliPortfolioReport"),
  generaliPortfolioReportAdded: document.querySelector("#generaliPortfolioReportAdded"),
  generaliPortfolioReportEnriched: document.querySelector("#generaliPortfolioReportEnriched"),
  generaliPortfolioReportWarning: document.querySelector("#generaliPortfolioReportWarning"),
  generaliPortfolioReportPdfs: document.querySelector("#generaliPortfolioReportPdfs"),
  generaliPortfolioReportPdfInfo: document.querySelector("#generaliPortfolioReportPdfInfo"),
  trastiUsernameSetting: document.querySelector("#trastiUsernameSetting"),
  trastiPortfolioImportButton: document.querySelector("#trastiPortfolioImportButton"),
  trastiPortfolioManualRepair: document.querySelector("#trastiPortfolioManualRepair"),
  trastiPortfolioImportStatus: document.querySelector("#trastiPortfolioImportStatus"),
  trastiPortfolioDownloadPdfs: document.querySelector("#trastiPortfolioDownloadPdfs"),
  trastiPortfolioPdfOptions: document.querySelector("#trastiPortfolioPdfOptions"),
  trastiPortfolioReportDialog: document.querySelector("#trastiPortfolioReportDialog"),
  closeTrastiPortfolioReport: document.querySelector("#closeTrastiPortfolioReport"),
  confirmTrastiPortfolioReport: document.querySelector("#confirmTrastiPortfolioReport"),
  trastiPortfolioReportAdded: document.querySelector("#trastiPortfolioReportAdded"),
  trastiPortfolioReportEnriched: document.querySelector("#trastiPortfolioReportEnriched"),
  trastiPortfolioReportWarning: document.querySelector("#trastiPortfolioReportWarning"),
  trastiPortfolioReportPdfs: document.querySelector("#trastiPortfolioReportPdfs"),
  trastiPortfolioReportPdfInfo: document.querySelector("#trastiPortfolioReportPdfInfo"),
  trastiPasswordSetting: document.querySelector("#trastiPasswordSetting"),
  toggleTrastiPassword: document.querySelector("#toggleTrastiPassword"),
  clearTrastiCredentials: document.querySelector("#clearTrastiCredentials"),
  clearTrastiNavigationPath: document.querySelector("#clearTrastiNavigationPath"),
  downloadTrastiNavigationPath: document.querySelector("#downloadTrastiNavigationPath"),
  restoreTrastiNavigationPath: document.querySelector("#restoreTrastiNavigationPath"),
  importTrastiNavigationPath: document.querySelector("#importTrastiNavigationPath"),
  trastiNavigationPathInput: document.querySelector("#trastiNavigationPathInput"),
  trastiCredentialHint: document.querySelector("#trastiCredentialHint"),
  trastiNavigationHint: document.querySelector("#trastiNavigationHint"),
  trastiAutomationStatus: document.querySelector("#trastiAutomationStatus"),
  wienerUsernameSetting: document.querySelector("#wienerUsernameSetting"),
  wienerPasswordSetting: document.querySelector("#wienerPasswordSetting"),
  toggleWienerPassword: document.querySelector("#toggleWienerPassword"),
  clearWienerCredentials: document.querySelector("#clearWienerCredentials"),
  clearWienerNavigationPath: document.querySelector("#clearWienerNavigationPath"),
  downloadWienerNavigationPath: document.querySelector("#downloadWienerNavigationPath"),
  restoreWienerNavigationPath: document.querySelector("#restoreWienerNavigationPath"),
  importWienerNavigationPath: document.querySelector("#importWienerNavigationPath"),
  wienerNavigationPathInput: document.querySelector("#wienerNavigationPathInput"),
  wienerCredentialHint: document.querySelector("#wienerCredentialHint"),
  wienerNavigationHint: document.querySelector("#wienerNavigationHint"),
  wienerAutomationStatus: document.querySelector("#wienerAutomationStatus"),
  compensaUsernameSetting: document.querySelector("#compensaUsernameSetting"),
  compensaPasswordSetting: document.querySelector("#compensaPasswordSetting"),
  toggleCompensaPassword: document.querySelector("#toggleCompensaPassword"),
  clearCompensaCredentials: document.querySelector("#clearCompensaCredentials"),
  clearCompensaNavigationPath: document.querySelector("#clearCompensaNavigationPath"),
  downloadCompensaNavigationPath: document.querySelector("#downloadCompensaNavigationPath"),
  restoreCompensaNavigationPath: document.querySelector("#restoreCompensaNavigationPath"),
  importCompensaNavigationPath: document.querySelector("#importCompensaNavigationPath"),
  compensaNavigationPathInput: document.querySelector("#compensaNavigationPathInput"),
  compensaCredentialHint: document.querySelector("#compensaCredentialHint"),
  compensaNavigationHint: document.querySelector("#compensaNavigationHint"),
  compensaAutomationStatus: document.querySelector("#compensaAutomationStatus"),
  compensaPortfolioImportButton: document.querySelector("#compensaPortfolioImportButton"),
  compensaPortfolioManualRepair: document.querySelector("#compensaPortfolioManualRepair"),
  compensaPortfolioImportStatus: document.querySelector("#compensaPortfolioImportStatus"),
  compensaPortfolioReportDialog: document.querySelector("#compensaPortfolioReportDialog"),
  closeCompensaPortfolioReport: document.querySelector("#closeCompensaPortfolioReport"),
  confirmCompensaPortfolioReport: document.querySelector("#confirmCompensaPortfolioReport"),
  compensaPortfolioReportAdded: document.querySelector("#compensaPortfolioReportAdded"),
  compensaPortfolioReportEnriched: document.querySelector("#compensaPortfolioReportEnriched"),
  compensaPortfolioReportWarning: document.querySelector("#compensaPortfolioReportWarning"),
  compensaPortfolioDownloadPdfs: document.querySelector("#compensaPortfolioDownloadPdfs"),
  compensaPortfolioPdfOptions: document.querySelector("#compensaPortfolioPdfOptions"),
  compensaPortfolioReportPdfs: document.querySelector("#compensaPortfolioReportPdfs"),
  compensaPortfolioReportPdfInfo: document.querySelector("#compensaPortfolioReportPdfInfo"),
  allianzPortfolioImportButton: document.querySelector("#allianzPortfolioImportButton"),
  allianzPortfolioManualRepair: document.querySelector("#allianzPortfolioManualRepair"),
  allianzPortfolioImportStatus: document.querySelector("#allianzPortfolioImportStatus"),
  allianzPortfolioReportDialog: document.querySelector("#allianzPortfolioReportDialog"),
  closeAllianzPortfolioReport: document.querySelector("#closeAllianzPortfolioReport"),
  confirmAllianzPortfolioReport: document.querySelector("#confirmAllianzPortfolioReport"),
  allianzPortfolioReportAdded: document.querySelector("#allianzPortfolioReportAdded"),
  allianzPortfolioReportEnriched: document.querySelector("#allianzPortfolioReportEnriched"),
  allianzPortfolioReportWarning: document.querySelector("#allianzPortfolioReportWarning"),
  allianzPortfolioDownloadPdfs: document.querySelector("#allianzPortfolioDownloadPdfs"),
  allianzPortfolioPdfOptions: document.querySelector("#allianzPortfolioPdfOptions"),
  allianzPortfolioReportPdfs: document.querySelector("#allianzPortfolioReportPdfs"),
  allianzPortfolioReportPdfInfo: document.querySelector("#allianzPortfolioReportPdfInfo"),
  allianzUsernameSetting: document.querySelector("#allianzUsernameSetting"),
  allianzPasswordSetting: document.querySelector("#allianzPasswordSetting"),
  toggleAllianzPassword: document.querySelector("#toggleAllianzPassword"),
  clearAllianzCredentials: document.querySelector("#clearAllianzCredentials"),
  allianzCredentialHint: document.querySelector("#allianzCredentialHint"),
  allianzAutomationStatus: document.querySelector("#allianzAutomationStatus"),
  settingsLogoInput: document.querySelector("#settingsLogoInput"),
  settingsLogoPreview: document.querySelector("#settingsLogoPreview"),
  settingsLogoMessage: document.querySelector("#settingsLogoMessage"),
  resetSettingsLogo: document.querySelector("#resetSettingsLogo"),
  settingsDatabaseName: document.querySelector("#settingsDatabaseName"),
  welcomeDialog: document.querySelector("#welcomeDialog"),
  welcomeQuickCard: document.querySelector("#welcomeQuickCard"),
  welcomeQuickStatus: document.querySelector("#welcomeQuickStatus"),
  welcomeQuickSetup: document.querySelector("#welcomeQuickSetup"),
  welcomeQuickSeparator: document.querySelector("#welcomeQuickSeparator"),
  welcomeDataFileCard: document.querySelector("#welcomeDataFileCard"),
  welcomeSettingsFileCard: document.querySelector("#welcomeSettingsFileCard"),
  welcomeDataFileStatus: document.querySelector("#welcomeDataFileStatus"),
  welcomeSettingsFileStatus: document.querySelector("#welcomeSettingsFileStatus"),
  welcomeOpenDataFile: document.querySelector("#welcomeOpenDataFile"),
  welcomeCreateDataFile: document.querySelector("#welcomeCreateDataFile"),
  welcomeOpenSettingsFile: document.querySelector("#welcomeOpenSettingsFile"),
  welcomeCreateSettingsFile: document.querySelector("#welcomeCreateSettingsFile"),
  welcomeSetupHint: document.querySelector("#welcomeSetupHint"),
  finishInitialSetup: document.querySelector("#finishInitialSetup"),
  emptyState: document.querySelector("#emptyState"),
  emptyTitle: document.querySelector("#emptyTitle"),
  emptyCopy: document.querySelector("#emptyCopy"),
  recordCount: document.querySelector("#recordCount"),
  todayDate: document.querySelector("#todayDate"),
  todayDateValue: document.querySelector("#todayDateValue"),
  todayWeekday: document.querySelector("#todayWeekday"),
  todayRenewalsBadge: document.querySelector("#todayRenewalsBadge"),
  todayTasksBadge: document.querySelector("#todayTasksBadge"),
  calendarDialog: document.querySelector("#calendarDialog"),
  closeCalendar: document.querySelector("#closeCalendar"),
  closeCalendarFooter: document.querySelector("#closeCalendarFooter"),
  calendarPreviousMonth: document.querySelector("#calendarPreviousMonth"),
  calendarNextMonth: document.querySelector("#calendarNextMonth"),
  calendarMonthLabel: document.querySelector("#calendarMonthLabel"),
  calendarDays: document.querySelector("#calendarDays"),
  calendarGoToToday: document.querySelector("#calendarGoToToday"),
  calendarSelectedDate: document.querySelector("#calendarSelectedDate"),
  calendarTaskForm: document.querySelector("#calendarTaskForm"),
  calendarTaskText: document.querySelector("#calendarTaskText"),
  addCalendarTasks: document.querySelector("#addCalendarTasks"),
  calendarTaskList: document.querySelector("#calendarTaskList"),
  calendarTasksEmpty: document.querySelector("#calendarTasksEmpty"),
  calendarRenewalsPanel: document.querySelector("#calendarRenewalsPanel"),
  calendarRenewalsTitle: document.querySelector("#calendarRenewalsTitle"),
  calendarRenewalsDate: document.querySelector("#calendarRenewalsDate"),
  calendarRenewalList: document.querySelector("#calendarRenewalList"),
  calendarRenewalsEmpty: document.querySelector("#calendarRenewalsEmpty"),
  calendarSummary: document.querySelector("#calendarSummary"),
  confirmDeleteDialog: document.querySelector("#confirmDeleteDialog"),
  confirmDeleteTitle: document.querySelector("#confirmDeleteTitle"),
  confirmDeleteMessage: document.querySelector("#confirmDeleteMessage"),
  closeConfirmDelete: document.querySelector("#closeConfirmDelete"),
  cancelConfirmDelete: document.querySelector("#cancelConfirmDelete"),
  acceptConfirmDelete: document.querySelector("#acceptConfirmDelete"),
  portfolioPathRepairDialog: document.querySelector("#portfolioPathRepairDialog"),
  portfolioPathRepairTitle: document.querySelector("#portfolioPathRepairTitle"),
  portfolioPathRepairMessage: document.querySelector("#portfolioPathRepairMessage"),
  closePortfolioPathRepair: document.querySelector("#closePortfolioPathRepair"),
  cancelPortfolioPathRepair: document.querySelector("#cancelPortfolioPathRepair"),
  acceptPortfolioPathRepair: document.querySelector("#acceptPortfolioPathRepair"),
  calendarRenewalMenu: document.querySelector("#calendarRenewalMenu"),
  calendarRenewalsHiddenRestore: document.querySelector("#calendarRenewalsHiddenRestore"),
  calendarRenewedDialog: document.querySelector("#calendarRenewedDialog"),
  closeCalendarRenewed: document.querySelector("#closeCalendarRenewed"),
  cancelCalendarRenewed: document.querySelector("#cancelCalendarRenewed"),
  calendarRenewedLater: document.querySelector("#calendarRenewedLater"),
  calendarRenewedSearch: document.querySelector("#calendarRenewedSearch"),
  calendarRenewedResults: document.querySelector("#calendarRenewedResults"),
  calendarRenewedEmpty: document.querySelector("#calendarRenewedEmpty"),
  calendarRenewedPolicyLabel: document.querySelector("#calendarRenewedPolicyLabel"),
  calendarRenewedPolicyMeta: document.querySelector("#calendarRenewedPolicyMeta"),
  usageGuideRow: document.querySelector(".usage-guide-row"),
  usageGuideButton: document.querySelector("#usageGuideButton"),
  usageGuideOverlay: document.querySelector("#usageGuideOverlay"),
  usageGuideArrows: document.querySelector("#usageGuideArrows"),
  usageGuideHighlights: document.querySelector("#usageGuideHighlights"),
  usageGuideLabels: document.querySelector("#usageGuideLabels"),
  resultsSummary: document.querySelector("#resultsSummary"),
  recordsPaginationBar: document.querySelector("#recordsPaginationBar"),
  recordsPerPage: document.querySelector("#recordsPerPage"),
  paginationNav: document.querySelector("#paginationNav"),
  paginationStatus: document.querySelector("#paginationStatus"),
  dataFileBar: document.querySelector("#dataFileBar"),
  dataFileName: document.querySelector("#dataFileName"),
  dataFileHint: document.querySelector("#dataFileHint"),
  openDataFile: document.querySelector("#openDataFile"),
  backupDataFile: document.querySelector("#backupDataFile"),
  saveDataFile: document.querySelector("#saveDataFile"),
  dataFileInput: document.querySelector("#dataFileInput"),
  dataIntegrityBanner: document.querySelector("#dataIntegrityBanner"),
  dataIntegrityTitle: document.querySelector("#dataIntegrityTitle"),
  dataIntegrityMessage: document.querySelector("#dataIntegrityMessage"),
  resolveDataIntegrity: document.querySelector("#resolveDataIntegrity"),
  dismissDataIntegrity: document.querySelector("#dismissDataIntegrity"),
  saveStatusPopup: document.querySelector("#saveStatusPopup"),
  saveStatusPopupText: document.querySelector("#saveStatusPopupText"),
  pageScrollControls: document.querySelector("#pageScrollControls"),
  scrollPageTop: document.querySelector("#scrollPageTop"),
  scrollPageBottom: document.querySelector("#scrollPageBottom"),
  mergeFirstDataFile: document.querySelector("#mergeFirstDataFile"),
  mergeSecondDataFile: document.querySelector("#mergeSecondDataFile"),
  mergeDataFiles: document.querySelector("#mergeDataFiles"),
  mergeConflictDialog: document.querySelector("#mergeConflictDialog"),
  mergeConflictProgress: document.querySelector("#mergeConflictProgress"),
  mergeConflictTitle: document.querySelector("#mergeConflictTitle"),
  mergeConflictCopy: document.querySelector("#mergeConflictCopy"),
  mergeFirstDatabaseName: document.querySelector("#mergeFirstDatabaseName"),
  mergeSecondDatabaseName: document.querySelector("#mergeSecondDatabaseName"),
  mergeFirstRecord: document.querySelector("#mergeFirstRecord"),
  mergeSecondRecord: document.querySelector("#mergeSecondRecord"),
  mergeChooseFirst: document.querySelector("#mergeChooseFirst"),
  mergeKeepBoth: document.querySelector("#mergeKeepBoth"),
  mergeChooseSecond: document.querySelector("#mergeChooseSecond"),
  mergeChooseAllFirst: document.querySelector("#mergeChooseAllFirst"),
  mergeChooseAllSecond: document.querySelector("#mergeChooseAllSecond"),
  cancelMergeConflict: document.querySelector("#cancelMergeConflict"),
  settingsFileBar: document.querySelector("#settingsFileBar"),
  settingsFileName: document.querySelector("#settingsFileName"),
  settingsFileHint: document.querySelector("#settingsFileHint"),
  openSettingsFile: document.querySelector("#openSettingsFile"),
  saveSettingsFile: document.querySelector("#saveSettingsFile"),
  settingsFileInput: document.querySelector("#settingsFileInput"),
  applicationUpdateRow: document.querySelector("#applicationUpdateRow"),
  applicationUpdateStatus: document.querySelector("#applicationUpdateStatus"),
  applicationUpdateDetails: document.querySelector("#applicationUpdateDetails"),
  downloadApplicationUpdate: document.querySelector("#downloadApplicationUpdate"),
  licenseRow: document.querySelector("#licenseRow"),
  licenseStatus: document.querySelector("#licenseStatus"),
  licenseDetails: document.querySelector("#licenseDetails"),
  licenseToggleForm: document.querySelector("#licenseToggleForm"),
  licenseForm: document.querySelector("#licenseForm"),
  licenseLogin: document.querySelector("#licenseLogin"),
  licensePassword: document.querySelector("#licensePassword"),
  licenseSave: document.querySelector("#licenseSave"),
  licenseCancel: document.querySelector("#licenseCancel"),
  licenseRemove: document.querySelector("#licenseRemove"),
  licenseBanner: document.querySelector("#licenseBanner"),
  licenseBannerTitle: document.querySelector("#licenseBannerTitle"),
  licenseBannerMessage: document.querySelector("#licenseBannerMessage"),
  licenseBannerAction: document.querySelector("#licenseBannerAction"),
  alwaysVisibleSuggestions: document.querySelector("#alwaysVisibleSuggestions"),
  notificationDock: document.querySelector("#notificationDock"),
  toastStack: document.querySelector("#toastStack"),
  attachmentsInfoDialog: document.querySelector("#attachmentsInfoDialog"),
  attachmentsInfoConfirm: document.querySelector("#attachmentsInfoConfirm"),
  attachmentsInfoCancel: document.querySelector("#attachmentsInfoCancel"),
  attachmentProgress: document.querySelector("#attachmentProgress"),
  attachmentProgressTitle: document.querySelector("#attachmentProgressTitle"),
  attachmentProgressDetail: document.querySelector("#attachmentProgressDetail"),
  attachmentProgressBar: document.querySelector("#attachmentProgressBar"),
};
const printColumnInputs = [...document.querySelectorAll("[data-print-column]")];



let currentAccount = null;
let agencyMembers = [];

let activeProfileFilter = "";

let renewalOwnerExclusions = new Set();
const RENEWAL_OWNER_EXCLUSIONS_STORAGE_KEY = "sekagent-odnowienia-konta-v1";
const PROFILE_FILTER_SESSION_KEY = "sekagent-profil-v1";

const PIN_SESSION_REQUIRED_CODE = "PIN_SESSION_REQUIRED";
const PIN_SESSION_MANUAL_RETRY_CODE = "PIN_SESSION_MANUAL_RETRY";
const SCREEN_LOCK_REQUEST_TIMEOUT_MS = 4000;
const SCREEN_LOCK_RETRY_DELAY_MS = 1500;
let activeAccountGatePromise = null;
let resolveActiveAccountGate = null;
let showAccountLoginGate = null;
let accountGateInitialized = false;
let applicationScreenLockInProgress = false;

function beginAccountGateSession(showGate = null) {
  if (activeAccountGatePromise) return activeAccountGatePromise;
  let resolveGate = null;
  const pendingGate = new Promise((resolve) => {
    resolveGate = resolve;
  });
  const sharedGate = pendingGate.finally(() => {
    if (activeAccountGatePromise === sharedGate) {
      activeAccountGatePromise = null;
      resolveActiveAccountGate = null;
    }
  });
  activeAccountGatePromise = sharedGate;
  resolveActiveAccountGate = resolveGate;
  showGate?.();
  return sharedGate;
}

function completeAccountGateSession() {
  resolveActiveAccountGate?.();
}

function requestPinReauthentication(options = {}) {
  if (activeAccountGatePromise) return activeAccountGatePromise;
  if (typeof showAccountLoginGate !== "function") {
    return Promise.reject(new Error("Nie można otworzyć bramki PIN. Odśwież aplikację."));
  }
  return beginAccountGateSession(() => showAccountLoginGate(options));
}

function waitBeforeScreenLockRetry() {
  return new Promise((resolve) => {
    globalThis.setTimeout(resolve, SCREEN_LOCK_RETRY_DELAY_MS);
  });
}

async function revokePinSessionForScreenLock() {
  while (true) {
    const controller = typeof globalThis.AbortController === "function"
      ? new globalThis.AbortController()
      : null;
    const timeoutId = controller
      ? globalThis.setTimeout(() => controller.abort(), SCREEN_LOCK_REQUEST_TIMEOUT_MS)
      : null;
    try {
      const response = await globalThis.fetch("/api/konto/lock", {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: "{}",
        ...(controller ? { signal: controller.signal } : {}),
      });
      if (response.status === 200) return;
      const payload = await response.json().catch(() => ({}));
      
      
      if (response.status === 401 && payload?.code === PIN_SESSION_REQUIRED_CODE) return;
    } catch {
      
      
    } finally {
      if (timeoutId !== null) globalThis.clearTimeout(timeoutId);
    }
    await waitBeforeScreenLockRetry();
  }
}

async function lockApplicationScreen() {
  if (!elements.screenLockButton || applicationScreenLockInProgress) return;
  applicationScreenLockInProgress = true;
  let markSessionRevoked = null;
  const sessionRevokedPromise = new Promise((resolve) => {
    markSessionRevoked = resolve;
  });
  
  
  const gatePromise = requestPinReauthentication({
    quickLock: true,
    sessionRevokedPromise,
  });
  try {
    await revokePinSessionForScreenLock();
    markSessionRevoked();
    await gatePromise;
  } catch (error) {
    showToast(error?.message || "Nie udało się zablokować ekranu.", "warning");
  } finally {
    applicationScreenLockInProgress = false;
  }
}

function getApiRequestDetails(input, init = {}) {
  const inputUrl = typeof input === "string" || input instanceof URL
    ? String(input)
    : String(input?.url || "");
  let url = null;
  try {
    url = new URL(inputUrl, globalThis.location?.href || "http://127.0.0.1/");
  } catch {
  }
  const method = String(init?.method || input?.method || "GET").toUpperCase();
  return { url, method };
}

function isLocalApiRequest(url) {
  if (!url) return false;
  let currentOrigin = "";
  try {
    currentOrigin = new URL(globalThis.location?.href || "http://127.0.0.1/").origin;
  } catch {
  }
  return url.origin === currentOrigin && (url.pathname === "/api" || url.pathname.startsWith("/api/"));
}

function canReplayApiRequestAfterPin(input, init, replayAfterPin) {
  const { url, method } = getApiRequestDetails(input, init);
  if (!isLocalApiRequest(url)) return false;
  if (method === "GET" || method === "HEAD") return true;
  
  
  
  return replayAfterPin === true
    && method === "POST"
    && typeof init?.body === "string"
    && (/^\/api\/automation\/jobs\/[^/]+\/(?:consumed|pdf-retry|cancel)$/.test(url.pathname)
      || /^\/api\/automation\/quote-batches\/[^/]+\/cancel$/.test(url.pathname));
}

async function responseRequiresPinSession(response) {
  if (response?.status !== 401) return false;
  const payload = await response.clone().json().catch(() => null);
  return payload?.code === PIN_SESSION_REQUIRED_CODE;
}

function createAbortedApiRequestError(signal) {
  if (signal?.reason instanceof Error) return signal.reason;
  const error = new Error("Żądanie zostało anulowane.");
  error.name = "AbortError";
  return error;
}

function waitForPinReauthentication(signal) {
  if (signal?.aborted) return Promise.reject(createAbortedApiRequestError(signal));
  const gatePromise = requestPinReauthentication();
  if (!signal?.addEventListener) return gatePromise;
  return new Promise((resolve, reject) => {
    let settled = false;
    const cleanup = () => signal.removeEventListener("abort", onAbort);
    const finish = (callback, value) => {
      if (settled) return;
      settled = true;
      cleanup();
      callback(value);
    };
    const onAbort = () => finish(reject, createAbortedApiRequestError(signal));
    signal.addEventListener("abort", onAbort, { once: true });
    gatePromise.then(
      () => finish(resolve),
      (error) => finish(reject, error),
    );
    if (signal.aborted) onAbort();
  });
}

async function apiFetch(
  input,
  init = {},
  {
    replayAfterPin = false,
    onPinWaitStart = null,
    onPinWaitEnd = null,
  } = {},
) {
  const firstResponse = await globalThis.fetch(input, init);
  const { url } = getApiRequestDetails(input, init);
  if (!isLocalApiRequest(url) || !(await responseRequiresPinSession(firstResponse))) {
    return firstResponse;
  }

  const signal = init?.signal || input?.signal;
  onPinWaitStart?.();
  try {
    await waitForPinReauthentication(signal);
  } finally {
    onPinWaitEnd?.();
  }
  const replayable = canReplayApiRequestAfterPin(input, init, replayAfterPin);
  if (!replayable) {
    const error = new Error("Sesja PIN została odnowiona. Uruchom tę operację ponownie.");
    error.code = PIN_SESSION_MANUAL_RETRY_CODE;
    throw error;
  }
  if (signal?.aborted) throw createAbortedApiRequestError(signal);

  
  
  return globalThis.fetch(input, init);
}

function loadRenewalOwnerExclusions() {
  try {
    const saved = JSON.parse(globalThis.localStorage?.getItem(RENEWAL_OWNER_EXCLUSIONS_STORAGE_KEY) || "[]");
    if (Array.isArray(saved)) renewalOwnerExclusions = new Set(saved.filter((id) => typeof id === "string"));
  } catch {
  }
}

function saveRenewalOwnerExclusions() {
  try {
    globalThis.localStorage?.setItem(
      RENEWAL_OWNER_EXCLUSIONS_STORAGE_KEY,
      JSON.stringify([...renewalOwnerExclusions]),
    );
  } catch {
  }
}

loadRenewalOwnerExclusions();


function getPolicyOwnerIdForFiltering(policy) {
  return policy?.ownerId || currentAccount?.id || "";
}



function createPolicyOwnerBadge(policy) {
  const ownerId = policy?.ownerId || "";
  if (!ownerId || !currentAccount || ownerId === currentAccount.id) return "";
  const member = agencyMembers.find((entry) => entry.id === ownerId);
  if (member) {
    return `<span class="policy-owner-badge" title="Polisa pracownika: ${escapeHtml(member.label)} (${escapeHtml(ownerId)})">${escapeHtml(member.label)}</span>`;
  }
  return `<span class="policy-owner-badge policy-owner-badge--unknown" title="Polisa konta ${escapeHtml(ownerId)} - konta nie ma na liście pracowników">${escapeHtml(ownerId.slice(0, 4))}…</span>`;
}

const EMPLOYEE_PACKAGE_TRANSACTION_ID_PATTERN = /^[A-Za-z0-9][A-Za-z0-9_-]{7,127}$/;
const EMPLOYEE_PACKAGE_DIGEST_PATTERN = /^[a-f0-9]{64}$/;
const MAX_EMPLOYEE_PACKAGE_IMPORT_RECEIPTS = 256;
const EMPLOYEE_TO_CENTRAL_PACKAGE_KIND = "employee-to-central";
const CENTRAL_TO_EMPLOYEE_PACKAGE_KIND = "central-to-employee";
const EMPLOYEE_PACKAGE_RECEIPT_KINDS = new Set([
  EMPLOYEE_TO_CENTRAL_PACKAGE_KIND,
  CENTRAL_TO_EMPLOYEE_PACKAGE_KIND,
]);
const EMPLOYEE_PACKAGE_IMPORT_LOCK_NAME = "baza-polis-employee-package-import";
let policies = loadLegacyPolicies();
let deletedPolicies = [];
let calendarTasks = [];
let employeePackageImportReceipts = [];


let clientAccountLinks = [];
let sortMode = null;
let sortDirection = "asc";


let insurerSortSelection = null;
let policyTypeSortIndex = -1;
let renewalsOnly = false;
let renewalWindowDays = RENEWAL_WINDOW_DAYS;


const renewalShowExpired = true;
let hideRenewedPolicies = false;
let hideInactivePolicies = false;
let currentPage = 1;
let pageJumpOpen = false;
let editingPolicyId = null;
let contactDetailsPolicyId = null;
let contactDetailsSaving = false;
let vehicleDetailsPolicyId = null;
let vehicleDetailsSaving = false;
let vehicleDetailsEditingField = "";
let vehicleDetailsHistoryBusy = false;
let clientProfilePolicyId = null;
let clientProfileEditingPolicyId = null;
let clientProfileEditingVehicleKey = "";


let clientProfileVehicleHistoryBusyKey = "";
const clientProfileVehicleHistoryHighlights = new Set();
let clientProfileSaving = false;
let clientProfileMergeOpen = false;
let clientProfileMergeSearchPolicyId = null;
let clientProfileLinkPanelOpen = false;
let clientProfileLinkSearchPolicyId = null;
let calendarViewDate = null;
let calendarSelectedDate = "";
let calendarSaving = false;
let expandedPolicyId = null;
let attachmentPanelTransitioning = false;
let recordAttachmentPolicyId = null;
let activeAttachmentDropPanel = null;
let pendingAttachments = [];
let attachmentOperationActive = false;
let addPolicySubmitting = false;


const TOAST_STACK_LIMIT = 5;
const TOAST_DISMISS_AFTER_MS = 2600;
const TOAST_EXIT_MS = 200;
const toastDismissTimers = new Map();
let insurerSettingsPopupTimer = null;
let insurerSettingsPopupHideTimer = null;
let pageScrollControlsFrame = 0;
let usageGuideActive = false;
let usageGuideFadeTimer = null;
let usageGuideEndTimer = null;
let usageGuideRefreshFrame = 0;
let dataFileHandle = null;
let rememberedDataFileHandle = null;
let dataFileName = "";
let initialDataFileReady = false;
let dataFileRevision = null;
let dataFileNeedsVerification = false;
let dataFileConflictBlocked = false;
let hasUnsavedPolicyChanges = false;
let policyChangeGeneration = 0;
let dataIntegrityNotice = null;
let hasLegacyPolicies = policies.length > 0;
let hasLegacyUiSettings = false;
let uiSettings = loadUiSettings();
let settingsFileHandle = null;
let rememberedSettingsFileHandle = null;
let settingsFileName = "";
let settingsFileRevision = null;
let initialSettingsFileReady = false;
let attachmentsBaseDirectoryHandle = null;
let rememberedAttachmentsBaseDirectoryHandle = null;
let appDirectoryHandle = null;
let rememberedAppDirectoryHandle = null;
let quickSetupInProgress = false;
let initialSetupFinishInProgress = false;
let welcomeSetupError = "";
let welcomeConnectFailureAccepted = false;
let pendingSettingsTheme = "dark";
let settingsOpeningTheme = "dark";
let pendingSettingsFontSize = "standard";
let settingsOpeningFontSize = "standard";
let pendingShowAppearanceDock = true;
let settingsOpeningShowAppearanceDock = true;
let pendingShowStartDateInput = false;
let settingsOpeningShowStartDateInput = false;
let pendingShowUsageGuide = true;
let settingsOpeningShowUsageGuide = true;
let quickAppearanceSaving = false;
let appearanceDockCollapsed = getSavedAppearanceDockCollapsed();
let appliedStartDateInputSetting = false;
let pendingLogoDataUrl = "";
let pendingDatabaseName = DEFAULT_DATABASE_NAME;
let pendingInsurerSettings = [];
let wartaAutomationAvailable = false;
let wartaPasswordSaved = false;
let inslyPasswordSaved = false;
let pzuPasswordSaved = false;
let wartaPathSaved = false;
let generaliPasswordSaved = false;
let generaliPathSaved = false;
let mtuPasswordSaved = false;
let mtuPathSaved = false;
let hestiaPasswordSaved = false;
let trastiPasswordSaved = false;
let trastiPathSaved = false;
let wienerPasswordSaved = false;
let wienerPathSaved = false;
let compensaPasswordSaved = false;
let compensaPathSaved = false;
let allianzPasswordSaved = false;
let quoteJobPollTimer = null;
let activeQuoteJobIds = new Set();
let quoteJobStates = new Map();
let quoteJobPollFailures = new Map();
let quoteCalculationActive = false;
let quoteCancellationPending = false;
let quoteCalculatorManualMode = false;
let quoteCalculationErrors = [];
let activeQuoteBatch = null;
let quoteContextCleanupRun = null;
const pendingQuoteContextCleanups = new Map();
let quoteHistorySaveQueue = Promise.resolve();
let quoteResultsRestoreToken = 0;
let renderedQuoteResultsContext = null;
let renderedQuotePremiums = [];
let quotePrintGroups = [];


let expandedQuoteResultInsurers = new Set();
let activeQuoteArchiveEntryId = null;
let quoteArchiveEntriesById = new Map();
let quoteArchiveRenderToken = 0;
let expandedQuoteArchiveGroupKey = null;
let activeSettingsTab = "application";
let mergeConflictResolver = null;


const ENTRY_ORGANIZER_GROUPS = [
  { id: "nazwy", label: "Nazwy klientów do ujednolicenia" },
  { id: "rodzaje", label: "Rodzaje polis do poprawienia" },
  { id: "towarzystwa", label: "Towarzystwa MTU / Hestia po serii numeru" },
  { id: "daty", label: "Daty pierwszej rejestracji pojazdów" },
  { id: "pdf", label: "Dane pojazdów i ryzyk z plików PDF" },
  { id: "nipy", label: "NIP-y firm z rejestru podatników" },
  { id: "pesele", label: "Brakujące PESEL-e" },
  { id: "rozdzielenia", label: "Sklejone konta osoby i firmy do rozdzielenia" },
  { id: "powiazania", label: "Powiązania osoby z firmą" },
  { id: "wznowienia", label: "Powiązania wznowień polis" },
];
const ENTRY_ORGANIZER_GROUP_SELECTION_KEY = "iseca-porzadkowanie-grupy-v1";
let entryOrganizerSelectedGroups = new Set(ENTRY_ORGANIZER_GROUPS.map((group) => group.id));
let entryOrganizerQueue = [];
let entryOrganizerIndex = 0;
let entryOrganizerStage = "matches";
let entryOrganizerManualQueue = [];
let entryOrganizerManualIndex = 0;
let entryOrganizerApprovedCount = 0;
let entryOrganizerRejectedCount = 0;
let entryOrganizerManualSavedCount = 0;
let entryOrganizerManualSkippedCount = 0;
let entryOrganizerNameUnifiedCount = 0;
let entryOrganizerClassificationFixedCount = 0;
let entryOrganizerErgoInsurerFixedCount = 0;
let entryOrganizerFirstRegistrationDateFilledCount = 0;
let entryOrganizerAttachmentDataFilledCount = 0;
let entryOrganizerRenewalVerifiedCount = 0;
let entryOrganizerNipFilledCount = 0;
let entryOrganizerLinkQueue = [];
let entryOrganizerLinkIndex = 0;
let entryOrganizerLinkedCount = 0;
let entryOrganizerSplitQueue = [];
let entryOrganizerSplitIndex = 0;
let entryOrganizerSplitCount = 0;
let entryOrganizerBusy = false;
let activeAlwaysSuggestionInput = null;
let visibleAlwaysSuggestions = [];
let addFormAutoFilledIdentity = "";
let editingPolicyDraft = null;
const terminationPdfTemplatePromises = new Map();
let terminationDetailsResolver = null;
let zipCrc32Table = null;
const baseFontStyles = new WeakMap();

function getAttachmentMimeType(fileLike) {
  const declaredType = String(fileLike?.type ?? "").trim().toLocaleLowerCase("en");
  if (ALLOWED_ATTACHMENT_TYPES.has(declaredType)) return declaredType;
  const extension = String(fileLike?.name ?? "").split(".").pop()?.toLocaleLowerCase("en") ?? "";
  return ATTACHMENT_EXTENSION_TYPES[extension] ?? "";
}

function sanitizeAttachmentDisplayName(name, type) {
  return String(name || (type === "application/pdf" ? "załącznik.pdf" : "załącznik.jpg"))
    .replace(/[\u0000-\u001F]/g, "")
    .trim()
    .slice(0, 180);
}

function normalizeAttachmentCategory(value) {
  const category = String(value ?? "")
    .replace(/[\u0000-\u001F]/g, "")
    .replace(/\s+/g, " ")
    .trim()
    .slice(0, MAX_ATTACHMENT_CATEGORY_LENGTH);
  const isDefaultCategory = category.toLocaleLowerCase("pl") === DEFAULT_ATTACHMENT_CATEGORY.toLocaleLowerCase("pl");
  return isDefaultCategory ? "" : category;
}

function normalizeAttachmentRelativePath(relativePath) {
  if (!Array.isArray(relativePath) || relativePath.length < 3 || relativePath.length > 4) return null;
  const normalizedPath = relativePath.map((part) => String(part ?? "").trim());
  const containsUnsafePart = normalizedPath.some((part) => (
    !part
    || part === "."
    || part === ".."
    || /[<>:"/\\|?*\u0000-\u001F]/.test(part)
  ));
  if (containsUnsafePart || normalizedPath[0] !== ATTACHMENTS_DIRECTORY_NAME) return null;
  return normalizedPath;
}

function isExternalAttachment(attachment) {
  return attachment?.storage === "file" && Boolean(normalizeAttachmentRelativePath(attachment.relativePath));
}

function normalizeAttachment(attachment) {
  if (!attachment || typeof attachment !== "object") return null;
  const type = getAttachmentMimeType(attachment);
  if (!type) return null;

  const size = Number(attachment.size);
  const normalizedAttachment = {
    id: String(attachment.id || (globalThis.crypto?.randomUUID?.() ?? `${Date.now()}-${Math.random()}`)),
    name: sanitizeAttachmentDisplayName(attachment.name, type),
    type,
    size: Number.isFinite(size) && size >= 0 ? size : 0,
    createdAt: Number(attachment.createdAt) || Date.now(),
  };
  const category = normalizeAttachmentCategory(attachment.category);
  if (category) normalizedAttachment.category = category;

  const relativePath = normalizeAttachmentRelativePath(attachment.relativePath);
  if (attachment.storage === "file" && relativePath) {
    return { ...normalizedAttachment, storage: "file", relativePath };
  }

  const dataUrl = String(attachment.dataUrl ?? "");
  const dataUrlHeader = dataUrl.slice(0, 100).match(/^data:([^;,]+);base64,/i);
  if (!dataUrlHeader || dataUrlHeader[1].toLocaleLowerCase("en") !== type) return null;
  return { ...normalizedAttachment, dataUrl };
}

function normalizePolicyAttachments(attachments) {
  if (!Array.isArray(attachments)) return [];
  return attachments.map(normalizeAttachment).filter(Boolean);
}




const RISK_SUMMARY_CONTACT_LINE_PATTERN = /^Ryzyka (?:MTU|Hesti[ia]|Trasti|Wart[ay]|Wiener|PZU|TU[WZ]?)\s*:\s*/i;

function extractRiskSummaryFromContact(contact) {
  const text = String(contact ?? "");
  if (!RISK_SUMMARY_CONTACT_LINE_PATTERN.test(text) && !text.includes("\nRyzyka ")) {
    return { contact: text, riskSummary: "" };
  }
  const riskParts = [];
  const contactLines = [];
  text.split("\n").forEach((line) => {
    const match = line.match(RISK_SUMMARY_CONTACT_LINE_PATTERN);
    if (!match) {
      contactLines.push(line);
      return;
    }
    const value = line.slice(match[0].length).trim();
    if (value) riskParts.push(value);
  });
  return {
    contact: contactLines.join("\n").trim(),
    riskSummary: riskParts.join(" • ").slice(0, 400),
  };
}


const OWNER_ID_PATTERN = /^[A-Z2-9]{4}-[A-Z2-9]{4}-[A-Z2-9]{4}$/;

function normalizePolicyOwnerId(value) {
  const ownerId = String(value || "").trim().toUpperCase();
  return OWNER_ID_PATTERN.test(ownerId) ? ownerId : "";
}



function normalizeLoadedPolicies(saved, defaultOwnerId = currentAccount?.id || "") {
  if (!Array.isArray(saved)) return [];
  const fallbackOwnerId = normalizePolicyOwnerId(defaultOwnerId);
  return saved.map((policy) => {
    const normalizedPolicy = policy && typeof policy === "object" ? policy : {};
    const extractedRisks = extractRiskSummaryFromContact(normalizedPolicy.contact);
    const clientAddress = normalizeClientAddress(normalizedPolicy.clientAddress);
    const importedPolicyTracking = normalizeImportedPolicyTracking(normalizedPolicy);
    return {
      ...normalizedPolicy,
      ownerId: normalizePolicyOwnerId(normalizedPolicy.ownerId) || fallbackOwnerId,
      contact: extractedRisks.contact,
      riskSummary: String(normalizedPolicy.riskSummary || "").trim() || extractedRisks.riskSummary,
      id: String(normalizedPolicy.id || (globalThis.crypto?.randomUUID?.() ?? `${Date.now()}-${Math.random()}`)),
      secondaryIdentityNumber: String(normalizedPolicy.secondaryIdentityNumber || "").trim(),
      vehicleMake: normalizeVehicleDetail(normalizedPolicy.vehicleMake),
      vehicleModel: normalizeVehicleDetail(normalizedPolicy.vehicleModel),
      vehicleType: normalizeVehicleDetail(normalizedPolicy.vehicleType),
      productionYear: normalizeVehicleDetail(normalizedPolicy.productionYear),
      fuelType: normalizeVehicleDetail(normalizedPolicy.fuelType),
      seats: normalizeVehicleDetail(normalizedPolicy.seats),
      grossWeight: normalizeVehicleDetail(normalizedPolicy.grossWeight),
      vin: normalizeVehicleIdentifier(normalizedPolicy.vin),
      firstRegistrationDate: normalizeFirstRegistrationDate(normalizedPolicy.firstRegistrationDate),
      engineCapacity: normalizeVehicleDetail(normalizedPolicy.engineCapacity),
      enginePower: normalizeVehicleDetail(normalizedPolicy.enginePower),
      mileage: normalizeVehicleDetail(normalizedPolicy.mileage),
      driverLicenseDate: normalizeDriverLicenseDate(normalizedPolicy.driverLicenseDate),
      clientPhone: normalizeClientPhone(normalizedPolicy.clientPhone),
      clientEmail: normalizeClientEmail(normalizedPolicy.clientEmail),
      clientAddress,
      clientPostalCode: normalizeClientPostalCode(normalizedPolicy.clientPostalCode)
        || extractClientPostalCode(clientAddress),
      renewalStatus: normalizedPolicy.renewalStatus ?? null,
      attachments: normalizePolicyAttachments(normalizedPolicy.attachments),
      validFromManuallyEdited: importedPolicyTracking.manuallyEditedImportedFields
        ?.includes("validFrom") === true,
      ...importedPolicyTracking,
    };
  });
}

function normalizeDeletedPolicies(saved) {
  if (!Array.isArray(saved)) return [];
  return normalizeLoadedPolicies(saved).map((policy) => {
    const deletedAt = Number(policy.deletedAt);
    return {
      ...policy,
      deletedAt: Number.isFinite(deletedAt) && deletedAt > 0 ? deletedAt : Date.now(),
    };
  });
}

function normalizeCalendarTasks(saved) {
  if (!Array.isArray(saved)) return [];
  const usedIds = new Set();
  return saved.map((task) => {
    if (!task || typeof task !== "object") return null;
    const date = String(task.date ?? "").trim();
    const text = String(task.text ?? "").trim().slice(0, MAX_CALENDAR_TASK_LENGTH);
    if (!parseLocalDate(date) || !text) return null;

    let id = String(task.id ?? "").trim();
    if (!id || usedIds.has(id)) {
      id = globalThis.crypto?.randomUUID?.() ?? `${date}-${Date.now()}-${Math.random()}`;
    }
    usedIds.add(id);

    const createdAt = Number(task.createdAt);
    const updatedAt = Number(task.updatedAt);
    return {
      id,
      date: formatDateForInput(parseLocalDate(date)),
      text,
      completed: task.completed === true,
      createdAt: Number.isFinite(createdAt) && createdAt > 0 ? createdAt : Date.now(),
      updatedAt: Number.isFinite(updatedAt) && updatedAt > 0
        ? updatedAt
        : (Number.isFinite(createdAt) && createdAt > 0 ? createdAt : Date.now()),
    };
  }).filter(Boolean);
}

function loadLegacyPolicies() {
  try {
    return normalizeLoadedPolicies(JSON.parse(localStorage.getItem(LEGACY_STORAGE_KEY)));
  } catch {
    return [];
  }
}

function clearLegacyPolicies() {
  try {
    localStorage.removeItem(LEGACY_STORAGE_KEY);
  } catch {
  }
  hasLegacyPolicies = false;
}

function loadUiSettings() {
  let saved = null;
  let savedTheme = null;
  let bootTheme = null;
  try {
    const savedSettingsValue = localStorage.getItem(UI_SETTINGS_KEY);
    savedTheme = localStorage.getItem(THEME_KEY);
    bootTheme = localStorage.getItem(BOOT_THEME_KEY);
    saved = savedSettingsValue ? JSON.parse(savedSettingsValue) : null;
    hasLegacyUiSettings = Boolean(savedSettingsValue || savedTheme);
  } catch {
    saved = null;
    savedTheme = null;
    bootTheme = null;
    hasLegacyUiSettings = false;
  }
  return normalizeUiSettings({
    ...saved,
    theme: savedTheme || saved?.theme || bootTheme,
  });
}

function getRememberedBootTheme() {
  try {
    const theme = localStorage.getItem(BOOT_THEME_KEY);
    return theme === "dark" || theme === "light" ? theme : "";
  } catch {
    return "";
  }
}

function rememberBootTheme(theme) {
  if (theme !== "dark" && theme !== "light") return;
  try {
    localStorage.setItem(BOOT_THEME_KEY, theme);
  } catch {
  }
}

function applyStartupTheme(statusTheme) {
  const rememberedTheme = getRememberedBootTheme();
  const serverTheme = statusTheme === "dark" || statusTheme === "light" ? statusTheme : "";
  const theme = rememberedTheme || serverTheme;
  if (!theme) return;
  uiSettings = normalizeUiSettings({ ...uiSettings, theme });
  rememberBootTheme(theme);
  applyTheme(theme);
}

function getDefaultTheme() {
  return "dark";
}

function normalizeUiFontSize(fontSize) {
  return fontSize === "medium" || fontSize === "large" ? fontSize : "standard";
}

function normalizeDatabaseName(value) {
  const normalizedName = String(value ?? "")
    .replace(/\s+/g, " ")
    .trim()
    .slice(0, MAX_DATABASE_NAME_LENGTH);
  if (normalizedName.toLocaleLowerCase("pl") === "sekagent") return DEFAULT_DATABASE_NAME;
  return normalizedName || DEFAULT_DATABASE_NAME;
}

function normalizeInsurerUrl(value) {
  const rawUrl = String(value ?? "").trim().slice(0, MAX_INSURER_URL_LENGTH);
  if (!rawUrl) return "";
  const candidate = /^[a-z][a-z\d+.-]*:\/\//i.test(rawUrl) ? rawUrl : `https://${rawUrl}`;
  try {
    const parsedUrl = new URL(candidate);
    return parsedUrl.protocol === "http:" || parsedUrl.protocol === "https:" ? parsedUrl.href : "";
  } catch {
    return "";
  }
}

function normalizeInsurerId(value) {
  const insurerId = String(value ?? "")
    .toLocaleLowerCase("pl")
    .normalize("NFD")
    .replace(/[\u0300-\u036f]/g, "")
    .replace(/[^a-z0-9]+/g, "-")
    .replace(/^-+|-+$/g, "")
    .slice(0, MAX_INSURER_NAME_LENGTH);
  return INSURER_ID_ALIASES[insurerId] || insurerId;
}

function normalizeInsurerSettings(insurers) {
  
  
  
  const source = Array.isArray(insurers) ? [...insurers] : [...DEFAULT_INSURER_SETTINGS];
  if (Array.isArray(insurers)) {
    const sourceIds = new Set(source.map((entry) => normalizeInsurerId(
      typeof entry === "string" ? entry : entry?.id || entry?.name,
    )).filter(Boolean));
    DEFAULT_INSURER_SETTINGS.forEach((entry) => {
      if (!sourceIds.has(entry.id)) source.push(entry);
    });
  }
  const seenNames = new Set();
  const seenIds = new Set();
  const normalizedInsurers = [];
  for (const entry of source) {
    const name = String(typeof entry === "string" ? entry : entry?.name ?? "")
      .trim()
      .slice(0, MAX_INSURER_NAME_LENGTH);
    const nameKey = normalize(name);
    const id = normalizeInsurerId(typeof entry === "string" ? name : entry?.id || name);
    if (!nameKey || !id || seenNames.has(nameKey) || seenIds.has(id)) continue;
    seenNames.add(nameKey);
    seenIds.add(id);
    
    
    const savedUrl = normalizeInsurerUrl(typeof entry === "string" ? "" : entry?.url);
    const catalogUrl = DEFAULT_INSURER_SETTINGS.find((catalogEntry) => catalogEntry.id === id)?.url || "";
    normalizedInsurers.push({
      id,
      name,
      url: savedUrl || normalizeInsurerUrl(catalogUrl),
    });
  }
  return normalizedInsurers;
}

function getServedInsurerIds() {
  if (Array.isArray(currentAccount?.servedInsurers)) {
    return new Set(currentAccount.servedInsurers.map(normalizeInsurerId).filter(Boolean));
  }
  
  
  return new Set(normalizeInsurerSettings(uiSettings?.insurers).map((insurer) => insurer.id));
}

function isInsurerServed(insurer) {
  const insurerId = normalizeInsurerId(typeof insurer === "string" ? insurer : insurer?.id || insurer?.name);
  return Boolean(insurerId && getServedInsurerIds().has(insurerId));
}

function getServedInsurerSettings() {
  return normalizeInsurerSettings(uiSettings.insurers).filter(isInsurerServed);
}

function getMissingPolicyInsurers(policyRecords, configuredInsurers = uiSettings.insurers) {
  const configured = normalizeInsurerSettings(configuredInsurers);
  const configuredNames = new Set(configured.map((insurer) => normalize(insurer.name)));
  const configuredIds = new Set(configured.map((insurer) => insurer.id));
  const missingInsurers = [];
  for (const policy of Array.isArray(policyRecords) ? policyRecords : []) {
    const name = String(policy?.insurer ?? "").trim().slice(0, MAX_INSURER_NAME_LENGTH);
    const nameKey = normalize(name);
    const id = normalizeInsurerId(name);
    if (!nameKey || configuredNames.has(nameKey) || configuredIds.has(id)) continue;
    configuredNames.add(nameKey);
    configuredIds.add(id);
    missingInsurers.push({ id, name, url: "" });
  }
  return missingInsurers;
}

async function syncImportedInsurersToSettings(policyRecords) {
  const missingInsurers = getMissingPolicyInsurers(policyRecords);
  if (missingInsurers.length === 0) return { addedInsurers: [], saved: true };
  const nextUiSettings = normalizeUiSettings({
    ...uiSettings,
    insurers: [...normalizeInsurerSettings(uiSettings.insurers), ...missingInsurers],
  });
  if (!(await persistUiSettings(nextUiSettings))) {
    return { addedInsurers: missingInsurers, saved: false };
  }
  uiSettings = nextUiSettings;
  return { addedInsurers: missingInsurers, saved: true };
}

function getImportedInsurersResultMessage(result) {
  if (!result?.addedInsurers?.length) return "";
  const names = result.addedInsurers.map((insurer) => insurer.name).join(", ");
  return result.saved
    ? ` Dodano do listy towarzystw: ${names}.`
    : ` Nie udało się dopisać do listy towarzystw: ${names}.`;
}

function updateTodayDate() {
  const today = new Date();
  const machineDate = formatDateForInput(today);
  elements.todayDateValue.textContent = SHORT_DATE_FORMAT.format(today);
  elements.todayWeekday.textContent = WEEKDAY_NAME_FORMAT.format(today);
  elements.todayDate.dataset.date = machineDate;
  const fullDate = FULL_DATE_FORMAT.format(today);
  elements.todayDate.title = "Otwórz kalendarz zadań i wznowień";
  updateTodayTaskIndicator(machineDate, fullDate);
}

function pluralizeTasks(count) {
  if (count === 1) return "1 zadanie";
  const lastTwo = count % 100;
  const last = count % 10;
  if (last >= 2 && last <= 4 && !(lastTwo >= 12 && lastTwo <= 14)) return `${count} zadania`;
  return `${count} zadań`;
}

function getCalendarTasksForDate(dateKey) {
  return calendarTasks.filter((task) => task.date === dateKey);
}

function getIncompleteCalendarTaskCount(dateKey) {
  return calendarTasks.filter((task) => task.date === dateKey && !task.completed).length;
}

function getCalendarRenewalsForDate(dateKey) {
  const selectedDate = parseLocalDate(dateKey);
  if (!selectedDate) return [];
  const selectedDateKey = formatDateForInput(selectedDate);
  return policies
    .filter((policy) => {
      if (isTravelPolicy(policy) || policy?.renewalStatus === "renewed" || policy?.calendarHidden === true) return false;
      const endDate = parseLocalDate(policy?.validUntil);
      return endDate && formatDateForInput(endDate) === selectedDateKey;
    })
    .sort((first, second) => (
      compareAlphabetically(first.clientName, second.clientName)
      || compareAlphabetically(first.registration, second.registration)
      || compareAlphabetically(first.policyNumber, second.policyNumber)
    ));
}



function getCalendarRenewalCountsByDate() {
  const counts = new Map();
  for (const policy of policies) {
    if (isTravelPolicy(policy) || policy?.renewalStatus === "renewed" || policy?.calendarHidden === true) continue;
    const endDate = parseLocalDate(policy?.validUntil);
    if (!endDate) continue;
    const dateKey = formatDateForInput(endDate);
    counts.set(dateKey, (counts.get(dateKey) ?? 0) + 1);
  }
  return counts;
}

function getHiddenCalendarRenewalCountForDate(dateKey) {
  const selectedDate = parseLocalDate(dateKey);
  if (!selectedDate) return 0;
  const selectedDateKey = formatDateForInput(selectedDate);
  return policies.filter((policy) => {
    if (policy?.calendarHidden !== true || isTravelPolicy(policy) || policy?.renewalStatus === "renewed") return false;
    const endDate = parseLocalDate(policy?.validUntil);
    return Boolean(endDate && formatDateForInput(endDate) === selectedDateKey);
  }).length;
}

function getIncompleteCalendarTaskCountsByDate() {
  const counts = new Map();
  for (const task of calendarTasks) {
    if (task.completed) continue;
    counts.set(task.date, (counts.get(task.date) ?? 0) + 1);
  }
  return counts;
}

function getCalendarRenewalStatus(policy) {
  if (policy?.renewalStatus === "renewed") {
    return { label: "Odnowiona", modifier: "renewed" };
  }
  if (policy?.renewalStatus === "not-renewed") {
    return { label: "Utracona", modifier: "lost" };
  }
  return { label: "Do wznowienia", modifier: "pending" };
}

function updateTodayTaskIndicator(dateKey = formatDateForInput(new Date()), fullDate = "") {
  const incompleteCount = getIncompleteCalendarTaskCount(dateKey);
  const renewalCount = getCalendarRenewalsForDate(dateKey).length;
  elements.todayTasksBadge.textContent = incompleteCount > 99 ? "99+" : String(incompleteCount);
  elements.todayTasksBadge.hidden = incompleteCount === 0;
  elements.todayRenewalsBadge.textContent = renewalCount > 99 ? "99+" : String(renewalCount);
  elements.todayRenewalsBadge.hidden = renewalCount === 0;
  const dateLabel = fullDate || FULL_DATE_FORMAT.format(parseLocalDate(dateKey));
  const calendarDescriptions = [];
  if (renewalCount > 0) calendarDescriptions.push(`${pluralizePolicies(renewalCount)} do wznowienia`);
  if (incompleteCount > 0) calendarDescriptions.push(`${pluralizeTasks(incompleteCount)} niewykonane`);
  elements.todayDate.setAttribute("aria-label", [
    `Dzisiejsza data: ${dateLabel}`,
    ...calendarDescriptions,
    "Otwórz kalendarz zadań i wznowień",
  ].join(". "));
}

function formatCalendarDateLabel(dateKey) {
  const date = parseLocalDate(dateKey);
  if (!date) return "-";
  return FULL_DATE_FORMAT.format(date);
}

function setCalendarSaving(isSaving) {
  calendarSaving = Boolean(isSaving);
  elements.calendarTaskText.disabled = calendarSaving;
  elements.addCalendarTasks.disabled = calendarSaving;
  elements.addCalendarTasks.textContent = calendarSaving ? "Zapisywanie..." : "Dodaj zadanie";
  elements.closeCalendar.disabled = calendarSaving;
  elements.closeCalendarFooter.disabled = calendarSaving;
  elements.calendarPreviousMonth.disabled = calendarSaving;
  elements.calendarNextMonth.disabled = calendarSaving;
  elements.calendarGoToToday.disabled = calendarSaving;
  elements.calendarDays.querySelectorAll("button").forEach((button) => {
    button.disabled = calendarSaving;
  });
  elements.calendarTaskList.querySelectorAll("button").forEach((button) => {
    button.disabled = calendarSaving;
  });
}

function renderCalendarDays() {
  const viewDate = calendarViewDate || new Date();
  const viewYear = viewDate.getFullYear();
  const viewMonth = viewDate.getMonth();
  const monthStart = new Date(viewYear, viewMonth, 1, 12);
  const mondayOffset = (monthStart.getDay() + 6) % 7;
  const daysInMonth = new Date(viewYear, viewMonth + 1, 0).getDate();
  
  
  const totalCells = 42;
  const todayKey = formatDateForInput(new Date());

  elements.calendarMonthLabel.textContent = MONTH_YEAR_FORMAT.format(monthStart);

  const incompleteTaskCounts = getIncompleteCalendarTaskCountsByDate();
  const renewalCounts = getCalendarRenewalCountsByDate();
  const days = [];
  for (let index = 0; index < totalCells; index += 1) {
    const dayOfMonth = index - mondayOffset + 1;
    if (dayOfMonth < 1 || dayOfMonth > daysInMonth) {
      days.push('<span class="calendar-day calendar-day--empty" aria-hidden="true"></span>');
      continue;
    }
    const date = new Date(viewYear, viewMonth, dayOfMonth, 12);
    const dateKey = formatDateForInput(date);
    const incompleteCount = incompleteTaskCounts.get(dateKey) ?? 0;
    const renewalCount = renewalCounts.get(dateKey) ?? 0;
    const classNames = [
      "calendar-day",
      dateKey === todayKey ? "calendar-day--today" : "",
      dateKey === calendarSelectedDate ? "calendar-day--selected" : "",
    ].filter(Boolean).join(" ");
    const taskDescription = incompleteCount > 0 ? `, ${pluralizeTasks(incompleteCount)} niewykonane` : "";
    const renewalDescription = renewalCount > 0
      ? `, ${pluralizePolicies(renewalCount)} kończy okres ubezpieczenia`
      : "";
    days.push(`
      <button
        class="${classNames}"
        type="button"
        role="gridcell"
        data-calendar-date="${dateKey}"
        aria-label="${escapeHtml(formatCalendarDateLabel(dateKey))}${taskDescription}${renewalDescription}"
        aria-selected="${dateKey === calendarSelectedDate}"
      >
        <span>${date.getDate()}</span>
        ${incompleteCount > 0 ? `<strong class="calendar-day__tasks">${incompleteCount > 99 ? "99+" : incompleteCount}</strong>` : ""}
        ${renewalCount > 0 ? `<strong class="calendar-day__renewals" title="Polisy kończące okres ubezpieczenia">${renewalCount > 99 ? "99+" : renewalCount}</strong>` : ""}
      </button>
    `);
  }
  elements.calendarDays.innerHTML = days.join("");
}

function renderCalendarTasks() {
  const previousScrollTop = elements.calendarTaskList.scrollTop;
  const tasksForDate = getCalendarTasksForDate(calendarSelectedDate)
    .sort((first, second) => Number(first.completed) - Number(second.completed)
      || Number(first.createdAt) - Number(second.createdAt));
  const incompleteCount = tasksForDate.filter((task) => !task.completed).length;

  elements.calendarSelectedDate.textContent = formatCalendarDateLabel(calendarSelectedDate);
  elements.calendarTaskList.innerHTML = tasksForDate.map((task) => `
    <div class="calendar-task-row${task.completed ? " calendar-task-row--completed" : ""}" data-calendar-task-id="${escapeHtml(task.id)}">
      <span class="calendar-task-text">${escapeHtml(task.text)}</span>
      <span class="calendar-task-actions">
        <button
          class="calendar-task-delete"
          type="button"
          data-calendar-action="delete"
          data-calendar-task-id="${escapeHtml(task.id)}"
          aria-label="Usuń zadanie: ${escapeHtml(task.text)}"
          title="Usuń zadanie"
        >×</button>
        <button
          class="calendar-task-check"
          type="button"
          data-calendar-action="toggle"
          data-calendar-task-id="${escapeHtml(task.id)}"
          aria-label="${task.completed ? "Oznacz jako niewykonane" : "Oznacz jako wykonane"}: ${escapeHtml(task.text)}"
          aria-pressed="${task.completed}"
          title="${task.completed ? "Cofnij wykonanie" : "Oznacz jako wykonane"}"
        >✓</button>
      </span>
    </div>
  `).join("");
  elements.calendarTaskList.scrollTop = previousScrollTop;
  elements.calendarTasksEmpty.hidden = tasksForDate.length > 0;
  elements.calendarSummary.textContent = incompleteCount > 0
    ? `${pluralizeTasks(incompleteCount)} niewykonane w wybranym dniu`
    : "Brak niewykonanych zadań w wybranym dniu";
  setCalendarSaving(calendarSaving);
}

function renderCalendarRenewals() {
  const previousScrollTop = elements.calendarRenewalList.scrollTop;
  closeCalendarRenewalMenu();
  const renewals = getCalendarRenewalsForDate(calendarSelectedDate);
  const hiddenCount = getHiddenCalendarRenewalCountForDate(calendarSelectedDate);
  elements.calendarRenewalsDate.textContent = formatCalendarDateLabel(calendarSelectedDate);
  elements.calendarRenewalsEmpty.hidden = renewals.length > 0;
  elements.calendarRenewalsHiddenRestore.hidden = hiddenCount === 0;
  if (hiddenCount > 0) {
    elements.calendarRenewalsHiddenRestore.textContent = `Ukryte w tym dniu: ${hiddenCount} - przywróć`;
  }
  if (renewals.length === 0) {
    elements.calendarRenewalsTitle.textContent = "Brak polis do wznowienia";
    elements.calendarRenewalList.innerHTML = "";
    return;
  }

  elements.calendarRenewalsTitle.textContent = renewals.length === 1
    ? "1 polisa kończy okres ubezpieczenia"
    : `${pluralizePolicies(renewals.length)} kończą okres ubezpieczenia`;
  elements.calendarRenewalList.innerHTML = renewals.map((policy) => {
    const status = getCalendarRenewalStatus(policy);
    const policyNumber = policy.policyNumber || "";
    return `
      <button
        class="calendar-renewal-row"
        type="button"
        data-calendar-renewal-policy-id="${escapeHtml(policy.id)}"
        aria-haspopup="menu"
        aria-label="Opcje polisy ${escapeHtml(policyNumber || "bez numeru")} klienta ${escapeHtml(policy.clientName || "bez nazwy")}"
      >
        <div class="calendar-renewal-row__client">
          <strong>${escapeHtml(policy.clientName || "Bez nazwy klienta")}</strong>
          <small>${escapeHtml(policy.registration || "Brak numeru rejestracyjnego / rodzaju")}</small>
        </div>
        <div class="calendar-renewal-row__policy">
          <span>${escapeHtml(policy.insurer || "Brak towarzystwa")}</span>
          <small>Polisa ${escapeHtml(policy.policyNumber || "bez numeru")}</small>
        </div>
        <span class="calendar-renewal-row__premium">${escapeHtml(formatPremium(policy.premium))}</span>
        <strong class="calendar-renewal-status calendar-renewal-status--${status.modifier}">${status.label}</strong>
      </button>
    `;
  }).join("");
  elements.calendarRenewalList.scrollTop = previousScrollTop;
}

function renderCalendar() {
  renderCalendarDays();
  renderCalendarTasks();
  renderCalendarRenewals();
  updateTodayTaskIndicator();
}

let calendarRenewalMenuPolicyId = null;
let calendarRenewedPolicyId = null;

function closeCalendarRenewalMenu() {
  calendarRenewalMenuPolicyId = null;
  if (!elements.calendarRenewalMenu.hidden) elements.calendarRenewalMenu.hidden = true;
}



function openCalendarRenewalMenu(row, policyId) {
  const policy = policies.find((item) => item.id === policyId);
  if (!policy) return;
  calendarRenewalMenuPolicyId = policyId;
  const menu = elements.calendarRenewalMenu;
  menu.querySelector('[data-renewal-menu-action="open"]').disabled = !policy.policyNumber;
  menu.hidden = false;
  const rowRect = row.getBoundingClientRect();
  const menuRect = menu.getBoundingClientRect();
  const left = Math.min(
    Math.max(12, rowRect.right - menuRect.width),
    Math.max(12, globalThis.innerWidth - menuRect.width - 12),
  );
  const fitsBelow = rowRect.bottom + 6 + menuRect.height <= globalThis.innerHeight - 12;
  const top = fitsBelow ? rowRect.bottom + 6 : Math.max(12, rowRect.top - menuRect.height - 6);
  menu.style.left = `${Math.round(left)}px`;
  menu.style.top = `${Math.round(top)}px`;
}

function formatCalendarPolicyDate(value) {
  const date = parseLocalDate(value);
  return date ? SHORT_DATE_FORMAT.format(date) : "";
}

function closeCalendarRenewedDialog() {
  calendarRenewedPolicyId = null;
  if (elements.calendarRenewedDialog.open) elements.calendarRenewedDialog.close();
}

function openCalendarRenewedDialog(policyId) {
  const policy = policies.find((item) => item.id === policyId);
  if (!policy) return;
  calendarRenewedPolicyId = policyId;
  elements.calendarRenewedPolicyLabel.textContent = policy.clientName || "Bez nazwy klienta";
  const endDate = formatCalendarPolicyDate(policy.validUntil);
  elements.calendarRenewedPolicyMeta.textContent = [
    policy.policyNumber ? `Polisa ${policy.policyNumber}` : "Polisa bez numeru",
    policy.registration || "",
    endDate ? `koniec ${endDate}` : "",
  ].filter(Boolean).join(" - ");
  elements.calendarRenewedSearch.value = policy.registration || policy.clientName || "";
  renderCalendarRenewedResults();
  elements.calendarRenewedDialog.showModal();
  requestAnimationFrame(() => {
    elements.calendarRenewedSearch.focus();
    elements.calendarRenewedSearch.select();
  });
}

function renderCalendarRenewedResults() {
  const previousPolicy = policies.find((item) => item.id === calendarRenewedPolicyId);
  const query = String(elements.calendarRenewedSearch.value ?? "").trim().toLowerCase();
  let matches = [];
  if (previousPolicy && query.length >= 2) {
    matches = policies
      .filter((policy) => policy.id !== previousPolicy.id
        && [policy.policyNumber, policy.clientName, policy.registration]
          .some((value) => String(value ?? "").toLowerCase().includes(query)))
      .sort((first, second) => compareAlphabetically(String(second.validFrom ?? ""), String(first.validFrom ?? ""))
        || compareAlphabetically(first.policyNumber, second.policyNumber))
      .slice(0, 8);
  }
  elements.calendarRenewedEmpty.hidden = !(query.length >= 2 && matches.length === 0);
  elements.calendarRenewedResults.innerHTML = matches.map((policy) => {
    const period = [formatCalendarPolicyDate(policy.validFrom), formatCalendarPolicyDate(policy.validUntil)]
      .filter(Boolean).join(" do ");
    const detailParts = [
      policy.clientName || "Bez nazwy klienta",
      policy.registration || "",
      period,
    ].filter(Boolean);
    return `
      <button class="calendar-renewed-result" type="button" data-calendar-renewed-successor-id="${escapeHtml(policy.id)}">
        <strong>${escapeHtml(policy.policyNumber || "Bez numeru")}${policy.insurer ? ` - ${escapeHtml(policy.insurer)}` : ""}</strong>
        <small>${escapeHtml(detailParts.join(" - "))}</small>
      </button>
    `;
  }).join("");
}

function selectCalendarDate(dateKey) {
  const date = parseLocalDate(dateKey);
  if (!date) return;
  calendarSelectedDate = formatDateForInput(date);
  calendarViewDate = new Date(date.getFullYear(), date.getMonth(), 1, 12);
  elements.calendarTaskText.value = "";
  elements.calendarTaskList.scrollTop = 0;
  elements.calendarRenewalList.scrollTop = 0;
  renderCalendar();
}

function openCalendarDialog() {
  const today = new Date();
  calendarSelectedDate = formatDateForInput(today);
  calendarViewDate = new Date(today.getFullYear(), today.getMonth(), 1, 12);
  elements.calendarTaskText.value = "";
  elements.calendarTaskList.scrollTop = 0;
  elements.calendarRenewalList.scrollTop = 0;
  renderCalendar();
  elements.calendarDialog.showModal();
  requestAnimationFrame(() => {
    elements.calendarDays.querySelector(`[data-calendar-date="${calendarSelectedDate}"]`)?.focus();
  });
}

function closeCalendarDialog() {
  if (calendarSaving) return;
  if (elements.calendarDialog.open) elements.calendarDialog.close();
}

function changeCalendarMonth(offset) {
  const current = calendarViewDate || new Date();
  calendarViewDate = new Date(current.getFullYear(), current.getMonth() + offset, 1, 12);
  renderCalendarDays();
}

function cloneCalendarTasks(taskRecords = calendarTasks) {
  return taskRecords.map((task) => ({ ...task }));
}

async function persistCalendarTaskMutation(applyMutation, successMessage) {
  if (calendarSaving) return false;
  setCalendarSaving(true);
  try {
    if (!(await ensureWritableDataFile({ deferFreshnessCheck: true }))) return false;
    let rollbackTasks = cloneCalendarTasks();
    if (applyMutation() === false) return false;
    renderCalendar();

    const saved = await persistPolicies({
      reapplyAfterConflict: async () => {
        rollbackTasks = cloneCalendarTasks();
        const reapplied = applyMutation();
        renderCalendar();
        return reapplied;
      },
    });
    if (!saved) {
      calendarTasks = rollbackTasks;
      markPoliciesRolledBack();
      renderCalendar();
      return false;
    }
    showToast(successMessage);
    return true;
  } finally {
    setCalendarSaving(false);
    renderCalendar();
  }
}

async function addCalendarTasks(event) {
  event.preventDefault();
  const text = String(elements.calendarTaskText.value ?? "").trim();
  if (!text) {
    showToast("Wpisz zadanie", "error");
    elements.calendarTaskText.focus();
    return;
  }
  if (text.length > MAX_CALENDAR_TASK_LENGTH) {
    showToast(`Zadanie może mieć maksymalnie ${MAX_CALENDAR_TASK_LENGTH} znaków`, "error");
    return;
  }
  const existingCount = getCalendarTasksForDate(calendarSelectedDate).length;
  if (existingCount >= MAX_CALENDAR_TASKS_PER_DAY) {
    showToast(`Na jeden dzień można zapisać maksymalnie ${MAX_CALENDAR_TASKS_PER_DAY} zadań`, "error");
    return;
  }

  const createdAt = Date.now();
  const newTask = {
    id: globalThis.crypto?.randomUUID?.() ?? `${createdAt}-${Math.random()}`,
    date: calendarSelectedDate,
    text,
    completed: false,
    createdAt,
    updatedAt: createdAt,
  };
  const saved = await persistCalendarTaskMutation(() => {
    if (!calendarTasks.some((task) => task.id === newTask.id)) calendarTasks.push({ ...newTask });
    return true;
  }, "Dodano zadanie do kalendarza");
  if (saved) {
    elements.calendarTaskText.value = "";
    elements.calendarTaskText.focus();
    requestAnimationFrame(() => {
      elements.calendarTaskList.scrollTop = elements.calendarTaskList.scrollHeight;
    });
  }
}

async function toggleCalendarTask(taskId) {
  const currentTask = calendarTasks.find((task) => task.id === taskId);
  if (!currentTask) return;
  const completed = !currentTask.completed;
  const updatedAt = Date.now();
  await persistCalendarTaskMutation(() => {
    const task = calendarTasks.find((item) => item.id === taskId);
    if (!task) return false;
    task.completed = completed;
    task.updatedAt = updatedAt;
    return true;
  }, completed ? "Zadanie oznaczono jako wykonane" : "Zadanie oznaczono jako niewykonane");
}

let confirmDeleteDialogResolve = null;

function finishDeleteConfirmation(confirmed) {
  const resolve = confirmDeleteDialogResolve;
  confirmDeleteDialogResolve = null;
  resolve?.(confirmed);
}




function requestDeleteConfirmation({ title, message, confirmLabel = "Usuń" }) {
  const dialog = elements.confirmDeleteDialog;
  if (typeof dialog?.showModal !== "function") {
    return Promise.resolve(typeof globalThis.confirm !== "function" || globalThis.confirm(message));
  }
  finishDeleteConfirmation(false);
  if (dialog.open) dialog.close();
  elements.confirmDeleteTitle.textContent = title;
  elements.confirmDeleteMessage.textContent = message;
  elements.acceptConfirmDelete.textContent = confirmLabel;
  return new Promise((resolve) => {
    confirmDeleteDialogResolve = resolve;
    dialog.showModal();
    requestAnimationFrame(() => elements.cancelConfirmDelete.focus());
  });
}

let portfolioPathRepairDialogResolve = null;

function finishPortfolioPathRepairConfirmation(confirmed) {
  const resolve = portfolioPathRepairDialogResolve;
  portfolioPathRepairDialogResolve = null;
  resolve?.(confirmed);
}

function requestPortfolioPathRepairConfirmation(insurerName) {
  const label = String(insurerName || "towarzystwa").trim();
  const message = `Poprawienie ścieżki dotyczy drogi od strony głównej portalu ${label} do listy (portfela) polis. Nie zmienia trasy kalkulacji ani drogi do podglądu pojedynczej polisy. W otwartym oknie przejdź do listy polis i dokończ import.`;
  const dialog = elements.portfolioPathRepairDialog;
  if (typeof dialog?.showModal !== "function") {
    return Promise.resolve(typeof globalThis.confirm !== "function" || globalThis.confirm(message));
  }
  finishPortfolioPathRepairConfirmation(false);
  if (dialog.open) dialog.close();
  elements.portfolioPathRepairTitle.textContent = `Poprawić ścieżkę ${label}?`;
  elements.portfolioPathRepairMessage.textContent = message;
  return new Promise((resolve) => {
    portfolioPathRepairDialogResolve = resolve;
    dialog.showModal();
    requestAnimationFrame(() => elements.cancelPortfolioPathRepair.focus());
  });
}

async function runConfirmedPortfolioPathRepair(insurerName, repair) {
  if (!(await requestPortfolioPathRepairConfirmation(insurerName))) return;
  await repair();
}

async function deleteCalendarTask(taskId) {
  const task = calendarTasks.find((item) => item.id === taskId);
  if (!task) return;
  const confirmed = await requestDeleteConfirmation({
    title: "Usunięcie zadania",
    message: `Usunąć zadanie „${task.text}”?`,
    confirmLabel: "Usuń zadanie",
  });
  if (!confirmed) return;
  await persistCalendarTaskMutation(() => {
    calendarTasks = calendarTasks.filter((item) => item.id !== taskId);
    return true;
  }, "Usunięto zadanie z kalendarza");
}

function getUsageGuideDescription(button) {
  const action = button.dataset.action;
  if (action && USAGE_GUIDE_ACTION_DESCRIPTIONS[action]) {
    return USAGE_GUIDE_ACTION_DESCRIPTIONS[action];
  }
  if (button.id && USAGE_GUIDE_ID_DESCRIPTIONS[button.id]) {
    return USAGE_GUIDE_ID_DESCRIPTIONS[button.id];
  }
  if (button.classList.contains("policy-import-info-button")) {
    return "Lista obsługiwanych polis PDF";
  }
  if (button.classList.contains("inline-save")) return "Zapisanie zmian wpisu";
  if (button.dataset.pendingAttachmentId) return "Usuwanie wybranego załącznika";
  if (button.dataset.calendarDate) return "Wybór dnia w kalendarzu";
  if (button.dataset.calendarAction === "toggle") return "Oznaczenie zadania jako wykonane";
  if (button.dataset.calendarAction === "delete") return "Usuwanie zadania z kalendarza";
  if (button.dataset.calendarRenewalPolicyId) return "Menu polisy do wznowienia";
  if (button.dataset.renewalMenuAction === "open") return "Przejście do polisy";
  if (button.dataset.renewalMenuAction === "renewed") return "Oznaczenie polisy jako wznowionej";
  if (button.dataset.renewalMenuAction === "hide") return "Ukrycie polisy w kalendarzu";
  if (button.dataset.calendarRenewedSuccessorId) return "Wskazanie nowej polisy wznowienia";
  if (button.dataset.deletedAction === "restore") return "Przywrócenie usuniętego wpisu";
  if (button.dataset.deletedAction === "delete-permanently") return "Trwałe usunięcie wpisu";
  if (button.dataset.page) return `Przejście do strony ${button.dataset.page}`;
  if ("pageJump" in button.dataset) return "Wpisanie numeru strony";
  if ("pageJumpConfirm" in button.dataset) return "Przejście do podanej strony";
  if ("pageJumpCancel" in button.dataset) return "Anulowanie wyboru strony";
  if (button.dataset.idleRpgStat) return "Rozwój cechy gracza";
  if (button.dataset.idleRpgUpgrade) return "Zakup ulepszenia";

  const description = String(
    button.getAttribute("aria-label")
      || button.getAttribute("title")
      || button.textContent
      || "Przycisk",
  ).replace(/\s+/g, " ").trim();
  return description.length > 64 ? `${description.slice(0, 61).trim()}…` : description;
}

function isUsageGuideTargetVisible(target) {
  if (target === elements.usageGuideButton || target.closest("#usageGuideOverlay")) return false;
  if (target.closest("[hidden]") || target.getAttribute("aria-hidden") === "true") return false;
  const dialog = target.closest("dialog");
  if (dialog && !dialog.open) return false;
  const style = globalThis.getComputedStyle(target);
  if (style.display === "none" || style.visibility === "hidden" || Number(style.opacity) === 0) return false;
  const rect = target.getBoundingClientRect();
  return rect.width > 1
    && rect.height > 1
    && rect.right > 0
    && rect.bottom > 0
    && rect.left < globalThis.innerWidth
    && rect.top < globalThis.innerHeight;
}

function getUsageGuideOverlapArea(first, second, padding = 0) {
  const width = Math.max(
    0,
    Math.min(first.right + padding, second.right + padding)
      - Math.max(first.left - padding, second.left - padding),
  );
  const height = Math.max(
    0,
    Math.min(first.bottom + padding, second.bottom + padding)
      - Math.max(first.top - padding, second.top - padding),
  );
  return width * height;
}

function getUsageGuideLabelPosition(targetRect, labelWidth, labelHeight, occupiedRects, targetRects) {
  const viewportWidth = globalThis.innerWidth;
  const viewportHeight = globalThis.innerHeight;
  const margin = 8;
  const gap = 34;
  const centerX = targetRect.left + targetRect.width / 2;
  const centerY = targetRect.top + targetRect.height / 2;
  const horizontalStep = Math.max(labelWidth * 0.78, 88) + USAGE_GUIDE_LABEL_CLEARANCE_PX;
  const verticalStep = labelHeight + USAGE_GUIDE_LABEL_CLEARANCE_PX;
  const horizontalShifts = [0, -horizontalStep, horizontalStep, -2 * horizontalStep, 2 * horizontalStep];
  const verticalShifts = [0, -verticalStep, verticalStep, -2 * verticalStep, 2 * verticalStep, -3 * verticalStep, 3 * verticalStep];
  const preferredSides = centerX > viewportWidth / 2
    ? ["left", "top", "bottom", "right"]
    : ["right", "top", "bottom", "left"];
  const candidates = [];
  const statusRect = {
    left: viewportWidth / 2 - 120,
    top: 6,
    right: viewportWidth / 2 + 120,
    bottom: 64,
  };
  const getObstructionPenalty = (rect) => {
    let penalty = 0;
    occupiedRects.forEach((occupied) => {
      penalty += getUsageGuideOverlapArea(
        rect,
        occupied,
        USAGE_GUIDE_LABEL_CLEARANCE_PX / 2,
      ) * 180;
    });
    targetRects.forEach((target) => {
      penalty += getUsageGuideOverlapArea(rect, target, 5) * 18;
    });
    penalty += getUsageGuideOverlapArea(rect, statusRect, 4) * 100;
    return penalty;
  };

  preferredSides.forEach((side, sideIndex) => {
    const shifts = side === "left" || side === "right" ? verticalShifts : horizontalShifts;
    shifts.forEach((shift, shiftIndex) => {
      let left = centerX - labelWidth / 2;
      let top = centerY - labelHeight / 2;
      if (side === "left") left = targetRect.left - gap - labelWidth;
      if (side === "right") left = targetRect.right + gap;
      if (side === "top") top = targetRect.top - gap - labelHeight;
      if (side === "bottom") top = targetRect.bottom + gap;
      if (side === "left" || side === "right") top += shift;
      else left += shift;

      const unclampedLeft = left;
      const unclampedTop = top;
      left = Math.min(Math.max(margin, left), Math.max(margin, viewportWidth - labelWidth - margin));
      top = Math.min(Math.max(margin, top), Math.max(margin, viewportHeight - labelHeight - margin));
      const rect = {
        left,
        top,
        right: left + labelWidth,
        bottom: top + labelHeight,
        width: labelWidth,
        height: labelHeight,
      };
      let score = sideIndex * 8 + shiftIndex * 2;
      score += (Math.abs(left - unclampedLeft) + Math.abs(top - unclampedTop)) * 4;
      score += getObstructionPenalty(rect);
      candidates.push({ rect, score });
    });
  });

  const edgeLaneTop = 72;
  const verticalLaneStep = labelHeight + USAGE_GUIDE_LABEL_CLEARANCE_PX;
  const horizontalLaneStep = labelWidth + USAGE_GUIDE_LABEL_CLEARANCE_PX;
  for (
    let top = edgeLaneTop;
    top <= viewportHeight - labelHeight - margin;
    top += verticalLaneStep
  ) {
    [margin, viewportWidth - labelWidth - margin].forEach((left) => {
      if (left < margin) return;
      const rect = {
        left,
        top,
        right: left + labelWidth,
        bottom: top + labelHeight,
        width: labelWidth,
        height: labelHeight,
      };
      const distance = Math.hypot(
        left + labelWidth / 2 - centerX,
        top + labelHeight / 2 - centerY,
      );
      candidates.push({
        rect,
        score: 90 + distance * 0.08 + getObstructionPenalty(rect),
      });
    });
  }
  for (
    let left = margin;
    left <= viewportWidth - labelWidth - margin;
    left += horizontalLaneStep
  ) {
    [edgeLaneTop, viewportHeight - labelHeight - margin].forEach((top) => {
      if (top < edgeLaneTop) return;
      const rect = {
        left,
        top,
        right: left + labelWidth,
        bottom: top + labelHeight,
        width: labelWidth,
        height: labelHeight,
      };
      const distance = Math.hypot(
        left + labelWidth / 2 - centerX,
        top + labelHeight / 2 - centerY,
      );
      candidates.push({
        rect,
        score: 90 + distance * 0.08 + getObstructionPenalty(rect),
      });
    });
  }

  const hasRequiredClearance = ({ rect }) => occupiedRects.every(
    (occupied) => getUsageGuideOverlapArea(
      rect,
      occupied,
      USAGE_GUIDE_LABEL_CLEARANCE_PX / 2,
    ) === 0,
  );
  const clearCandidates = candidates.filter(hasRequiredClearance);
  const rankedCandidates = clearCandidates.length > 0 ? clearCandidates : candidates;
  rankedCandidates.sort((first, second) => first.score - second.score);
  return rankedCandidates[0]?.rect ?? {
    left: margin,
    top: margin,
    right: margin + labelWidth,
    bottom: margin + labelHeight,
    width: labelWidth,
    height: labelHeight,
  };
}

function getUsageGuideRectEdge(rect, towardX, towardY) {
  const centerX = rect.left + rect.width / 2;
  const centerY = rect.top + rect.height / 2;
  const dx = towardX - centerX;
  const dy = towardY - centerY;
  const scale = 1 / Math.max(
    Math.abs(dx) / Math.max(rect.width / 2, 1),
    Math.abs(dy) / Math.max(rect.height / 2, 1),
    1,
  );
  return { x: centerX + dx * scale, y: centerY + dy * scale };
}

function appendUsageGuideArrow(labelRect, targetRect, index) {
  const svgNamespace = "http://www.w3.org/2000/svg";
  const labelCenter = {
    x: labelRect.left + labelRect.width / 2,
    y: labelRect.top + labelRect.height / 2,
  };
  const targetCenter = {
    x: targetRect.left + targetRect.width / 2,
    y: targetRect.top + targetRect.height / 2,
  };
  const start = getUsageGuideRectEdge(labelRect, targetCenter.x, targetCenter.y);
  const end = getUsageGuideRectEdge(targetRect, labelCenter.x, labelCenter.y);
  const dx = end.x - start.x;
  const dy = end.y - start.y;
  const distance = Math.max(Math.hypot(dx, dy), 1);
  const bend = Math.min(24, distance * 0.14) * (index % 2 === 0 ? 1 : -1);
  const controlX = (start.x + end.x) / 2 - (dy / distance) * bend;
  const controlY = (start.y + end.y) / 2 + (dx / distance) * bend;
  const path = document.createElementNS(svgNamespace, "path");
  path.setAttribute("class", "usage-guide-arrow");
  path.setAttribute("d", `M ${start.x.toFixed(1)} ${start.y.toFixed(1)} Q ${controlX.toFixed(1)} ${controlY.toFixed(1)} ${end.x.toFixed(1)} ${end.y.toFixed(1)}`);
  path.setAttribute("marker-end", "url(#usageGuideArrowhead)");
  elements.usageGuideArrows.append(path);
}

function renderUsageGuide() {
  usageGuideRefreshFrame = 0;
  if (!usageGuideActive || elements.usageGuideOverlay.hidden) return;
  const svgNamespace = "http://www.w3.org/2000/svg";
  const targets = USAGE_GUIDE_TARGETS.flatMap((definition) => {
    const selectors = definition.selectors || [definition.selector];
    const matchedTargets = selectors.flatMap((selector) => {
      const target = [...document.querySelectorAll(selector)]
        .find(isUsageGuideTargetVisible);
      return target ? [target] : [];
    });
    if (matchedTargets.length === 0) return [];
    const matchedRects = matchedTargets.map((target) => target.getBoundingClientRect());
    const rect = {
      left: Math.min(...matchedRects.map(({ left }) => left)),
      top: Math.min(...matchedRects.map(({ top }) => top)),
      right: Math.max(...matchedRects.map(({ right }) => right)),
      bottom: Math.max(...matchedRects.map(({ bottom }) => bottom)),
    };
    rect.width = rect.right - rect.left;
    rect.height = rect.bottom - rect.top;
    return [{
      rect,
      description: definition.description || getUsageGuideDescription(matchedTargets[0]),
      highlightClass: definition.highlightClass || "",
      highlightPadding: Number.isFinite(definition.highlightPadding)
        ? definition.highlightPadding
        : 3,
    }];
  });
  const targetRects = targets.map(({ rect }) => rect);
  const occupiedRects = [];

  elements.usageGuideHighlights.replaceChildren();
  elements.usageGuideLabels.replaceChildren();
  elements.usageGuideArrows.replaceChildren();
  elements.usageGuideArrows.setAttribute("viewBox", `0 0 ${globalThis.innerWidth} ${globalThis.innerHeight}`);

  const definitions = document.createElementNS(svgNamespace, "defs");
  const marker = document.createElementNS(svgNamespace, "marker");
  marker.setAttribute("id", "usageGuideArrowhead");
  marker.setAttribute("viewBox", "0 0 8 8");
  marker.setAttribute("refX", "7");
  marker.setAttribute("refY", "4");
  marker.setAttribute("markerWidth", "7");
  marker.setAttribute("markerHeight", "7");
  marker.setAttribute("orient", "auto-start-reverse");
  const arrowhead = document.createElementNS(svgNamespace, "path");
  arrowhead.setAttribute("d", "M 0 0 L 8 4 L 0 8 Z");
  arrowhead.setAttribute("fill", "#f4bd32");
  marker.append(arrowhead);
  definitions.append(marker);
  elements.usageGuideArrows.append(definitions);

  targets.forEach(({
    rect,
    description,
    highlightClass,
    highlightPadding,
  }, index) => {
    const highlightLeft = Math.max(0, rect.left - highlightPadding);
    const highlightTop = Math.max(0, rect.top - highlightPadding);
    const highlight = document.createElement("span");
    highlight.className = `usage-guide-highlight${highlightClass ? ` ${highlightClass}` : ""}`;
    highlight.style.left = `${highlightLeft}px`;
    highlight.style.top = `${highlightTop}px`;
    highlight.style.width = `${Math.min(globalThis.innerWidth, rect.right + highlightPadding) - highlightLeft}px`;
    highlight.style.height = `${Math.min(globalThis.innerHeight, rect.bottom + highlightPadding) - highlightTop}px`;
    elements.usageGuideHighlights.append(highlight);

    const label = document.createElement("span");
    label.className = "usage-guide-label";
    label.textContent = description;
    label.style.visibility = "hidden";
    elements.usageGuideLabels.append(label);
    const measured = label.getBoundingClientRect();
    const labelPosition = getUsageGuideLabelPosition(
      rect,
      measured.width,
      measured.height,
      occupiedRects,
      targetRects,
    );
    label.style.left = `${labelPosition.left}px`;
    label.style.top = `${labelPosition.top}px`;
    label.style.visibility = "visible";
    occupiedRects.push(labelPosition);
    appendUsageGuideArrow(labelPosition, rect, index);
  });
}

function scheduleUsageGuideRender() {
  if (!usageGuideActive || usageGuideRefreshFrame) return;
  usageGuideRefreshFrame = globalThis.requestAnimationFrame(renderUsageGuide);
}

function hideUsageGuide() {
  globalThis.clearTimeout(usageGuideFadeTimer);
  globalThis.clearTimeout(usageGuideEndTimer);
  if (usageGuideRefreshFrame) globalThis.cancelAnimationFrame(usageGuideRefreshFrame);
  usageGuideFadeTimer = null;
  usageGuideEndTimer = null;
  usageGuideRefreshFrame = 0;
  usageGuideActive = false;
  elements.usageGuideButton.setAttribute("aria-pressed", "false");
  elements.usageGuideOverlay.hidden = true;
  elements.usageGuideOverlay.classList.remove("usage-guide-overlay--leaving");
  elements.usageGuideArrows.replaceChildren();
  elements.usageGuideHighlights.replaceChildren();
  elements.usageGuideLabels.replaceChildren();
}

function showUsageGuide() {
  globalThis.clearTimeout(usageGuideFadeTimer);
  globalThis.clearTimeout(usageGuideEndTimer);
  if (usageGuideRefreshFrame) globalThis.cancelAnimationFrame(usageGuideRefreshFrame);
  usageGuideRefreshFrame = 0;
  usageGuideActive = true;
  elements.usageGuideButton.setAttribute("aria-pressed", "true");
  elements.usageGuideOverlay.hidden = false;
  elements.usageGuideOverlay.classList.remove("usage-guide-overlay--leaving");

  const progress = elements.usageGuideOverlay.querySelector(".usage-guide-status i");
  progress.style.animation = "none";
  void progress.offsetWidth;
  progress.style.animation = "";
  renderUsageGuide();

  usageGuideFadeTimer = globalThis.setTimeout(() => {
    elements.usageGuideOverlay.classList.add("usage-guide-overlay--leaving");
  }, USAGE_GUIDE_DURATION_MS - USAGE_GUIDE_FADE_MS);
  usageGuideEndTimer = globalThis.setTimeout(hideUsageGuide, USAGE_GUIDE_DURATION_MS);
}

function toggleUsageGuide() {
  if (usageGuideActive) hideUsageGuide();
  else showUsageGuide();
}

function getPageScrollMetrics() {
  const root = document.documentElement;
  const body = document.body;
  const viewportHeight = globalThis.innerHeight || root.clientHeight;
  const scrollHeight = Math.max(
    root.scrollHeight,
    root.offsetHeight,
    body?.scrollHeight || 0,
    body?.offsetHeight || 0,
  );
  const scrollTop = Math.max(0, globalThis.scrollY || root.scrollTop || body?.scrollTop || 0);
  return {
    maxScrollTop: Math.max(0, scrollHeight - viewportHeight),
    scrollTop,
  };
}

function updatePageScrollControls() {
  pageScrollControlsFrame = 0;
  const { maxScrollTop, scrollTop } = getPageScrollMetrics();
  const hasVerticalScroll = maxScrollTop > 2;
  elements.pageScrollControls.hidden = !hasVerticalScroll;
  if (!hasVerticalScroll) return;

  elements.scrollPageTop.disabled = scrollTop <= 2;
  elements.scrollPageBottom.disabled = scrollTop >= maxScrollTop - 2;
}

function schedulePageScrollControlsUpdate() {
  if (pageScrollControlsFrame) return;
  pageScrollControlsFrame = globalThis.requestAnimationFrame(updatePageScrollControls);
}

function scrollPageTo(edge) {
  const { maxScrollTop } = getPageScrollMetrics();
  const reduceMotion = globalThis.matchMedia?.("(prefers-reduced-motion: reduce)").matches;
  globalThis.scrollTo({
    top: edge === "top" ? 0 : maxScrollTop,
    behavior: reduceMotion ? "auto" : "smooth",
  });
}

function normalizeCalculatorAccounts(accounts) {
  const source = accounts && typeof accounts === "object" && !Array.isArray(accounts) ? accounts : {};
  const warta = source.warta && typeof source.warta === "object" && !Array.isArray(source.warta)
    ? source.warta
    : {};
  const generali = source.generali && typeof source.generali === "object" && !Array.isArray(source.generali)
    ? source.generali
    : {};
  const mtu = source.mtu && typeof source.mtu === "object" && !Array.isArray(source.mtu)
    ? source.mtu
    : {};
  const hestia = source.hestia && typeof source.hestia === "object" && !Array.isArray(source.hestia)
    ? source.hestia
    : {};
  const trasti = source.trasti && typeof source.trasti === "object" && !Array.isArray(source.trasti)
    ? source.trasti
    : {};
  const wiener = source.wiener && typeof source.wiener === "object" && !Array.isArray(source.wiener)
    ? source.wiener
    : {};
  const compensa = source.compensa && typeof source.compensa === "object" && !Array.isArray(source.compensa)
    ? source.compensa
    : {};
  const allianz = source.allianz && typeof source.allianz === "object" && !Array.isArray(source.allianz)
    ? source.allianz
    : {};
  const insly = source.insly && typeof source.insly === "object" && !Array.isArray(source.insly)
    ? source.insly
    : {};
  const pzu = source.pzu && typeof source.pzu === "object" && !Array.isArray(source.pzu)
    ? source.pzu
    : {};
  return {
    warta: {
      username: String(warta.username ?? "").trim().slice(0, MAX_CALCULATOR_USERNAME_LENGTH),
    },
    generali: {
      username: String(generali.username ?? "").trim().slice(0, MAX_CALCULATOR_USERNAME_LENGTH),
    },
    mtu: {
      username: String(mtu.username ?? "").trim().slice(0, MAX_CALCULATOR_USERNAME_LENGTH),
    },
    hestia: {
      username: String(hestia.username ?? "").trim().slice(0, MAX_CALCULATOR_USERNAME_LENGTH),
    },
    trasti: {
      username: String(trasti.username ?? "").trim().slice(0, MAX_CALCULATOR_USERNAME_LENGTH),
    },
    wiener: {
      username: String(wiener.username ?? "").trim().slice(0, MAX_CALCULATOR_USERNAME_LENGTH),
    },
    compensa: {
      username: String(compensa.username ?? "").trim().slice(0, MAX_CALCULATOR_USERNAME_LENGTH),
    },
    allianz: {
      username: String(allianz.username ?? "").trim().slice(0, MAX_CALCULATOR_USERNAME_LENGTH),
    },
    insly: {
      username: String(insly.username ?? "").trim().slice(0, MAX_CALCULATOR_USERNAME_LENGTH),
    },
    pzu: {
      username: String(pzu.username ?? "").trim().slice(0, MAX_CALCULATOR_USERNAME_LENGTH),
    },
  };
}

function normalizeAgencyPrintDetails(details) {
  const normalizeSingleLine = (value, limit) => String(value ?? "")
    .replace(/\s+/g, " ")
    .trim()
    .slice(0, limit);
  const address = String(details?.address ?? "")
    .replace(/\r\n?/g, "\n")
    .split("\n")
    .map((line) => line.replace(/\s+/g, " ").trim())
    .filter(Boolean)
    .join("\n")
    .slice(0, AGENCY_PRINT_DETAILS_LIMITS.address);
  return {
    name: normalizeSingleLine(details?.name, AGENCY_PRINT_DETAILS_LIMITS.name),
    address,
    email: normalizeSingleLine(details?.email, AGENCY_PRINT_DETAILS_LIMITS.email),
    phone: normalizeSingleLine(details?.phone, AGENCY_PRINT_DETAILS_LIMITS.phone),
  };
}

function isAgencyPrintEmailValid(email) {
  return /^[^\s@]+@[^\s@]+\.[^\s@]+$/u.test(String(email || ""));
}

function isAgencyPrintDetailsComplete(details = uiSettings?.agencyPrintDetails) {
  const normalized = normalizeAgencyPrintDetails(details);
  return Boolean(
    normalized.name
    && normalized.address
    && normalized.phone
    && isAgencyPrintEmailValid(normalized.email),
  );
}

function normalizeUiSettings(saved) {
  const parsedRecordsPerPage = Number(saved?.recordsPerPage);
  return {
    theme: saved?.theme === "dark" || saved?.theme === "light" ? saved.theme : getDefaultTheme(),
    fontSize: normalizeUiFontSize(saved?.fontSize),
    showAppearanceDock: saved?.showAppearanceDock !== false,
    showStartDateInput: saved?.showStartDateInput === true,
    showUsageGuide: saved?.showUsageGuide !== false,
    
    
    recordsPerPage: RECORDS_PER_PAGE_OPTIONS.has(parsedRecordsPerPage)
      ? parsedRecordsPerPage
      : saved?.recordsPerPage === "unlimited"
        ? "unlimited"
        : DEFAULT_RECORDS_PER_PAGE,
    databaseName: normalizeDatabaseName(saved?.databaseName ?? saved?.agencyName),
    logoDataUrl: typeof saved?.logoDataUrl === "string" && saved.logoDataUrl.startsWith("data:image/")
      ? saved.logoDataUrl
      : "",
    agencyPrintDetails: normalizeAgencyPrintDetails(saved?.agencyPrintDetails),
    insurers: normalizeInsurerSettings(saved?.insurers),
    calculatorAccounts: normalizeCalculatorAccounts(saved?.calculatorAccounts),
    radio: globalThis.SekagentRadio?.normalizeSettings(saved?.radio) || {
      visible: true,
      shuffle: true,
      volume: 0.35,
      items: [],
    },
    idleRpg: saved?.idleRpg && typeof saved.idleRpg === "object" && !Array.isArray(saved.idleRpg)
      ? saved.idleRpg
      : null,
  };
}

function getDefaultUiSettings() {
  return normalizeUiSettings(null);
}

function clearLegacyUiSettings() {
  try {
    localStorage.removeItem(UI_SETTINGS_KEY);
    localStorage.removeItem(THEME_KEY);
  } catch {
  }
  hasLegacyUiSettings = false;
}

function applyUiSettings() {
  const databaseName = normalizeDatabaseName(uiSettings.databaseName);
  rememberBootTheme(uiSettings.theme);
  document.title = databaseName;
  elements.brandName.textContent = databaseName;
  elements.brand.setAttribute("aria-label", `${databaseName} - strona główna`);
  elements.brand.dataset.logoMode = uiSettings.logoDataUrl ? "custom" : "default";
  elements.brandLogo.src = uiSettings.logoDataUrl
    || (uiSettings.theme === "dark" ? DEFAULT_LOGO_LIGHT_SRC : DEFAULT_LOGO_SRC);
  elements.brandLogo.alt = uiSettings.logoDataUrl ? `Logo agencji ${databaseName}` : "Iseca";
  applyTheme(uiSettings.theme);
  applyFontSize(uiSettings.fontSize);
  applyAppearanceDockSetting(uiSettings.showAppearanceDock);
  applyStartDateInputSetting(uiSettings.showStartDateInput);
  applyUsageGuideSetting(uiSettings.showUsageGuide);
  elements.recordsPerPage.value = String(uiSettings.recordsPerPage);
  applyAgencyInsurerVisibility();
  if (currentAccount) renderAgencyInsurerSettings();
  globalThis.SekagentRadio?.configure(uiSettings.radio);
}

function updateThemeChoices(theme = pendingSettingsTheme) {
  elements.lightThemeChoice.setAttribute("aria-pressed", String(theme === "light"));
  elements.darkThemeChoice.setAttribute("aria-pressed", String(theme === "dark"));
}

function updateFontSizeChoices(fontSize = pendingSettingsFontSize) {
  const normalizedSize = normalizeUiFontSize(fontSize);
  elements.standardFontSizeChoice.setAttribute("aria-pressed", String(normalizedSize === "standard"));
  elements.mediumFontSizeChoice.setAttribute("aria-pressed", String(normalizedSize === "medium"));
  elements.largeFontSizeChoice.setAttribute("aria-pressed", String(normalizedSize === "large"));
}

function updateAppearanceDockControls(
  theme = document.documentElement.dataset.theme,
  fontSize = document.documentElement.dataset.fontSize,
) {
  const isDark = theme === "dark";
  const normalizedSize = normalizeUiFontSize(fontSize);
  elements.appearanceThemeToggle.setAttribute("aria-pressed", String(isDark));
  elements.appearanceThemeToggle.setAttribute(
    "aria-label",
    isDark ? "Włącz jasny motyw" : "Włącz ciemny motyw",
  );
  elements.appearanceThemeToggle.title = isDark ? "Włącz jasny motyw" : "Włącz ciemny motyw";
  elements.appearanceFontSizeChoices.forEach((button) => {
    button.setAttribute(
      "aria-pressed",
      String(button.dataset.appearanceFontSize === normalizedSize),
    );
  });
}

function getSavedAppearanceDockCollapsed() {
  try {
    return localStorage.getItem(APPEARANCE_DOCK_COLLAPSED_KEY) === "true";
  } catch {
    return false;
  }
}

function saveAppearanceDockCollapsed(collapsed) {
  try {
    localStorage.setItem(APPEARANCE_DOCK_COLLAPSED_KEY, String(collapsed));
  } catch {
  }
}

function setAppearanceDockCollapsed(collapsed, { save = true } = {}) {
  appearanceDockCollapsed = Boolean(collapsed);
  elements.appearanceDock.classList.toggle("appearance-dock--collapsed", appearanceDockCollapsed);
  elements.appearanceDock.setAttribute("aria-expanded", String(!appearanceDockCollapsed));
  elements.collapseAppearanceDock.hidden = appearanceDockCollapsed;
  elements.expandAppearanceDock.hidden = !appearanceDockCollapsed;
  if (save) saveAppearanceDockCollapsed(appearanceDockCollapsed);
}

const SETTINGS_TAB_ORDER = ["application", "user", "interface", "print-details", "agency"];

function getSettingsTabDefinitions() {
  return [
    ["application", elements.settingsApplicationTab, elements.settingsApplicationPanel],
    ["user", elements.settingsUserTab, elements.settingsUserPanel],
    ["interface", elements.settingsInterfaceTab, elements.settingsInterfacePanel],
    ["print-details", elements.settingsPrintDetailsTab, elements.settingsPrintDetailsPanel],
    ["agency", elements.settingsAgencyTab, elements.settingsAgencyPanel],
  ];
}

function setSettingsTab(tabName, options = {}) {
  activeSettingsTab = SETTINGS_TAB_ORDER.includes(tabName) ? tabName : "application";
  getSettingsTabDefinitions().forEach(([name, tab, panel]) => {
    if (!tab || !panel) return;
    const isActive = name === activeSettingsTab;
    panel.hidden = !isActive;
    tab.classList.toggle("settings-tab--active", isActive);
    tab.setAttribute("aria-selected", String(isActive));
    tab.tabIndex = isActive ? 0 : -1;
    if (isActive && options.focus) tab.focus();
  });
  if (options.resetScroll !== false) elements.settingsContent.scrollTop = 0;
}

function handleSettingsTabKeydown(event) {
  if (!["ArrowLeft", "ArrowRight", "Home", "End"].includes(event.key)) return;
  event.preventDefault();
  const currentIndex = Math.max(0, SETTINGS_TAB_ORDER.indexOf(activeSettingsTab));
  const nextTab = event.key === "Home"
    ? SETTINGS_TAB_ORDER[0]
    : event.key === "End"
      ? SETTINGS_TAB_ORDER[SETTINGS_TAB_ORDER.length - 1]
      : SETTINGS_TAB_ORDER[
        (currentIndex + (event.key === "ArrowRight" ? 1 : SETTINGS_TAB_ORDER.length - 1)) % SETTINGS_TAB_ORDER.length
      ];
  setSettingsTab(nextTab, { focus: true });
}

function setInsurerSettingsError(message = "") {
  elements.insurerSettingsError.textContent = message;
  elements.insurerSettingsError.hidden = !message;
}

function renderInsurerSettings() {
  elements.insurerSettingsEmpty.hidden = pendingInsurerSettings.length > 0;
  elements.insurerSettingsList.innerHTML = pendingInsurerSettings.map((insurer, index) => `
    <div class="insurer-settings-item" data-insurer-index="${index}">
      <label>
        <span>Nazwa</span>
        <input
          type="text"
          maxlength="${MAX_INSURER_NAME_LENGTH}"
          value="${escapeHtml(insurer.name)}"
          data-insurer-field="name"
          aria-label="Nazwa towarzystwa ${index + 1}"
        />
      </label>
      <label>
        <span>Adres strony</span>
        <input
          type="url"
          maxlength="${MAX_INSURER_URL_LENGTH}"
          inputmode="url"
          value="${escapeHtml(insurer.url)}"
          placeholder="Brak linku"
          data-insurer-field="url"
          aria-label="Adres strony towarzystwa ${escapeHtml(insurer.name)}"
        />
      </label>
      <div class="insurer-settings-actions">
        <div class="insurer-settings-order" role="group" aria-label="Zmień kolejność towarzystwa ${escapeHtml(insurer.name)}">
          <button
            type="button"
            data-insurer-action="move-up"
            aria-label="Przesuń towarzystwo ${escapeHtml(insurer.name)} wyżej"
            title="Przesuń wyżej"
            ${index === 0 ? "disabled" : ""}
          >↑</button>
          <button
            type="button"
            data-insurer-action="move-down"
            aria-label="Przesuń towarzystwo ${escapeHtml(insurer.name)} niżej"
            title="Przesuń niżej"
            ${index === pendingInsurerSettings.length - 1 ? "disabled" : ""}
          >↓</button>
        </div>
        <button
          class="insurer-settings-remove"
          type="button"
          data-insurer-action="remove"
          aria-label="Usuń towarzystwo ${escapeHtml(insurer.name)} z listy"
          title="${DEFAULT_INSURER_SETTINGS.some((entry) => entry.id === insurer.id) ? "Towarzystwo z katalogu aplikacji - wyłącz je w zakładce Agencja" : "Usuń z listy"}"
          ${DEFAULT_INSURER_SETTINGS.some((entry) => entry.id === insurer.id) ? "disabled" : ""}
        >×</button>
      </div>
    </div>
  `).join("");
}

function hideInsurerSettingsPopup() {
  globalThis.clearTimeout(insurerSettingsPopupTimer);
  globalThis.clearTimeout(insurerSettingsPopupHideTimer);
  insurerSettingsPopupTimer = null;
  insurerSettingsPopupHideTimer = null;
  elements.insurerSettingsPopup.classList.remove("insurer-settings-popup--visible");
  elements.insurerSettingsPopup.hidden = true;
}

function showInsurerSettingsPopup(message, type = "added") {
  globalThis.clearTimeout(insurerSettingsPopupTimer);
  globalThis.clearTimeout(insurerSettingsPopupHideTimer);
  elements.insurerSettingsPopupText.textContent = message;
  elements.insurerSettingsPopup.dataset.type = type;
  elements.insurerSettingsPopup.querySelector(".insurer-settings-popup__icon").textContent = type === "removed" ? "−" : "✓";
  elements.insurerSettingsPopup.hidden = false;
  elements.insurerSettingsPopup.classList.remove("insurer-settings-popup--visible");
  void elements.insurerSettingsPopup.offsetWidth;
  elements.insurerSettingsPopup.classList.add("insurer-settings-popup--visible");
  insurerSettingsPopupTimer = globalThis.setTimeout(() => {
    elements.insurerSettingsPopup.classList.remove("insurer-settings-popup--visible");
    insurerSettingsPopupHideTimer = globalThis.setTimeout(() => {
      elements.insurerSettingsPopup.hidden = true;
      insurerSettingsPopupHideTimer = null;
    }, 200);
  }, 2600);
}

function validatePendingInsurerSettings() {
  const validated = [];
  const seenNames = new Set();
  for (let index = 0; index < pendingInsurerSettings.length; index += 1) {
    const entry = pendingInsurerSettings[index];
    const name = String(entry?.name ?? "").trim().slice(0, MAX_INSURER_NAME_LENGTH);
    const nameKey = normalize(name);
    if (!nameKey) {
      const error = new Error(`Uzupełnij nazwę towarzystwa w pozycji ${index + 1}.`);
      error.insurerIndex = index;
      error.insurerField = "name";
      throw error;
    }
    if (seenNames.has(nameKey)) {
      const error = new Error(`Towarzystwo „${name}” występuje na liście więcej niż raz.`);
      error.insurerIndex = index;
      error.insurerField = "name";
      throw error;
    }
    seenNames.add(nameKey);
    const rawUrl = String(entry?.url ?? "").trim().slice(0, MAX_INSURER_URL_LENGTH);
    const url = normalizeInsurerUrl(rawUrl);
    if (rawUrl && !url) {
      const error = new Error(`Adres strony dla „${name}” jest nieprawidłowy.`);
      error.insurerIndex = index;
      error.insurerField = "url";
      throw error;
    }
    validated.push({ id: normalizeInsurerId(entry?.id || name), name, url });
  }
  return validated;
}

function focusInvalidInsurerSetting(error) {
  setSettingsTab("user");
  setInsurerSettingsError(error?.message || "Sprawdź ustawienia towarzystw.");
  const field = elements.insurerSettingsList.querySelector(
    `[data-insurer-index="${Number(error?.insurerIndex)}"] [data-insurer-field="${error?.insurerField || "name"}"]`,
  );
  field?.focus();
}

function addInsurerSetting(event) {
  event.preventDefault();
  const name = String(elements.newInsurerName.value ?? "").trim().slice(0, MAX_INSURER_NAME_LENGTH);
  const rawUrl = String(elements.newInsurerUrl.value ?? "").trim().slice(0, MAX_INSURER_URL_LENGTH);
  if (!name) {
    setInsurerSettingsError("Wpisz nazwę nowego towarzystwa.");
    elements.newInsurerName.focus();
    return;
  }
  if (pendingInsurerSettings.some((insurer) => normalize(insurer.name) === normalize(name))) {
    setInsurerSettingsError(`Towarzystwo „${name}” już znajduje się na liście.`);
    elements.newInsurerName.focus();
    return;
  }
  const url = normalizeInsurerUrl(rawUrl);
  if (rawUrl && !url) {
    setInsurerSettingsError("Wpisz prawidłowy adres strony zaczynający się od http:// lub https://.");
    elements.newInsurerUrl.focus();
    return;
  }
  pendingInsurerSettings.push({ id: normalizeInsurerId(name), name, url });
  elements.addInsurerForm.reset();
  setInsurerSettingsError();
  renderInsurerSettings();
  showInsurerSettingsPopup(`Dodano towarzystwo „${name}”`);
  elements.newInsurerName.focus();
}

function updateInsurerSetting(event) {
  const input = event.target.closest?.("[data-insurer-field]");
  if (!input) return;
  const item = input.closest("[data-insurer-index]");
  const insurer = pendingInsurerSettings[Number(item?.dataset.insurerIndex)];
  if (!insurer) return;
  insurer[input.dataset.insurerField] = input.value;
  setInsurerSettingsError();
}

function handleInsurerSettingsAction(event) {
  const button = event.target.closest?.("[data-insurer-action]");
  if (!button) return;
  const item = button.closest("[data-insurer-index]");
  const index = Number(item?.dataset.insurerIndex);
  if (!Number.isInteger(index) || index < 0 || index >= pendingInsurerSettings.length) return;
  const action = button.dataset.insurerAction;
  if (action === "remove") {
    if (button.disabled) return;
    const [removedInsurer] = pendingInsurerSettings.splice(index, 1);
    setInsurerSettingsError();
    renderInsurerSettings();
    showInsurerSettingsPopup(`Usunięto towarzystwo „${removedInsurer.name}”`, "removed");
    return;
  }

  const offset = action === "move-up" ? -1 : action === "move-down" ? 1 : 0;
  const nextIndex = index + offset;
  if (!offset || nextIndex < 0 || nextIndex >= pendingInsurerSettings.length) return;
  [pendingInsurerSettings[index], pendingInsurerSettings[nextIndex]] = [
    pendingInsurerSettings[nextIndex],
    pendingInsurerSettings[index],
  ];
  setInsurerSettingsError();
  renderInsurerSettings();
  requestAnimationFrame(() => {
    elements.insurerSettingsList.querySelector(
      `[data-insurer-index="${nextIndex}"] [data-insurer-action="${action}"]`,
    )?.focus();
  });
}

function updateWartaCredentialHint() {
  if (wartaPasswordSaved) {
    elements.wartaCredentialHint.textContent = "Hasło jest zapisane w magazynie zaszyfrowanym przez Windows. Wpisz nowe tylko, aby je zmienić.";
    elements.wartaPasswordSetting.placeholder = "Hasło zapisane - wpisz, aby zmienić";
    elements.clearWartaCredentials.hidden = false;
    if (!elements.wartaPasswordSetting.value || isWartaPasswordMaskActive()) setWartaPasswordMask();
  } else {
    elements.wartaCredentialHint.textContent = "Wpisz hasło raz i zapisz ustawienia. Następne kalkulacje użyją go automatycznie.";
    elements.wartaPasswordSetting.placeholder = "Wpisz hasło do eAgent";
    elements.clearWartaCredentials.hidden = true;
    if (isWartaPasswordMaskActive()) resetWartaPasswordEditor();
  }
}

function isWartaPasswordMaskActive() {
  return elements.wartaPasswordSetting.dataset.savedPasswordMask === "true";
}

function resetWartaPasswordToggle() {
  elements.wartaPasswordSetting.type = "password";
  elements.toggleWartaPassword.disabled = false;
  elements.toggleWartaPassword.textContent = "Pokaż";
  elements.toggleWartaPassword.setAttribute("aria-label", "Pokaż hasło");
  elements.toggleWartaPassword.setAttribute("aria-pressed", "false");
}

function resetWartaPasswordEditor() {
  elements.wartaPasswordSetting.value = "";
  delete elements.wartaPasswordSetting.dataset.savedPasswordMask;
  resetWartaPasswordToggle();
}

function setWartaPasswordMask() {
  elements.wartaPasswordSetting.value = SAVED_CALCULATOR_PASSWORD_MASK;
  elements.wartaPasswordSetting.dataset.savedPasswordMask = "true";
  elements.wartaPasswordSetting.type = "password";
  elements.toggleWartaPassword.disabled = true;
  elements.toggleWartaPassword.textContent = "Zapisane";
  elements.toggleWartaPassword.setAttribute("aria-label", "Hasło jest zapisane");
  elements.toggleWartaPassword.setAttribute("aria-pressed", "false");
}

function beginEditingWartaPassword() {
  if (!isWartaPasswordMaskActive()) return;
  resetWartaPasswordEditor();
  elements.wartaPasswordSetting.placeholder = "Wpisz nowe hasło do eAgent";
}

function restoreWartaPasswordMask() {
  if (wartaPasswordSaved && !elements.wartaPasswordSetting.value) setWartaPasswordMask();
}

function updateWartaNavigationHint() {
  elements.wartaNavigationHint.textContent = wartaPathSaved
    ? "Wykryto plik trasy Warty. Zawiera także wybór rekordu i będzie odtwarzany automatycznie."
    : "Brak pliku trasy Warty. Po logowaniu rozpocznij nagrywanie przed wyborem rekordu, wykonaj całą drogę i zakończ je na ekranie rejestracji i PESEL.";
  elements.clearWartaNavigationPath.disabled = !wartaPathSaved;
  elements.clearWartaNavigationPath.hidden = !wartaPathSaved;
  elements.downloadWartaNavigationPath.hidden = !wartaPathSaved;
}

function toggleWartaPasswordVisibility() {
  if (isWartaPasswordMaskActive()) return;
  const shouldShow = elements.wartaPasswordSetting.type === "password";
  elements.wartaPasswordSetting.type = shouldShow ? "text" : "password";
  elements.toggleWartaPassword.textContent = shouldShow ? "Ukryj" : "Pokaż";
  elements.toggleWartaPassword.setAttribute("aria-label", shouldShow ? "Ukryj hasło" : "Pokaż hasło");
  elements.toggleWartaPassword.setAttribute("aria-pressed", String(shouldShow));
}

async function deleteWartaPasswordFromVault() {
  const response = await apiFetch("/api/credentials/warta", {
    method: "DELETE",
    headers: { "Content-Type": "application/json" },
    body: "{}",
  });
  const data = await response.json();
  if (!response.ok) throw new Error(data?.error || "Nie udało się usunąć zapisanego hasła.");
}

async function deleteWartaNavigationPathFromVault() {
  const response = await apiFetch("/api/credentials/warta/path", {
    method: "DELETE",
    headers: { "Content-Type": "application/json" },
    body: "{}",
  });
  const data = await response.json();
  if (!response.ok) throw new Error(data?.error || "Nie udało się usunąć zapamiętanej trasy Warty.");
}

async function saveWartaPasswordToVault(password) {
  const response = await apiFetch("/api/credentials/warta", {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({ password }),
  });
  const data = await response.json();
  if (!response.ok) throw new Error(data?.error || "Nie udało się bezpiecznie zapisać hasła.");
}

async function clearWartaSavedPassword() {
  elements.clearWartaCredentials.disabled = true;
  try {
    await deleteWartaPasswordFromVault();
    wartaPasswordSaved = false;
    resetWartaPasswordEditor();
    updateWartaCredentialHint();
    renderWartaAutomationAvailability();
    showToast("Zapisane hasło Warty zostało usunięte");
  } catch (error) {
    showToast(error?.message || "Nie udało się usunąć hasła", "warning");
  } finally {
    elements.clearWartaCredentials.disabled = false;
  }
}

function updateInslyCredentialHint() {
  if (inslyPasswordSaved) {
    elements.inslyCredentialHint.textContent = "Hasło jest zapisane w magazynie zaszyfrowanym przez Windows. Importy logują się nim automatycznie.";
    elements.inslyPasswordSetting.placeholder = "Hasło zapisane - wpisz, aby zmienić";
    elements.clearInslyCredentials.hidden = false;
    if (!elements.inslyPasswordSetting.value || isInslyPasswordMaskActive()) setInslyPasswordMask();
  } else {
    elements.inslyCredentialHint.textContent = "Wpisz dane logowania Superpolisy raz i zapisz ustawienia - importy będą logować się same.";
    elements.inslyPasswordSetting.placeholder = "Wpisz hasło do Strefy Agenta";
    elements.clearInslyCredentials.hidden = true;
    if (isInslyPasswordMaskActive()) resetInslyPasswordEditor();
  }
}

function isInslyPasswordMaskActive() {
  return elements.inslyPasswordSetting.dataset.savedPasswordMask === "true";
}

function resetInslyPasswordToggle() {
  elements.inslyPasswordSetting.type = "password";
  elements.toggleInslyPassword.disabled = false;
  elements.toggleInslyPassword.textContent = "Pokaż";
  elements.toggleInslyPassword.setAttribute("aria-label", "Pokaż hasło");
  elements.toggleInslyPassword.setAttribute("aria-pressed", "false");
}

function resetInslyPasswordEditor() {
  elements.inslyPasswordSetting.value = "";
  delete elements.inslyPasswordSetting.dataset.savedPasswordMask;
  resetInslyPasswordToggle();
}

function setInslyPasswordMask() {
  elements.inslyPasswordSetting.value = SAVED_CALCULATOR_PASSWORD_MASK;
  elements.inslyPasswordSetting.dataset.savedPasswordMask = "true";
  elements.inslyPasswordSetting.type = "password";
  elements.toggleInslyPassword.disabled = true;
  elements.toggleInslyPassword.textContent = "Zapisane";
  elements.toggleInslyPassword.setAttribute("aria-label", "Hasło jest zapisane");
  elements.toggleInslyPassword.setAttribute("aria-pressed", "false");
}

function beginEditingInslyPassword() {
  if (!isInslyPasswordMaskActive()) return;
  resetInslyPasswordEditor();
  elements.inslyPasswordSetting.placeholder = "Wpisz nowe hasło do Strefy Agenta";
}

function restoreInslyPasswordMask() {
  if (inslyPasswordSaved && !elements.inslyPasswordSetting.value) setInslyPasswordMask();
}

function toggleInslyPasswordVisibility() {
  if (isInslyPasswordMaskActive()) return;
  const shouldShow = elements.inslyPasswordSetting.type === "password";
  elements.inslyPasswordSetting.type = shouldShow ? "text" : "password";
  elements.toggleInslyPassword.textContent = shouldShow ? "Ukryj" : "Pokaż";
  elements.toggleInslyPassword.setAttribute("aria-label", shouldShow ? "Ukryj hasło" : "Pokaż hasło");
  elements.toggleInslyPassword.setAttribute("aria-pressed", String(shouldShow));
}

async function deleteInslyPasswordFromVault() {
  const response = await apiFetch("/api/credentials/insly", {
    method: "DELETE",
    headers: { "Content-Type": "application/json" },
    body: "{}",
  });
  const data = await response.json();
  if (!response.ok) throw new Error(data?.error || "Nie udało się usunąć zapisanego hasła.");
}

async function saveInslyPasswordToVault(password) {
  const response = await apiFetch("/api/credentials/insly", {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({ password }),
  });
  const data = await response.json();
  if (!response.ok) throw new Error(data?.error || "Nie udało się bezpiecznie zapisać hasła.");
}

async function clearInslySavedPassword() {
  elements.clearInslyCredentials.disabled = true;
  try {
    await deleteInslyPasswordFromVault();
    inslyPasswordSaved = false;
    resetInslyPasswordEditor();
    updateInslyCredentialHint();
    showToast("Zapisane hasło Superpolisy zostało usunięte");
  } catch (error) {
    showToast(error?.message || "Nie udało się usunąć hasła", "warning");
  } finally {
    elements.clearInslyCredentials.disabled = false;
  }
}

function updatePzuCredentialHint() {
  if (pzuPasswordSaved) {
    elements.pzuCredentialHint.textContent = "Hasło jest zapisane w magazynie zaszyfrowanym przez Windows. Importy logują się nim automatycznie.";
    elements.pzuPasswordSetting.placeholder = "Hasło zapisane - wpisz, aby zmienić";
    elements.clearPzuCredentials.hidden = false;
    if (!elements.pzuPasswordSetting.value || isPzuPasswordMaskActive()) setPzuPasswordMask();
  } else {
    elements.pzuCredentialHint.textContent = "Wpisz dane logowania PZU raz i zapisz ustawienia - importy będą logować się same; przy dodatkowym potwierdzeniu (SMS) dokończysz w otwartej karcie.";
    elements.pzuPasswordSetting.placeholder = "Wpisz hasło do PZU";
    elements.clearPzuCredentials.hidden = true;
    if (isPzuPasswordMaskActive()) resetPzuPasswordEditor();
  }
}

function isPzuPasswordMaskActive() {
  return elements.pzuPasswordSetting.dataset.savedPasswordMask === "true";
}

function resetPzuPasswordToggle() {
  elements.pzuPasswordSetting.type = "password";
  elements.togglePzuPassword.disabled = false;
  elements.togglePzuPassword.textContent = "Pokaż";
  elements.togglePzuPassword.setAttribute("aria-label", "Pokaż hasło");
  elements.togglePzuPassword.setAttribute("aria-pressed", "false");
}

function resetPzuPasswordEditor() {
  elements.pzuPasswordSetting.value = "";
  delete elements.pzuPasswordSetting.dataset.savedPasswordMask;
  resetPzuPasswordToggle();
}

function setPzuPasswordMask() {
  elements.pzuPasswordSetting.value = SAVED_CALCULATOR_PASSWORD_MASK;
  elements.pzuPasswordSetting.dataset.savedPasswordMask = "true";
  elements.pzuPasswordSetting.type = "password";
  elements.togglePzuPassword.disabled = true;
  elements.togglePzuPassword.textContent = "Zapisane";
  elements.togglePzuPassword.setAttribute("aria-label", "Hasło jest zapisane");
  elements.togglePzuPassword.setAttribute("aria-pressed", "false");
}

function beginEditingPzuPassword() {
  if (!isPzuPasswordMaskActive()) return;
  resetPzuPasswordEditor();
  elements.pzuPasswordSetting.placeholder = "Wpisz nowe hasło do PZU";
}

function restorePzuPasswordMask() {
  if (pzuPasswordSaved && !elements.pzuPasswordSetting.value) setPzuPasswordMask();
}

function togglePzuPasswordVisibility() {
  if (isPzuPasswordMaskActive()) return;
  const shouldShow = elements.pzuPasswordSetting.type === "password";
  elements.pzuPasswordSetting.type = shouldShow ? "text" : "password";
  elements.togglePzuPassword.textContent = shouldShow ? "Ukryj" : "Pokaż";
  elements.togglePzuPassword.setAttribute("aria-label", shouldShow ? "Ukryj hasło" : "Pokaż hasło");
  elements.togglePzuPassword.setAttribute("aria-pressed", String(shouldShow));
}

async function deletePzuPasswordFromVault() {
  const response = await apiFetch("/api/credentials/pzu", {
    method: "DELETE",
    headers: { "Content-Type": "application/json" },
    body: "{}",
  });
  const data = await response.json();
  if (!response.ok) throw new Error(data?.error || "Nie udało się usunąć zapisanego hasła.");
}

async function savePzuPasswordToVault(password) {
  const response = await apiFetch("/api/credentials/pzu", {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({ password }),
  });
  const data = await response.json();
  if (!response.ok) throw new Error(data?.error || "Nie udało się bezpiecznie zapisać hasła.");
}

async function clearPzuSavedPassword() {
  elements.clearPzuCredentials.disabled = true;
  try {
    await deletePzuPasswordFromVault();
    pzuPasswordSaved = false;
    resetPzuPasswordEditor();
    updatePzuCredentialHint();
    showToast("Zapisane hasło PZU zostało usunięte");
  } catch (error) {
    showToast(error?.message || "Nie udało się usunąć hasła", "warning");
  } finally {
    elements.clearPzuCredentials.disabled = false;
  }
}

async function clearWartaSavedNavigationPath() {
  elements.clearWartaNavigationPath.disabled = true;
  try {
    await deleteWartaNavigationPathFromVault();
    wartaPathSaved = false;
    updateWartaNavigationHint();
    showToast("Usunięto plik trasy Warty. Następna kalkulacja uruchomi nagrywanie od nowa");
  } catch (error) {
    showToast(error?.message || "Nie udało się usunąć zapamiętanej trasy", "warning");
  } finally {
    elements.clearWartaNavigationPath.disabled = !wartaPathSaved;
  }
}

async function importWartaNavigationPath(event) {
  const [file] = [...(event.target.files || [])];
  event.target.value = "";
  if (!file) return;
  if (file.size > 128 * 1024) {
    showToast("Plik trasy jest zbyt duży", "warning");
    return;
  }
  elements.importWartaNavigationPath.disabled = true;
  try {
    const route = JSON.parse(await file.text());
    const response = await apiFetch("/api/automation/routes/warta", {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({ route }),
    });
    const data = await response.json();
    if (!response.ok) throw new Error(data?.error || "Nie udało się wczytać trasy Warty.");
    wartaPathSaved = true;
    updateWartaNavigationHint();
    showToast(`Wczytano trasę Warty: ${Number(data?.steps?.form || 0)} kroków do formularza i ${Number(data?.steps?.results || 0)} do wyników`, "success");
  } catch (error) {
    showToast(error?.message || "Nieprawidłowy plik trasy Warty", "warning");
  } finally {
    elements.importWartaNavigationPath.disabled = false;
  }
}

function updateGeneraliCredentialHint() {
  if (generaliPasswordSaved) {
    elements.generaliCredentialHint.textContent = "Hasło jest zapisane w magazynie zaszyfrowanym przez Windows. Wpisz nowe tylko, aby je zmienić.";
    elements.generaliPasswordSetting.placeholder = "Hasło zapisane - wpisz, aby zmienić";
    elements.clearGeneraliCredentials.hidden = false;
    if (!elements.generaliPasswordSetting.value || isGeneraliPasswordMaskActive()) setGeneraliPasswordMask();
  } else {
    elements.generaliCredentialHint.textContent = "Wpisz hasło raz i zapisz ustawienia. Następne kalkulacje użyją go automatycznie.";
    elements.generaliPasswordSetting.placeholder = "";
    elements.clearGeneraliCredentials.hidden = true;
    if (isGeneraliPasswordMaskActive()) resetGeneraliPasswordEditor();
  }
}

function isGeneraliPasswordMaskActive() {
  return elements.generaliPasswordSetting.dataset.savedPasswordMask === "true";
}

function resetGeneraliPasswordToggle() {
  elements.generaliPasswordSetting.type = "password";
  elements.toggleGeneraliPassword.disabled = false;
  elements.toggleGeneraliPassword.textContent = "Pokaż";
  elements.toggleGeneraliPassword.setAttribute("aria-label", "Pokaż hasło");
  elements.toggleGeneraliPassword.setAttribute("aria-pressed", "false");
}

function resetGeneraliPasswordEditor() {
  delete elements.generaliPasswordSetting.dataset.savedPasswordMask;
  elements.generaliPasswordSetting.value = "";
  resetGeneraliPasswordToggle();
}

function setGeneraliPasswordMask() {
  elements.generaliPasswordSetting.value = SAVED_CALCULATOR_PASSWORD_MASK;
  elements.generaliPasswordSetting.type = "password";
  elements.generaliPasswordSetting.dataset.savedPasswordMask = "true";
  elements.toggleGeneraliPassword.disabled = true;
  elements.toggleGeneraliPassword.textContent = "Zapisane";
  elements.toggleGeneraliPassword.setAttribute("aria-label", "Hasło jest zapisane");
  elements.toggleGeneraliPassword.setAttribute("aria-pressed", "false");
}

function beginEditingGeneraliPassword() {
  if (!isGeneraliPasswordMaskActive()) return;
  resetGeneraliPasswordEditor();
}

function restoreGeneraliPasswordMask() {
  if (generaliPasswordSaved && !elements.generaliPasswordSetting.value) setGeneraliPasswordMask();
}

function updateGeneraliNavigationHint() {
  elements.generaliNavigationHint.textContent = generaliPathSaved
    ? "Trasa Generali jest zapisana. Możesz ją pobrać, przekazać innej osobie albo nagrać ponownie."
    : "Brak pliku trasy Generali. Po logowaniu kliknij „Rozpocznij nagrywanie” i wykonaj całą drogę. Nagrywanie zakończy się automatycznie na ekranie rejestracji i PESEL.";
  elements.clearGeneraliNavigationPath.disabled = !generaliPathSaved;
  elements.clearGeneraliNavigationPath.hidden = !generaliPathSaved;
  elements.downloadGeneraliNavigationPath.hidden = !generaliPathSaved;
}

function toggleGeneraliPasswordVisibility() {
  if (isGeneraliPasswordMaskActive()) return;
  const shouldShow = elements.generaliPasswordSetting.type === "password";
  elements.generaliPasswordSetting.type = shouldShow ? "text" : "password";
  elements.toggleGeneraliPassword.textContent = shouldShow ? "Ukryj" : "Pokaż";
  elements.toggleGeneraliPassword.setAttribute("aria-label", shouldShow ? "Ukryj hasło" : "Pokaż hasło");
  elements.toggleGeneraliPassword.setAttribute("aria-pressed", String(shouldShow));
}

async function deleteGeneraliPasswordFromVault() {
  const response = await apiFetch("/api/credentials/generali", {
    method: "DELETE",
    headers: { "Content-Type": "application/json" },
    body: "{}",
  });
  const data = await response.json();
  if (!response.ok) throw new Error(data?.error || "Nie udało się usunąć zapisanego hasła Generali.");
}

async function deleteGeneraliNavigationPathFromVault() {
  const response = await apiFetch("/api/credentials/generali/path", {
    method: "DELETE",
    headers: { "Content-Type": "application/json" },
    body: "{}",
  });
  const data = await response.json();
  if (!response.ok) throw new Error(data?.error || "Nie udało się usunąć zapamiętanej trasy Generali.");
}

async function saveGeneraliPasswordToVault(password) {
  const response = await apiFetch("/api/credentials/generali", {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({ password }),
  });
  const data = await response.json();
  if (!response.ok) throw new Error(data?.error || "Nie udało się bezpiecznie zapisać hasła Generali.");
}

async function clearGeneraliSavedPassword() {
  elements.clearGeneraliCredentials.disabled = true;
  try {
    await deleteGeneraliPasswordFromVault();
    generaliPasswordSaved = false;
    resetGeneraliPasswordEditor();
    updateGeneraliCredentialHint();
    renderAutomationAvailability();
    showToast("Zapisane hasło Generali zostało usunięte");
  } catch (error) {
    showToast(error?.message || "Nie udało się usunąć hasła Generali", "warning");
  } finally {
    elements.clearGeneraliCredentials.disabled = false;
  }
}

async function clearGeneraliSavedNavigationPath() {
  elements.clearGeneraliNavigationPath.disabled = true;
  try {
    await deleteGeneraliNavigationPathFromVault();
    generaliPathSaved = false;
    updateGeneraliNavigationHint();
    showToast("Usunięto plik trasy Generali. Następna kalkulacja uruchomi nagrywanie od nowa");
  } catch (error) {
    showToast(error?.message || "Nie udało się usunąć zapamiętanej trasy Generali", "warning");
  } finally {
    elements.clearGeneraliNavigationPath.disabled = !generaliPathSaved;
  }
}

async function importGeneraliNavigationPath(event) {
  const [file] = [...(event.target.files || [])];
  event.target.value = "";
  if (!file) return;
  if (file.size > 128 * 1024) {
    showToast("Plik trasy Generali jest zbyt duży", "warning");
    return;
  }
  elements.importGeneraliNavigationPath.disabled = true;
  try {
    const route = JSON.parse(await file.text());
    const response = await apiFetch("/api/automation/routes/generali", {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({ route }),
    });
    const data = await response.json();
    if (!response.ok) throw new Error(data?.error || "Nie udało się wczytać trasy Generali.");
    generaliPathSaved = true;
    updateGeneraliNavigationHint();
    showToast(`Wczytano trasę Generali: ${Number(data?.steps?.form || 0)} kroków do formularza i ${Number(data?.steps?.results || 0)} do wyników`, "success");
  } catch (error) {
    showToast(error?.message || "Nieprawidłowy plik trasy Generali", "warning");
  } finally {
    elements.importGeneraliNavigationPath.disabled = false;
  }
}

function updateMtuCredentialHint() {
  if (mtuPasswordSaved) {
    elements.mtuCredentialHint.textContent = "Hasło jest zapisane w magazynie zaszyfrowanym przez Windows. Wpisz nowe tylko, aby je zmienić.";
    elements.mtuPasswordSetting.placeholder = "Hasło zapisane - wpisz, aby zmienić";
    elements.clearMtuCredentials.hidden = false;
    if (!elements.mtuPasswordSetting.value || isMtuPasswordMaskActive()) setMtuPasswordMask();
  } else {
    elements.mtuCredentialHint.textContent = "Wpisz hasło raz i zapisz ustawienia. Logowanie przejdzie kolejno przez ekran loginu i ekran hasła.";
    elements.mtuPasswordSetting.placeholder = "Wpisz hasło do MTU";
    elements.clearMtuCredentials.hidden = true;
    if (isMtuPasswordMaskActive()) resetMtuPasswordEditor();
  }
}

function isMtuPasswordMaskActive() {
  return elements.mtuPasswordSetting.dataset.savedPasswordMask === "true";
}

function resetMtuPasswordToggle() {
  elements.mtuPasswordSetting.type = "password";
  elements.toggleMtuPassword.disabled = false;
  elements.toggleMtuPassword.textContent = "Pokaż";
  elements.toggleMtuPassword.setAttribute("aria-label", "Pokaż hasło");
  elements.toggleMtuPassword.setAttribute("aria-pressed", "false");
}

function resetMtuPasswordEditor() {
  delete elements.mtuPasswordSetting.dataset.savedPasswordMask;
  elements.mtuPasswordSetting.value = "";
  resetMtuPasswordToggle();
}

function setMtuPasswordMask() {
  elements.mtuPasswordSetting.value = SAVED_CALCULATOR_PASSWORD_MASK;
  elements.mtuPasswordSetting.type = "password";
  elements.mtuPasswordSetting.dataset.savedPasswordMask = "true";
  elements.toggleMtuPassword.disabled = true;
  elements.toggleMtuPassword.textContent = "Zapisane";
  elements.toggleMtuPassword.setAttribute("aria-label", "Hasło jest zapisane");
  elements.toggleMtuPassword.setAttribute("aria-pressed", "false");
}

function beginEditingMtuPassword() {
  if (!isMtuPasswordMaskActive()) return;
  resetMtuPasswordEditor();
}

function restoreMtuPasswordMask() {
  if (mtuPasswordSaved && !elements.mtuPasswordSetting.value) setMtuPasswordMask();
}

function updateMtuNavigationHint() {
  elements.mtuNavigationHint.textContent = mtuPathSaved
    ? "Trasa MTU jest zapisana. Po logowaniu zostanie odtworzona automatycznie."
    : "Brak pliku trasy MTU. Nagrywanie będzie dostępne dopiero po podaniu loginu, hasła i wejściu do kalkulatora.";
  elements.clearMtuNavigationPath.disabled = !mtuPathSaved;
  elements.clearMtuNavigationPath.hidden = !mtuPathSaved;
  elements.downloadMtuNavigationPath.hidden = !mtuPathSaved;
}

function toggleMtuPasswordVisibility() {
  if (isMtuPasswordMaskActive()) return;
  const shouldShow = elements.mtuPasswordSetting.type === "password";
  elements.mtuPasswordSetting.type = shouldShow ? "text" : "password";
  elements.toggleMtuPassword.textContent = shouldShow ? "Ukryj" : "Pokaż";
  elements.toggleMtuPassword.setAttribute("aria-label", shouldShow ? "Ukryj hasło" : "Pokaż hasło");
  elements.toggleMtuPassword.setAttribute("aria-pressed", String(shouldShow));
}

async function deleteMtuPasswordFromVault() {
  const response = await apiFetch("/api/credentials/mtu", {
    method: "DELETE",
    headers: { "Content-Type": "application/json" },
    body: "{}",
  });
  const data = await response.json();
  if (!response.ok) throw new Error(data?.error || "Nie udało się usunąć zapisanego hasła MTU.");
}

async function deleteMtuNavigationPathFromVault() {
  const response = await apiFetch("/api/credentials/mtu/path", {
    method: "DELETE",
    headers: { "Content-Type": "application/json" },
    body: "{}",
  });
  const data = await response.json();
  if (!response.ok) throw new Error(data?.error || "Nie udało się usunąć zapamiętanej trasy MTU.");
}

async function saveMtuPasswordToVault(password, username) {
  const response = await apiFetch("/api/credentials/mtu", {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({ password, username }),
  });
  const data = await response.json();
  if (!response.ok) throw new Error(data?.error || "Nie udało się bezpiecznie zapisać hasła MTU.");
}

async function clearMtuSavedPassword() {
  elements.clearMtuCredentials.disabled = true;
  try {
    await deleteMtuPasswordFromVault();
    mtuPasswordSaved = false;
    resetMtuPasswordEditor();
    updateMtuCredentialHint();
    renderAutomationAvailability();
    showToast("Zapisane hasło MTU zostało usunięte");
  } catch (error) {
    showToast(error?.message || "Nie udało się usunąć hasła MTU", "warning");
  } finally {
    elements.clearMtuCredentials.disabled = false;
  }
}

async function clearMtuSavedNavigationPath() {
  elements.clearMtuNavigationPath.disabled = true;
  try {
    await deleteMtuNavigationPathFromVault();
    mtuPathSaved = false;
    updateMtuNavigationHint();
    showToast("Usunięto plik trasy MTU. Następna kalkulacja uruchomi nagrywanie po zalogowaniu");
  } catch (error) {
    showToast(error?.message || "Nie udało się usunąć zapamiętanej trasy MTU", "warning");
  } finally {
    elements.clearMtuNavigationPath.disabled = !mtuPathSaved;
  }
}

async function importMtuNavigationPath(event) {
  const [file] = [...(event.target.files || [])];
  event.target.value = "";
  if (!file) return;
  if (file.size > 128 * 1024) {
    showToast("Plik trasy MTU jest zbyt duży", "warning");
    return;
  }
  elements.importMtuNavigationPath.disabled = true;
  try {
    const route = JSON.parse(await file.text());
    const response = await apiFetch("/api/automation/routes/mtu", {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({ route }),
    });
    const data = await response.json();
    if (!response.ok) throw new Error(data?.error || "Nie udało się wczytać trasy MTU.");
    mtuPathSaved = true;
    updateMtuNavigationHint();
    showToast(`Wczytano trasę MTU: ${Number(data?.steps?.form || 0)} kroków do formularza i ${Number(data?.steps?.results || 0)} do wyników`, "success");
  } catch (error) {
    showToast(error?.message || "Nieprawidłowy plik trasy MTU", "warning");
  } finally {
    elements.importMtuNavigationPath.disabled = false;
  }
}

function updateHestiaCredentialHint() {
  if (hestiaPasswordSaved) {
    elements.hestiaCredentialHint.textContent = "Hasło jest zapisane w magazynie zaszyfrowanym przez Windows. Wpisz nowe tylko, aby je zmienić.";
    elements.hestiaPasswordSetting.placeholder = "Hasło zapisane - wpisz, aby zmienić";
    elements.clearHestiaCredentials.hidden = false;
    if (!elements.hestiaPasswordSetting.value || isHestiaPasswordMaskActive()) setHestiaPasswordMask();
  } else {
    elements.hestiaCredentialHint.textContent = "Wpisz hasło raz i zapisz ustawienia. Logowanie przejdzie kolejno przez ekran loginu i ekran hasła (to samo konto ERGO co w MTU).";
    elements.hestiaPasswordSetting.placeholder = "Wpisz hasło do Ergo Hestii";
    elements.clearHestiaCredentials.hidden = true;
    if (isHestiaPasswordMaskActive()) resetHestiaPasswordEditor();
  }
}

function isHestiaPasswordMaskActive() {
  return elements.hestiaPasswordSetting.dataset.savedPasswordMask === "true";
}

function resetHestiaPasswordToggle() {
  elements.hestiaPasswordSetting.type = "password";
  elements.toggleHestiaPassword.disabled = false;
  elements.toggleHestiaPassword.textContent = "Pokaż";
  elements.toggleHestiaPassword.setAttribute("aria-label", "Pokaż hasło");
  elements.toggleHestiaPassword.setAttribute("aria-pressed", "false");
}

function resetHestiaPasswordEditor() {
  delete elements.hestiaPasswordSetting.dataset.savedPasswordMask;
  elements.hestiaPasswordSetting.value = "";
  resetHestiaPasswordToggle();
}

function setHestiaPasswordMask() {
  elements.hestiaPasswordSetting.value = SAVED_CALCULATOR_PASSWORD_MASK;
  elements.hestiaPasswordSetting.type = "password";
  elements.hestiaPasswordSetting.dataset.savedPasswordMask = "true";
  elements.toggleHestiaPassword.disabled = true;
  elements.toggleHestiaPassword.textContent = "Zapisane";
  elements.toggleHestiaPassword.setAttribute("aria-label", "Hasło jest zapisane");
  elements.toggleHestiaPassword.setAttribute("aria-pressed", "false");
}

function beginEditingHestiaPassword() {
  if (!isHestiaPasswordMaskActive()) return;
  resetHestiaPasswordEditor();
}

function restoreHestiaPasswordMask() {
  if (hestiaPasswordSaved && !elements.hestiaPasswordSetting.value) setHestiaPasswordMask();
}

function toggleHestiaPasswordVisibility() {
  if (isHestiaPasswordMaskActive()) return;
  const shouldShow = elements.hestiaPasswordSetting.type === "password";
  elements.hestiaPasswordSetting.type = shouldShow ? "text" : "password";
  elements.toggleHestiaPassword.textContent = shouldShow ? "Ukryj" : "Pokaż";
  elements.toggleHestiaPassword.setAttribute("aria-label", shouldShow ? "Ukryj hasło" : "Pokaż hasło");
  elements.toggleHestiaPassword.setAttribute("aria-pressed", String(shouldShow));
}

async function deleteHestiaPasswordFromVault() {
  const response = await apiFetch("/api/credentials/hestia", {
    method: "DELETE",
    headers: { "Content-Type": "application/json" },
    body: "{}",
  });
  const data = await response.json();
  if (!response.ok) throw new Error(data?.error || "Nie udało się usunąć zapisanego hasła Ergo Hestii.");
}

async function saveHestiaPasswordToVault(password, username) {
  const response = await apiFetch("/api/credentials/hestia", {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({ password, username }),
  });
  const data = await response.json();
  if (!response.ok) throw new Error(data?.error || "Nie udało się bezpiecznie zapisać hasła Ergo Hestii.");
}

async function clearHestiaSavedPassword() {
  elements.clearHestiaCredentials.disabled = true;
  try {
    await deleteHestiaPasswordFromVault();
    hestiaPasswordSaved = false;
    resetHestiaPasswordEditor();
    updateHestiaCredentialHint();
    showToast("Zapisane hasło Ergo Hestii zostało usunięte");
  } catch (error) {
    showToast(error?.message || "Nie udało się usunąć hasła Ergo Hestii", "warning");
  } finally {
    elements.clearHestiaCredentials.disabled = false;
  }
}

function updateTrastiCredentialHint() {
  if (trastiPasswordSaved) {
    elements.trastiCredentialHint.textContent = "Hasło jest zapisane w magazynie zaszyfrowanym przez Windows. Wpisz nowe tylko, aby je zmienić.";
    elements.trastiPasswordSetting.placeholder = "Hasło zapisane - wpisz, aby zmienić";
    elements.clearTrastiCredentials.hidden = false;
    if (!elements.trastiPasswordSetting.value || isTrastiPasswordMaskActive()) setTrastiPasswordMask();
  } else {
    elements.trastiCredentialHint.textContent = "Wpisz hasło raz i zapisz ustawienia. Następne kalkulacje użyją go automatycznie.";
    elements.trastiPasswordSetting.placeholder = "Wpisz hasło do Trasti";
    elements.clearTrastiCredentials.hidden = true;
    if (isTrastiPasswordMaskActive()) resetTrastiPasswordEditor();
  }
}

function isTrastiPasswordMaskActive() {
  return elements.trastiPasswordSetting.dataset.savedPasswordMask === "true";
}

function resetTrastiPasswordToggle() {
  elements.trastiPasswordSetting.type = "password";
  elements.toggleTrastiPassword.disabled = false;
  elements.toggleTrastiPassword.textContent = "Pokaż";
  elements.toggleTrastiPassword.setAttribute("aria-label", "Pokaż hasło");
  elements.toggleTrastiPassword.setAttribute("aria-pressed", "false");
}

function resetTrastiPasswordEditor() {
  delete elements.trastiPasswordSetting.dataset.savedPasswordMask;
  elements.trastiPasswordSetting.value = "";
  resetTrastiPasswordToggle();
}

function setTrastiPasswordMask() {
  elements.trastiPasswordSetting.value = SAVED_CALCULATOR_PASSWORD_MASK;
  elements.trastiPasswordSetting.type = "password";
  elements.trastiPasswordSetting.dataset.savedPasswordMask = "true";
  elements.toggleTrastiPassword.disabled = true;
  elements.toggleTrastiPassword.textContent = "Zapisane";
  elements.toggleTrastiPassword.setAttribute("aria-label", "Hasło jest zapisane");
  elements.toggleTrastiPassword.setAttribute("aria-pressed", "false");
}

function beginEditingTrastiPassword() {
  if (!isTrastiPasswordMaskActive()) return;
  resetTrastiPasswordEditor();
}

function restoreTrastiPasswordMask() {
  if (trastiPasswordSaved && !elements.trastiPasswordSetting.value) setTrastiPasswordMask();
}

function updateTrastiNavigationHint() {
  elements.trastiNavigationHint.textContent = trastiPathSaved
    ? "Trasa Trasti jest zapisana. Po logowaniu zostanie odtworzona automatycznie."
    : "Brak pliku trasy Trasti. Po logowaniu nagraj drogę do pól numeru rejestracyjnego i PESEL.";
  elements.clearTrastiNavigationPath.disabled = !trastiPathSaved;
  elements.clearTrastiNavigationPath.hidden = !trastiPathSaved;
  elements.downloadTrastiNavigationPath.hidden = !trastiPathSaved;
}

function toggleTrastiPasswordVisibility() {
  if (isTrastiPasswordMaskActive()) return;
  const shouldShow = elements.trastiPasswordSetting.type === "password";
  elements.trastiPasswordSetting.type = shouldShow ? "text" : "password";
  elements.toggleTrastiPassword.textContent = shouldShow ? "Ukryj" : "Pokaż";
  elements.toggleTrastiPassword.setAttribute("aria-label", shouldShow ? "Ukryj hasło" : "Pokaż hasło");
  elements.toggleTrastiPassword.setAttribute("aria-pressed", String(shouldShow));
}

async function deleteTrastiPasswordFromVault() {
  const response = await apiFetch("/api/credentials/trasti", {
    method: "DELETE",
    headers: { "Content-Type": "application/json" },
    body: "{}",
  });
  const data = await response.json();
  if (!response.ok) throw new Error(data?.error || "Nie udało się usunąć zapisanego hasła Trasti.");
}

async function deleteTrastiNavigationPathFromVault() {
  const response = await apiFetch("/api/credentials/trasti/path", {
    method: "DELETE",
    headers: { "Content-Type": "application/json" },
    body: "{}",
  });
  const data = await response.json();
  if (!response.ok) throw new Error(data?.error || "Nie udało się usunąć zapamiętanej trasy Trasti.");
}

async function saveTrastiPasswordToVault(password) {
  const response = await apiFetch("/api/credentials/trasti", {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({ password }),
  });
  const data = await response.json();
  if (!response.ok) throw new Error(data?.error || "Nie udało się bezpiecznie zapisać hasła Trasti.");
}

async function clearTrastiSavedPassword() {
  elements.clearTrastiCredentials.disabled = true;
  try {
    await deleteTrastiPasswordFromVault();
    trastiPasswordSaved = false;
    resetTrastiPasswordEditor();
    updateTrastiCredentialHint();
    renderAutomationAvailability();
    showToast("Zapisane hasło Trasti zostało usunięte");
  } catch (error) {
    showToast(error?.message || "Nie udało się usunąć hasła Trasti", "warning");
  } finally {
    elements.clearTrastiCredentials.disabled = false;
  }
}

async function clearTrastiSavedNavigationPath() {
  elements.clearTrastiNavigationPath.disabled = true;
  try {
    await deleteTrastiNavigationPathFromVault();
    trastiPathSaved = false;
    updateTrastiNavigationHint();
    showToast("Usunięto plik trasy Trasti. Następna kalkulacja uruchomi nagrywanie po zalogowaniu");
  } catch (error) {
    showToast(error?.message || "Nie udało się usunąć zapamiętanej trasy Trasti", "warning");
  } finally {
    elements.clearTrastiNavigationPath.disabled = !trastiPathSaved;
  }
}

async function importTrastiNavigationPath(event) {
  const [file] = [...(event.target.files || [])];
  event.target.value = "";
  if (!file) return;
  if (file.size > 128 * 1024) {
    showToast("Plik trasy Trasti jest zbyt duży", "warning");
    return;
  }
  elements.importTrastiNavigationPath.disabled = true;
  try {
    const route = JSON.parse(await file.text());
    const response = await apiFetch("/api/automation/routes/trasti", {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({ route }),
    });
    const data = await response.json();
    if (!response.ok) throw new Error(data?.error || "Nie udało się wczytać trasy Trasti.");
    trastiPathSaved = true;
    updateTrastiNavigationHint();
    showToast(`Wczytano trasę Trasti: ${Number(data?.steps?.form || 0)} kroków do formularza i ${Number(data?.steps?.results || 0)} do wyników`, "success");
  } catch (error) {
    showToast(error?.message || "Nieprawidłowy plik trasy Trasti", "warning");
  } finally {
    elements.importTrastiNavigationPath.disabled = false;
  }
}

function updateCompensaCredentialHint() {
  if (compensaPasswordSaved) {
    elements.compensaCredentialHint.textContent = "Has\u0142o jest zapisane w magazynie zaszyfrowanym przez Windows. Wpisz nowe tylko, aby je zmieni\u0107.";
    elements.compensaPasswordSetting.placeholder = "Has\u0142o zapisane - wpisz, aby zmieni\u0107";
    elements.clearCompensaCredentials.hidden = false;
    if (!elements.compensaPasswordSetting.value || isCompensaPasswordMaskActive()) setCompensaPasswordMask();
  } else {
    elements.compensaCredentialHint.textContent = "Wpisz has\u0142o raz i zapisz ustawienia. Nast\u0119pne kalkulacje u\u017cyj\u0105 go automatycznie.";
    elements.compensaPasswordSetting.placeholder = "Wpisz has\u0142o do cPortal";
    elements.clearCompensaCredentials.hidden = true;
    if (isCompensaPasswordMaskActive()) resetCompensaPasswordEditor();
  }
}

function isCompensaPasswordMaskActive() {
  return elements.compensaPasswordSetting.dataset.savedPasswordMask === "true";
}

function resetCompensaPasswordToggle() {
  elements.compensaPasswordSetting.type = "password";
  elements.toggleCompensaPassword.disabled = false;
  elements.toggleCompensaPassword.textContent = "Poka\u017c";
  elements.toggleCompensaPassword.setAttribute("aria-label", "Poka\u017c has\u0142o");
  elements.toggleCompensaPassword.setAttribute("aria-pressed", "false");
}

function resetCompensaPasswordEditor() {
  delete elements.compensaPasswordSetting.dataset.savedPasswordMask;
  elements.compensaPasswordSetting.value = "";
  resetCompensaPasswordToggle();
}

function setCompensaPasswordMask() {
  elements.compensaPasswordSetting.value = SAVED_CALCULATOR_PASSWORD_MASK;
  elements.compensaPasswordSetting.type = "password";
  elements.compensaPasswordSetting.dataset.savedPasswordMask = "true";
  elements.toggleCompensaPassword.disabled = true;
  elements.toggleCompensaPassword.textContent = "Zapisane";
  elements.toggleCompensaPassword.setAttribute("aria-label", "Has\u0142o jest zapisane");
  elements.toggleCompensaPassword.setAttribute("aria-pressed", "false");
}

function beginEditingCompensaPassword() {
  if (!isCompensaPasswordMaskActive()) return;
  resetCompensaPasswordEditor();
}

function restoreCompensaPasswordMask() {
  if (compensaPasswordSaved && !elements.compensaPasswordSetting.value) setCompensaPasswordMask();
}

function updateCompensaNavigationHint() {
  elements.compensaNavigationHint.textContent = compensaPathSaved
    ? "Trasa Compensa jest zapisana. Po logowaniu zostanie odtworzona automatycznie."
    : "Brak pliku trasy Compensa. Po logowaniu nagraj drog\u0119 do p\u00f3l PESEL i numeru rejestracyjnego.";
  elements.clearCompensaNavigationPath.disabled = !compensaPathSaved;
  elements.clearCompensaNavigationPath.hidden = !compensaPathSaved;
  elements.downloadCompensaNavigationPath.hidden = !compensaPathSaved;
}

function toggleCompensaPasswordVisibility() {
  if (isCompensaPasswordMaskActive()) return;
  const shouldShow = elements.compensaPasswordSetting.type === "password";
  elements.compensaPasswordSetting.type = shouldShow ? "text" : "password";
  elements.toggleCompensaPassword.textContent = shouldShow ? "Ukryj" : "Poka\u017c";
  elements.toggleCompensaPassword.setAttribute("aria-label", shouldShow ? "Ukryj has\u0142o" : "Poka\u017c has\u0142o");
  elements.toggleCompensaPassword.setAttribute("aria-pressed", String(shouldShow));
}

async function deleteCompensaPasswordFromVault() {
  const response = await apiFetch("/api/credentials/compensa", {
    method: "DELETE",
    headers: { "Content-Type": "application/json" },
  });
  const data = await response.json().catch(() => null);
  if (!response.ok) throw new Error(data?.error || "Nie uda\u0142o si\u0119 usun\u0105\u0107 zapisanego has\u0142a Compensa.");
}

async function deleteCompensaNavigationPathFromVault() {
  const response = await apiFetch("/api/credentials/compensa/path", {
    method: "DELETE",
    headers: { "Content-Type": "application/json" },
  });
  const data = await response.json().catch(() => null);
  if (!response.ok) throw new Error(data?.error || "Nie uda\u0142o si\u0119 usun\u0105\u0107 zapami\u0119tanej trasy Compensa.");
}

async function saveCompensaPasswordToVault(password) {
  const response = await apiFetch("/api/credentials/compensa", {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({ password }),
  });
  const data = await response.json().catch(() => null);
  if (!response.ok) throw new Error(data?.error || "Nie uda\u0142o si\u0119 bezpiecznie zapisa\u0107 has\u0142a Compensa.");
}

async function clearCompensaSavedPassword() {
  elements.clearCompensaCredentials.disabled = true;
  try {
    await deleteCompensaPasswordFromVault();
    compensaPasswordSaved = false;
    resetCompensaPasswordEditor();
    updateCompensaCredentialHint();
    renderAutomationAvailability();
    showToast("Zapisane has\u0142o Compensa zosta\u0142o usuni\u0119te");
  } catch (error) {
    showToast(error?.message || "Nie uda\u0142o si\u0119 usun\u0105\u0107 has\u0142a Compensa", "warning");
  } finally {
    elements.clearCompensaCredentials.disabled = false;
  }
}

function updateAllianzCredentialHint() {
  if (allianzPasswordSaved) {
    elements.allianzCredentialHint.textContent = "Hasło jest zapisane w magazynie zaszyfrowanym przez Windows. Wpisz nowe tylko, aby je zmienić.";
    elements.allianzPasswordSetting.placeholder = "Hasło zapisane - wpisz, aby zmienić";
    elements.clearAllianzCredentials.hidden = false;
    if (!elements.allianzPasswordSetting.value || isAllianzPasswordMaskActive()) setAllianzPasswordMask();
  } else {
    elements.allianzCredentialHint.textContent = "Wpisz login i hasło raz i zapisz ustawienia. Gdy portal poprosi o kod SMS, okno otworzy się samo - wystarczy przepisać kod.";
    elements.allianzPasswordSetting.placeholder = "Wpisz hasło do CHUCK";
    elements.clearAllianzCredentials.hidden = true;
    if (isAllianzPasswordMaskActive()) resetAllianzPasswordEditor();
  }
}

function isAllianzPasswordMaskActive() {
  return elements.allianzPasswordSetting.dataset.savedPasswordMask === "true";
}

function resetAllianzPasswordToggle() {
  elements.allianzPasswordSetting.type = "password";
  elements.toggleAllianzPassword.disabled = false;
  elements.toggleAllianzPassword.textContent = "Pokaż";
  elements.toggleAllianzPassword.setAttribute("aria-label", "Pokaż hasło");
  elements.toggleAllianzPassword.setAttribute("aria-pressed", "false");
}

function resetAllianzPasswordEditor() {
  delete elements.allianzPasswordSetting.dataset.savedPasswordMask;
  elements.allianzPasswordSetting.value = "";
  resetAllianzPasswordToggle();
}

function setAllianzPasswordMask() {
  elements.allianzPasswordSetting.value = SAVED_CALCULATOR_PASSWORD_MASK;
  elements.allianzPasswordSetting.type = "password";
  elements.allianzPasswordSetting.dataset.savedPasswordMask = "true";
  elements.toggleAllianzPassword.disabled = true;
  elements.toggleAllianzPassword.textContent = "Zapisane";
  elements.toggleAllianzPassword.setAttribute("aria-label", "Hasło jest zapisane");
  elements.toggleAllianzPassword.setAttribute("aria-pressed", "false");
}

function beginEditingAllianzPassword() {
  if (!isAllianzPasswordMaskActive()) return;
  resetAllianzPasswordEditor();
}

function restoreAllianzPasswordMask() {
  if (allianzPasswordSaved && !elements.allianzPasswordSetting.value) setAllianzPasswordMask();
}

function toggleAllianzPasswordVisibility() {
  if (isAllianzPasswordMaskActive()) return;
  const shouldShow = elements.allianzPasswordSetting.type === "password";
  elements.allianzPasswordSetting.type = shouldShow ? "text" : "password";
  elements.toggleAllianzPassword.textContent = shouldShow ? "Ukryj" : "Pokaż";
  elements.toggleAllianzPassword.setAttribute("aria-label", shouldShow ? "Ukryj hasło" : "Pokaż hasło");
  elements.toggleAllianzPassword.setAttribute("aria-pressed", String(shouldShow));
}

async function deleteAllianzPasswordFromVault() {
  const response = await apiFetch("/api/credentials/allianz", {
    method: "DELETE",
    headers: { "Content-Type": "application/json" },
  });
  const data = await response.json().catch(() => null);
  if (!response.ok) throw new Error(data?.error || "Nie udało się usunąć zapisanego hasła Allianz.");
}

async function saveAllianzPasswordToVault(password) {
  const response = await apiFetch("/api/credentials/allianz", {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({ password }),
  });
  const data = await response.json().catch(() => null);
  if (!response.ok) throw new Error(data?.error || "Nie udało się bezpiecznie zapisać hasła Allianz.");
}

async function clearAllianzSavedPassword() {
  elements.clearAllianzCredentials.disabled = true;
  try {
    await deleteAllianzPasswordFromVault();
    allianzPasswordSaved = false;
    resetAllianzPasswordEditor();
    updateAllianzCredentialHint();
    renderAutomationAvailability();
    showToast("Zapisane hasło Allianz zostało usunięte");
  } catch (error) {
    showToast(error?.message || "Nie udało się usunąć hasła Allianz", "warning");
  } finally {
    elements.clearAllianzCredentials.disabled = false;
  }
}

async function clearCompensaSavedNavigationPath() {
  elements.clearCompensaNavigationPath.disabled = true;
  try {
    await deleteCompensaNavigationPathFromVault();
    compensaPathSaved = false;
    updateCompensaNavigationHint();
    showToast("Usuni\u0119to plik trasy Compensa. Nast\u0119pna kalkulacja uruchomi nagrywanie po zalogowaniu");
  } catch (error) {
    showToast(error?.message || "Nie uda\u0142o si\u0119 usun\u0105\u0107 zapami\u0119tanej trasy Compensa", "warning");
  } finally {
    elements.clearCompensaNavigationPath.disabled = !compensaPathSaved;
  }
}

async function importCompensaNavigationPath(event) {
  const file = event.target.files?.[0];
  event.target.value = "";
  if (!file) return;
  if (file.size > MAX_NAVIGATION_PATH_FILE_SIZE) {
    showToast("Plik trasy Compensa jest zbyt du\u017cy", "warning");
    return;
  }
  elements.importCompensaNavigationPath.disabled = true;
  try {
    const route = JSON.parse(await file.text());
    const response = await apiFetch("/api/automation/routes/compensa", {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({ route }),
    });
    const data = await response.json().catch(() => null);
    if (!response.ok) throw new Error(data?.error || "Nie uda\u0142o si\u0119 wczyta\u0107 trasy Compensa.");
    compensaPathSaved = true;
    updateCompensaNavigationHint();
    showToast(`Wczytano tras\u0119 Compensa: ${Number(data?.steps?.form || 0)} krok\u00f3w do formularza i ${Number(data?.steps?.results || 0)} do wynik\u00f3w`, "success");
  } catch (error) {
    showToast(error?.message || "Nieprawid\u0142owy plik trasy Compensa", "warning");
  } finally {
    elements.importCompensaNavigationPath.disabled = false;
  }
}

function updateWienerCredentialHint() {
  if (wienerPasswordSaved) {
    elements.wienerCredentialHint.textContent = "Hasło jest zapisane w magazynie zaszyfrowanym przez Windows. Wpisz nowe tylko, aby je zmienić.";
    elements.wienerPasswordSetting.placeholder = "Hasło zapisane - wpisz, aby zmienić";
    elements.clearWienerCredentials.hidden = false;
    if (!elements.wienerPasswordSetting.value || isWienerPasswordMaskActive()) setWienerPasswordMask();
  } else {
    elements.wienerCredentialHint.textContent = "Wpisz hasło raz i zapisz ustawienia. Następne kalkulacje użyją go automatycznie.";
    elements.wienerPasswordSetting.placeholder = "Wpisz hasło do Wie.net";
    elements.clearWienerCredentials.hidden = true;
    if (isWienerPasswordMaskActive()) resetWienerPasswordEditor();
  }
}

function isWienerPasswordMaskActive() {
  return elements.wienerPasswordSetting.dataset.savedPasswordMask === "true";
}

function resetWienerPasswordToggle() {
  elements.wienerPasswordSetting.type = "password";
  elements.toggleWienerPassword.disabled = false;
  elements.toggleWienerPassword.textContent = "Pokaż";
  elements.toggleWienerPassword.setAttribute("aria-label", "Pokaż hasło");
  elements.toggleWienerPassword.setAttribute("aria-pressed", "false");
}

function resetWienerPasswordEditor() {
  delete elements.wienerPasswordSetting.dataset.savedPasswordMask;
  elements.wienerPasswordSetting.value = "";
  resetWienerPasswordToggle();
}

function setWienerPasswordMask() {
  elements.wienerPasswordSetting.value = SAVED_CALCULATOR_PASSWORD_MASK;
  elements.wienerPasswordSetting.type = "password";
  elements.wienerPasswordSetting.dataset.savedPasswordMask = "true";
  elements.toggleWienerPassword.disabled = true;
  elements.toggleWienerPassword.textContent = "Zapisane";
  elements.toggleWienerPassword.setAttribute("aria-label", "Hasło jest zapisane");
  elements.toggleWienerPassword.setAttribute("aria-pressed", "false");
}

function beginEditingWienerPassword() {
  if (!isWienerPasswordMaskActive()) return;
  resetWienerPasswordEditor();
}

function restoreWienerPasswordMask() {
  if (wienerPasswordSaved && !elements.wienerPasswordSetting.value) setWienerPasswordMask();
}

function updateWienerNavigationHint() {
  elements.wienerNavigationHint.textContent = wienerPathSaved
    ? "Trasa Wiener jest zapisana. Po logowaniu zostanie odtworzona automatycznie."
    : "Brak pliku trasy Wiener. Po logowaniu nagraj drogę do pól numeru rejestracyjnego i PESEL.";
  elements.clearWienerNavigationPath.disabled = !wienerPathSaved;
  elements.clearWienerNavigationPath.hidden = !wienerPathSaved;
  elements.downloadWienerNavigationPath.hidden = !wienerPathSaved;
}

function toggleWienerPasswordVisibility() {
  if (isWienerPasswordMaskActive()) return;
  const shouldShow = elements.wienerPasswordSetting.type === "password";
  elements.wienerPasswordSetting.type = shouldShow ? "text" : "password";
  elements.toggleWienerPassword.textContent = shouldShow ? "Ukryj" : "Pokaż";
  elements.toggleWienerPassword.setAttribute("aria-label", shouldShow ? "Ukryj hasło" : "Pokaż hasło");
  elements.toggleWienerPassword.setAttribute("aria-pressed", String(shouldShow));
}

async function deleteWienerPasswordFromVault() {
  const response = await apiFetch("/api/credentials/wiener", {
    method: "DELETE",
    headers: { "Content-Type": "application/json" },
    body: "{}",
  });
  const data = await response.json();
  if (!response.ok) throw new Error(data?.error || "Nie udało się usunąć zapisanego hasła Wiener.");
}

async function deleteWienerNavigationPathFromVault() {
  const response = await apiFetch("/api/credentials/wiener/path", {
    method: "DELETE",
    headers: { "Content-Type": "application/json" },
    body: "{}",
  });
  const data = await response.json();
  if (!response.ok) throw new Error(data?.error || "Nie udało się usunąć zapamiętanej trasy Wiener.");
}

async function saveWienerPasswordToVault(password) {
  const response = await apiFetch("/api/credentials/wiener", {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({ password }),
  });
  const data = await response.json();
  if (!response.ok) throw new Error(data?.error || "Nie udało się bezpiecznie zapisać hasła Wiener.");
}

async function clearWienerSavedPassword() {
  elements.clearWienerCredentials.disabled = true;
  try {
    await deleteWienerPasswordFromVault();
    wienerPasswordSaved = false;
    resetWienerPasswordEditor();
    updateWienerCredentialHint();
    renderAutomationAvailability();
    showToast("Zapisane hasło Wiener zostało usunięte");
  } catch (error) {
    showToast(error?.message || "Nie udało się usunąć hasła Wiener", "warning");
  } finally {
    elements.clearWienerCredentials.disabled = false;
  }
}

async function clearWienerSavedNavigationPath() {
  elements.clearWienerNavigationPath.disabled = true;
  try {
    await deleteWienerNavigationPathFromVault();
    wienerPathSaved = false;
    updateWienerNavigationHint();
    showToast("Usunięto plik trasy Wiener. Następna kalkulacja uruchomi nagrywanie po zalogowaniu");
  } catch (error) {
    showToast(error?.message || "Nie udało się usunąć zapamiętanej trasy Wiener", "warning");
  } finally {
    elements.clearWienerNavigationPath.disabled = !wienerPathSaved;
  }
}

async function importWienerNavigationPath(event) {
  const [file] = [...(event.target.files || [])];
  event.target.value = "";
  if (!file) return;
  if (file.size > 128 * 1024) {
    showToast("Plik trasy Wiener jest zbyt duży", "warning");
    return;
  }
  elements.importWienerNavigationPath.disabled = true;
  try {
    const route = JSON.parse(await file.text());
    const response = await apiFetch("/api/automation/routes/wiener", {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({ route }),
    });
    const data = await response.json();
    if (!response.ok) throw new Error(data?.error || "Nie udało się wczytać trasy Wiener.");
    wienerPathSaved = true;
    updateWienerNavigationHint();
    showToast(`Wczytano trasę Wiener: ${Number(data?.steps?.form || 0)} kroków do formularza i ${Number(data?.steps?.results || 0)} do wyników`, "success");
  } catch (error) {
    showToast(error?.message || "Nieprawidłowy plik trasy Wiener", "warning");
  } finally {
    elements.importWienerNavigationPath.disabled = false;
  }
}

async function restoreSavedNavigationPath({ insurer, label, buttonKey, onRestored }) {
  const button = elements[buttonKey];
  button.disabled = true;
  try {
    const response = await apiFetch(`/api/automation/routes/${insurer}/restore`, {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: "{}",
    });
    const data = await response.json();
    if (!response.ok) throw new Error(data?.error || `Nie udało się przywrócić trasy ${label}.`);
    onRestored();
    const sourceLabel = data?.source === "domyslna" ? "domyślną" : "poprzednią";
    showToast(`Przywrócono ${sourceLabel} trasę ${label}: ${Number(data?.steps?.form || 0)} kroków do formularza i ${Number(data?.steps?.results || 0)} do wyników`, "success");
  } catch (error) {
    showToast(error?.message || `Nie udało się przywrócić trasy ${label}`, "warning");
  } finally {
    button.disabled = false;
  }
}



const licenseGuardState = {
  stan: "nieznany",
  tylkoOdczyt: false,
  komunikat: "",
  wazneDo: "",
  dniDoKonca: null,
  nazwa: "",
};

const LICENCJA_TYTULY = {
  brak: "Zaloguj się, żeby korzystać z programu",
  wygasla: "Licencja programu skończyła się",
  wylaczona: "Dostęp do programu został wstrzymany",
  karencja: "Licencja programu skończyła się",
  "zegar-cofniety": "Data w komputerze się nie zgadza",
};

function renderLicenseGuard(state) {
  Object.assign(licenseGuardState, {
    stan: String(state?.stan || "nieznany"),
    tylkoOdczyt: state?.tylkoOdczyt === true,
    komunikat: String(state?.komunikat || ""),
    wazneDo: String(state?.wazneDo || ""),
    dniDoKonca: Number.isFinite(Number(state?.dniDoKonca)) ? Number(state.dniDoKonca) : null,
    nazwa: String(state?.nazwa || ""),
  });
  document.body.dataset.licencja = licenseGuardState.stan;
  document.body.dataset.tylkoOdczyt = licenseGuardState.tylkoOdczyt ? "tak" : "nie";

  
  
  
  const pokazPasek = licenseGuardState.tylkoOdczyt
    || licenseGuardState.stan === "karencja"
    || (licenseGuardState.stan === "aktywna"
      && licenseGuardState.dniDoKonca !== null
      && licenseGuardState.dniDoKonca <= 14);
  if (!pokazPasek) {
    elements.licenseBanner.hidden = true;
    return;
  }
  elements.licenseBanner.hidden = false;
  elements.licenseBanner.dataset.stan = licenseGuardState.stan;
  elements.licenseBannerTitle.textContent = LICENCJA_TYTULY[licenseGuardState.stan]
    || (licenseGuardState.dniDoKonca !== null && licenseGuardState.dniDoKonca >= 0
      ? `Licencja kończy się za ${licenseGuardState.dniDoKonca} dni`
      : "Licencja programu");
  elements.licenseBannerMessage.textContent = state?.bladSprawdzenia
    ? `${licenseGuardState.komunikat} ${state.bladSprawdzenia}`.trim()
    : licenseGuardState.komunikat;
  elements.licenseBannerAction.textContent = licenseGuardState.stan === "brak" ? "Zaloguj" : "Sprawdź ponownie";
}

async function refreshLicenseGuard() {
  try {
    const response = await apiFetch("/api/licencja/program", { cache: "no-store" });
    const data = await response.json();
    if (!response.ok) return null;
    renderLicenseGuard(data);
    return data;
  } catch {
    return null;
  }
}

async function forceLicenseRefresh() {
  elements.licenseBannerAction.disabled = true;
  try {
    const response = await apiFetch("/api/licencja/odswiez", {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: "{}",
    });
    const data = await response.json();
    if (!response.ok) throw new Error(data?.error || "Nie udało się sprawdzić licencji.");
    renderLicenseGuard(data);
    if (!data?.tylkoOdczyt) showToast("Licencja potwierdzona", "success");
    else if (data?.bladSprawdzenia) showToast(data.bladSprawdzenia, "warning");
    return data;
  } catch (error) {
    showToast(error?.message || "Nie udało się sprawdzić licencji", "warning");
    return null;
  } finally {
    elements.licenseBannerAction.disabled = false;
  }
}



let lastLicenseStatus = null;

function formatLicenseDate(value) {
  const date = String(value || "");
  if (!/^\d{4}-\d{2}-\d{2}$/.test(date)) return "";
  const [year, month, day] = date.split("-");
  return `${day}.${month}.${year}`;
}

function setLicenseFormVisible(visible, { focus = false } = {}) {
  elements.licenseForm.hidden = !visible;
  elements.licenseToggleForm.hidden = visible;
  if (!visible) {
    elements.licensePassword.value = "";
    return;
  }
  if (focus) {
    (elements.licenseLogin.value ? elements.licensePassword : elements.licenseLogin).focus();
  }
}

function renderLicenseStatus(license, { komunikat = "" } = {}) {
  if (!license) return;
  lastLicenseStatus = license;
  elements.licenseLogin.value = license.login || elements.licenseLogin.value;
  elements.licenseRemove.hidden = !license.skonfigurowana;
  const dataAbonamentu = formatLicenseDate(license.abonamentDo);
  
  
  const dni = license.dniDoKonca === null || license.dniDoKonca === undefined
    ? Number.NaN
    : Number(license.dniDoKonca);

  if (!license.skonfigurowana) {
    elements.licenseRow.dataset.state = "required";
    elements.licenseStatus.textContent = "Zaloguj się, żeby pobierać aktualizacje";
    elements.licenseDetails.textContent = komunikat
      || "Login i hasło otrzymujesz od autora programu razem z abonamentem.";
    elements.licenseToggleForm.textContent = "Zaloguj";
    return;
  }
  if (license.powod === "ABONAMENT_WYGASL") {
    elements.licenseRow.dataset.state = "error";
    elements.licenseStatus.textContent = dataAbonamentu
      ? `Abonament wygasł ${dataAbonamentu}`
      : "Abonament wygasł";
    elements.licenseDetails.textContent = komunikat
      || "Skontaktuj się z autorem programu, żeby przedłużyć abonament. Program działa dalej, nie pobiera tylko nowych wersji.";
    elements.licenseToggleForm.textContent = "Zmień dane";
    return;
  }
  if (license.powod === "AKTUALIZACJE_WSTRZYMANE") {
    elements.licenseRow.dataset.state = "error";
    elements.licenseStatus.textContent = "Pobieranie aktualizacji jest wstrzymane";
    elements.licenseDetails.textContent = komunikat
      || "Skontaktuj się z autorem programu. Twoje dane i program działają bez zmian.";
    elements.licenseToggleForm.textContent = "Zmień dane";
    return;
  }
  if (license.powod === "ZLE_DANE") {
    elements.licenseRow.dataset.state = "error";
    elements.licenseStatus.textContent = "Login lub hasło nie pasują";
    elements.licenseDetails.textContent = komunikat || "Sprawdź dane otrzymane od autora programu i zapisz je ponownie.";
    elements.licenseToggleForm.textContent = "Popraw dane";
    return;
  }
  elements.licenseRow.dataset.state = "active";
  elements.licenseStatus.textContent = license.nazwa
    ? `Abonament: ${license.nazwa}`
    : "Dostęp do aktualizacji jest aktywny";
  const czesci = [`Zalogowano jako ${license.login}`];
  if (dataAbonamentu) {
    czesci.push(Number.isFinite(dni) && dni <= 30
      ? `abonament do ${dataAbonamentu} (zostało ${Math.max(dni, 0)} dni)`
      : `abonament do ${dataAbonamentu}`);
  } else czesci.push("abonament bez terminu");
  elements.licenseDetails.textContent = `${czesci.join(" • ")}.`;
  elements.licenseToggleForm.textContent = "Zmień dane";
}

async function refreshLicenseStatus() {
  try {
    const response = await apiFetch("/api/licencja/status", { cache: "no-store" });
    const data = await response.json();
    if (!response.ok) throw new Error(data?.error || "Nie udało się sprawdzić dostępu do aktualizacji.");
    renderLicenseStatus(data);
    return data;
  } catch {
    elements.licenseRow.dataset.state = "checking";
    elements.licenseStatus.textContent = "Nie udało się sprawdzić dostępu do aktualizacji";
    elements.licenseDetails.textContent = "Sprawdź połączenie z internetem i spróbuj ponownie.";
    return null;
  }
}

async function saveLicenseCredentials() {
  const login = elements.licenseLogin.value.trim().toLowerCase();
  const haslo = elements.licensePassword.value;
  if (!login || !haslo) {
    showToast("Podaj login i hasło do aktualizacji", "warning");
    return;
  }
  elements.licenseSave.disabled = true;
  elements.licenseStatus.textContent = "Sprawdzanie loginu i hasła…";
  elements.licenseDetails.textContent = "";
  try {
    const response = await apiFetch("/api/licencja/zapisz", {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({ login, haslo }),
    });
    const data = await response.json();
    if (!response.ok) {
      const stan = { ...(data?.stan || lastLicenseStatus || {}) };
      if (data?.powod) stan.powod = data.powod;
      renderLicenseStatus(stan, { komunikat: data?.error });
      
      
      if (data?.powod && data.powod !== "ZLE_DANE" && data.powod !== "LOGOWANIE_WYMAGANE") {
        setLicenseFormVisible(false);
      }
      showToast(data?.error || "Nie udało się zapisać danych logowania", "warning");
      return;
    }
    renderLicenseStatus(data);
    setLicenseFormVisible(false);
    showToast(data?.nazwa ? `Zalogowano: ${data.nazwa}` : "Dane logowania zapisane", "success");
    if (data?.licencjaProgramu) renderLicenseGuard(data.licencjaProgramu);
    else void refreshLicenseGuard();
    void refreshApplicationUpdateStatus();
  } catch (error) {
    showToast(error?.message || "Nie udało się zapisać danych logowania", "warning");
  } finally {
    elements.licenseSave.disabled = false;
  }
}

async function removeLicenseCredentials() {
  if (!window.confirm("Usunąć zapisany login i hasło do aktualizacji? Program przestanie pobierać nowe wersje.")) return;
  try {
    const response = await apiFetch("/api/licencja/usun", {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: "{}",
    });
    const data = await response.json();
    if (!response.ok) throw new Error(data?.error || "Nie udało się usunąć danych logowania.");
    elements.licenseLogin.value = "";
    renderLicenseStatus(data);
    setLicenseFormVisible(false);
    showToast("Dane logowania usunięte", "success");
    void refreshLicenseGuard();
    void refreshApplicationUpdateStatus();
  } catch (error) {
    showToast(error?.message || "Nie udało się usunąć danych logowania", "warning");
  }
}

function renderApplicationUpdateStatus(status) {
  const currentVersion = status?.currentVersion || "?";
  const latestVersion = status?.latestVersion || currentVersion;
  if (status?.licencja) {
    renderLicenseStatus(status.licencja, { komunikat: status.licencja.komunikat || "" });
  }
  if (status?.licencja?.blad && !status?.pending) {
    elements.applicationUpdateRow.dataset.state = "current";
    elements.applicationUpdateStatus.textContent = `Zainstalowana wersja ${currentVersion}`;
    elements.applicationUpdateDetails.textContent = status.licencja.skonfigurowana
      ? "Sprawdzanie nowych wersji wróci, gdy dostęp do aktualizacji będzie aktywny."
      : "Zaloguj się powyżej, żeby sprawdzać i pobierać nowe wersje.";
    elements.downloadApplicationUpdate.textContent = "Brak dostępu";
    elements.downloadApplicationUpdate.disabled = true;
    return;
  }
  if (status?.pending) {
    elements.applicationUpdateRow.dataset.state = "pending";
    elements.applicationUpdateStatus.textContent = `Aktualizacja ${latestVersion} jest gotowa do instalacji`;
    elements.applicationUpdateDetails.textContent = `Pobrano ${Number(status.fileCount || 0)} plików. Zamknij aplikację i uruchom ją ponownie.`;
    elements.downloadApplicationUpdate.textContent = "Oczekuje na restart";
    elements.downloadApplicationUpdate.disabled = true;
    return;
  }
  if (status?.updateAvailable) {
    elements.applicationUpdateRow.dataset.state = "available";
    elements.applicationUpdateStatus.textContent = `Dostępna aktualizacja ${latestVersion}`;
    elements.applicationUpdateDetails.textContent = status.notes
      ? `${status.notes} • Zainstalowana wersja: ${currentVersion}`
      : `Do pobrania: ${Number(status.fileCount || 0)} plików • Zainstalowana wersja: ${currentVersion}`;
    elements.downloadApplicationUpdate.textContent = "Pobierz aktualizację";
    elements.downloadApplicationUpdate.disabled = false;
    return;
  }
  elements.applicationUpdateRow.dataset.state = "current";
  elements.applicationUpdateStatus.textContent = `Masz najnowszą wersję ${currentVersion}`;
  elements.applicationUpdateDetails.textContent = "Brak nowszych plików do pobrania.";
  elements.downloadApplicationUpdate.textContent = "Brak aktualizacji";
  elements.downloadApplicationUpdate.disabled = true;
}

function renderApplicationUpdateError(message) {
  elements.applicationUpdateRow.dataset.state = "error";
  elements.applicationUpdateStatus.textContent = "Nie udało się sprawdzić aktualizacji";
  elements.applicationUpdateDetails.textContent = message || "Sprawdź połączenie z internetem i spróbuj ponownie.";
  elements.downloadApplicationUpdate.textContent = "Spróbuj ponownie";
  elements.downloadApplicationUpdate.disabled = false;
}

async function refreshApplicationUpdateStatus() {
  elements.applicationUpdateRow.dataset.state = "checking";
  elements.applicationUpdateStatus.textContent = "Sprawdzanie dostępności aktualizacji…";
  elements.applicationUpdateDetails.textContent = "";
  elements.downloadApplicationUpdate.textContent = "Sprawdzanie…";
  elements.downloadApplicationUpdate.disabled = true;
  try {
    const response = await apiFetch("/api/update/status", { cache: "no-store" });
    const data = await response.json();
    if (!response.ok) throw new Error(data?.error || "Nie udało się sprawdzić aktualizacji.");
    renderApplicationUpdateStatus(data);
  } catch (error) {
    renderApplicationUpdateError(error?.message);
  }
}

async function downloadApplicationUpdate() {
  elements.applicationUpdateRow.dataset.state = "checking";
  elements.applicationUpdateStatus.textContent = "Pobieranie i sprawdzanie aktualizacji…";
  elements.applicationUpdateDetails.textContent = "Nie zamykaj aplikacji do zakończenia pobierania.";
  elements.downloadApplicationUpdate.textContent = "Pobieranie…";
  elements.downloadApplicationUpdate.disabled = true;
  try {
    const response = await apiFetch("/api/update/prepare", {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: "{}",
    });
    const data = await response.json();
    if (!response.ok) {
      
      
      if (data?.licencja) {
        renderLicenseStatus(data.licencja, { komunikat: data?.error });
        showToast(data?.error || "Nie udało się pobrać aktualizacji", "warning");
        await refreshApplicationUpdateStatus();
        return;
      }
      throw new Error(data?.error || "Nie udało się pobrać aktualizacji.");
    }
    renderApplicationUpdateStatus(data);
    if (data?.pending) {
      showToast(`Aktualizacja ${data.latestVersion} została pobrana. Uruchom aplikację ponownie.`, "success");
    } else {
      showToast("Masz już najnowszą wersję aplikacji", "success");
    }
  } catch (error) {
    renderApplicationUpdateError(error?.message);
    showToast(error?.message || "Nie udało się pobrać aktualizacji", "warning");
  }
}







function openSettingsDialog() {
  hideInsurerSettingsPopup();
  settingsOpeningTheme = document.documentElement.dataset.theme === "dark" ? "dark" : "light";
  settingsOpeningFontSize = normalizeUiFontSize(document.documentElement.dataset.fontSize);
  settingsOpeningShowAppearanceDock = uiSettings.showAppearanceDock !== false;
  settingsOpeningShowStartDateInput = uiSettings.showStartDateInput === true;
  settingsOpeningShowUsageGuide = uiSettings.showUsageGuide !== false;
  syncSettingsDialogFromUi();
  setSettingsTab("application", { resetScroll: false });
  resetEntryOrganizerSettingsSummary();
  updateDeletedRecordsSettingsSummary();
  renderAgencySeedPicker();
  refreshAgencyExportPanel();
  elements.settingsDialog.showModal();
  setLicenseFormVisible(false);
  void refreshLicenseStatus();
  void refreshApplicationUpdateStatus();
  
  
}

function syncSettingsDialogFromUi() {
  pendingSettingsTheme = uiSettings.theme === "dark" ? "dark" : "light";
  pendingSettingsFontSize = normalizeUiFontSize(uiSettings.fontSize);
  pendingShowAppearanceDock = uiSettings.showAppearanceDock !== false;
  pendingShowStartDateInput = uiSettings.showStartDateInput === true;
  pendingShowUsageGuide = uiSettings.showUsageGuide !== false;
  pendingLogoDataUrl = uiSettings.logoDataUrl || "";
  pendingDatabaseName = normalizeDatabaseName(uiSettings.databaseName);
  pendingInsurerSettings = normalizeInsurerSettings(uiSettings.insurers).map((insurer) => ({ ...insurer }));
  const agencyPrintDetails = normalizeAgencyPrintDetails(uiSettings.agencyPrintDetails);
  elements.agencyPrintName.value = agencyPrintDetails.name;
  elements.agencyPrintAddress.value = agencyPrintDetails.address;
  elements.agencyPrintEmail.value = agencyPrintDetails.email;
  elements.agencyPrintPhone.value = agencyPrintDetails.phone;
  elements.wartaUsernameSetting.value = uiSettings.calculatorAccounts?.warta?.username || "";
  elements.generaliUsernameSetting.value = uiSettings.calculatorAccounts?.generali?.username || "";
  elements.mtuUsernameSetting.value = uiSettings.calculatorAccounts?.mtu?.username || "";
  elements.hestiaUsernameSetting.value = uiSettings.calculatorAccounts?.hestia?.username || "";
  elements.trastiUsernameSetting.value = uiSettings.calculatorAccounts?.trasti?.username || "";
  elements.wienerUsernameSetting.value = uiSettings.calculatorAccounts?.wiener?.username || "";
  elements.compensaUsernameSetting.value = uiSettings.calculatorAccounts?.compensa?.username || "";
  elements.allianzUsernameSetting.value = uiSettings.calculatorAccounts?.allianz?.username || "";
  elements.inslyUsernameSetting.value = uiSettings.calculatorAccounts?.insly?.username || "";
  elements.pzuUsernameSetting.value = uiSettings.calculatorAccounts?.pzu?.username || "";
  resetWartaPasswordEditor();
  resetGeneraliPasswordEditor();
  resetMtuPasswordEditor();
  resetHestiaPasswordEditor();
  resetTrastiPasswordEditor();
  resetWienerPasswordEditor();
  resetCompensaPasswordEditor();
  resetAllianzPasswordEditor();
  resetInslyPasswordEditor();
  resetPzuPasswordEditor();
  updateWartaCredentialHint();
  updateWartaNavigationHint();
  updateGeneraliCredentialHint();
  updateGeneraliNavigationHint();
  updateMtuCredentialHint();
  updateMtuNavigationHint();
  updateHestiaCredentialHint();
  updateTrastiCredentialHint();
  updateTrastiNavigationHint();
  updateWienerCredentialHint();
  updateWienerNavigationHint();
  updateCompensaCredentialHint();
  updateCompensaNavigationHint();
  updateAllianzCredentialHint();
  updateInslyCredentialHint();
  updatePzuCredentialHint();
  elements.settingsLogoPreview.src = pendingLogoDataUrl || DEFAULT_LOGO_SRC;
  elements.settingsDatabaseName.value = pendingDatabaseName;
  elements.settingsLogoInput.value = "";
  showSettingsLogoMessage("");
  setInsurerSettingsError();
  elements.addInsurerForm.reset();
  renderInsurerSettings();
  globalThis.SekagentRadio?.syncSettingsForm(uiSettings.radio);
  elements.showAppearanceDockSetting.checked = pendingShowAppearanceDock;
  elements.showStartDateInputSetting.checked = pendingShowStartDateInput;
  elements.showUsageGuideSetting.checked = pendingShowUsageGuide;
  updateThemeChoices();
  updateFontSizeChoices();
}

function closeSettingsDialog() {
  hideInsurerSettingsPopup();
  applyTheme(settingsOpeningTheme);
  applyFontSize(settingsOpeningFontSize);
  applyAppearanceDockSetting(settingsOpeningShowAppearanceDock);
  applyStartDateInputSetting(settingsOpeningShowStartDateInput);
  applyUsageGuideSetting(settingsOpeningShowUsageGuide);
  resetWartaPasswordEditor();
  resetGeneraliPasswordEditor();
  resetMtuPasswordEditor();
  resetHestiaPasswordEditor();
  resetTrastiPasswordEditor();
  elements.settingsDialog.close();
}

function setQuoteCalculatorError(message = "") {
  elements.quoteCalculatorError.textContent = message;
  elements.quoteCalculatorError.hidden = !message;
}

function normalizeQuoteRegistration(value) {
  return String(value ?? "")
    .toUpperCase()
    .replace(/[^A-Z0-9]/g, "")
    .slice(0, 12);
}

function normalizeQuotePesel(value) {
  return String(value ?? "").replace(/\D/g, "").slice(0, 11);
}



function getQuotePolicyPeriodTime(policy) {
  const endTime = parseLocalDate(policy?.validUntil)?.getTime();
  if (Number.isFinite(endTime)) return endTime;
  const startTime = parseLocalDate(policy?.validFrom)?.getTime();
  return Number.isFinite(startTime) ? startTime : null;
}

function compareQuotePolicyRecency(left, right) {
  const leftTime = getQuotePolicyPeriodTime(left);
  const rightTime = getQuotePolicyPeriodTime(right);
  if (leftTime !== rightTime) {
    if (leftTime === null) return 1;
    if (rightTime === null) return -1;
    return rightTime - leftTime;
  }
  return (Number(right?.createdAt) || 0) - (Number(left?.createdAt) || 0);
}

function sortQuotePolicyRecords(records) {
  return [...records].sort(compareQuotePolicyRecency);
}

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


function isQuoteRecordOfOtherClient(policy, pesel) {
  const digits = String(policy?.identityNumber ?? "").replace(/\D/g, "");
  if (!digits) return false;
  return digits !== pesel;
}

function findQuoteRegistrationRecords(registration) {
  const normalizedRegistration = normalizeQuoteRegistration(registration);
  if (normalizedRegistration.length < 4) return [];
  return sortQuotePolicyRecords(policies.filter((policy) => (
    normalizeQuoteRegistration(policy?.registration) === normalizedRegistration
  )));
}






let quoteIdentityIndexCache = null;

function getQuoteIdentityIndex() {
  const cached = quoteIdentityIndexCache;
  if (cached
    && cached.sourcePolicies === policies
    && cached.policyCount === policies.length
    && cached.sourceLinks === clientAccountLinks
    && cached.linkCount === clientAccountLinks.length) {
    return cached;
  }
  const policyEntries = [];
  const entriesByKey = new Map();
  policies.forEach((policy, order) => {
    const identityPairs = [];
    getClientProfileIdentityValues(policy).forEach((value) => {
      const key = getClientProfileIdentityKey(value);
      if (getIdentityNumberType(key)) identityPairs.push([key, value]);
    });
    if (identityPairs.length === 0) return;
    const entry = { policy, order, keys: identityPairs.map(([key]) => key), identityPairs };
    policyEntries.push(entry);
    entry.keys.forEach((key) => {
      const bucket = entriesByKey.get(key);
      if (bucket) bucket.push(entry);
      else entriesByKey.set(key, [entry]);
    });
  });
  const index = {
    sourcePolicies: policies,
    policyCount: policies.length,
    sourceLinks: clientAccountLinks,
    linkCount: clientAccountLinks.length,
    policyEntries,
    entriesByKey,
    accountKeysByDigits: new Map(),
    equivalentKeysByDigits: new Map(),
  };
  quoteIdentityIndexCache = index;
  Promise.resolve().then(() => {
    if (quoteIdentityIndexCache === index) quoteIdentityIndexCache = null;
  });
  return index;
}


function collectQuoteIdentityIndexEntries(index, identityKeys) {
  const matched = new Set();
  identityKeys.forEach((key) => {
    const bucket = index.entriesByKey.get(key);
    if (bucket) bucket.forEach((entry) => matched.add(entry));
  });
  return [...matched].sort((left, right) => left.order - right.order);
}




function expandQuoteIdentityKeysWithAccounts(identityKeys, index = getQuoteIdentityIndex()) {
  index.policyEntries.forEach((entry) => {
    if (entry.keys.some((key) => identityKeys.has(key))) {
      entry.keys.forEach((key) => identityKeys.add(key));
    }
  });
}

function expandQuoteIdentityKeysWithLinks(identityKeys) {
  clientAccountLinks.forEach((link) => {
    const linkKeys = [...link.personKeys, ...link.companyKeys];
    if (linkKeys.some((key) => identityKeys.has(key))) {
      linkKeys.forEach((key) => identityKeys.add(key));
    }
  });
}



function getQuoteAccountIdentityKeys(identity) {
  const digits = normalizeQuotePesel(identity);
  if (!getIdentityNumberType(digits)) return null;
  const index = getQuoteIdentityIndex();
  let identityKeys = index.accountKeysByDigits.get(digits);
  if (!identityKeys) {
    identityKeys = new Set([digits]);
    expandQuoteIdentityKeysWithAccounts(identityKeys, index);
    index.accountKeysByDigits.set(digits, identityKeys);
  }
  return new Set(identityKeys);
}

function getQuoteEquivalentIdentityKeys(identity) {
  const digits = normalizeQuotePesel(identity);
  if (!getIdentityNumberType(digits)) return null;
  const index = getQuoteIdentityIndex();
  let identityKeys = index.equivalentKeysByDigits.get(digits);
  if (!identityKeys) {
    identityKeys = getQuoteAccountIdentityKeys(digits);
    expandQuoteIdentityKeysWithLinks(identityKeys);
    expandQuoteIdentityKeysWithAccounts(identityKeys, index);
    index.equivalentKeysByDigits.set(digits, identityKeys);
  }
  return new Set(identityKeys);
}

function findQuoteIdentityRecords(identity) {
  const identityKeys = getQuoteAccountIdentityKeys(identity);
  if (!identityKeys) return [];
  const entries = collectQuoteIdentityIndexEntries(getQuoteIdentityIndex(), identityKeys);
  return sortQuotePolicyRecords(entries.map((entry) => entry.policy));
}






function buildQuoteRecordSources(registration, pesel) {
  const normalizedPesel = normalizeQuotePesel(pesel);
  const identityType = getIdentityNumberType(normalizedPesel);
  const hasIdentity = Boolean(identityType);
  const equivalentKeys = hasIdentity ? getQuoteEquivalentIdentityKeys(normalizedPesel) : null;
  const isOwnRecord = (policy) => {
    const digits = String(policy?.identityNumber ?? "").replace(/\D/g, "");
    return Boolean(digits) && equivalentKeys.has(digits);
  };
  const isOtherClientRecord = (policy) => {
    const digits = String(policy?.identityNumber ?? "").replace(/\D/g, "");
    return Boolean(digits) && !equivalentKeys.has(digits);
  };
  const registrationRecords = findQuoteRegistrationRecords(registration);
  const ownRegistrationRecords = hasIdentity ? registrationRecords.filter(isOwnRecord) : [];
  const anonymousRegistrationRecords = hasIdentity
    ? registrationRecords.filter((policy) => !isOwnRecord(policy) && !isOtherClientRecord(policy))
    : registrationRecords;
  const otherClientRegistrationRecords = hasIdentity
    ? registrationRecords.filter(isOtherClientRecord)
    : [];
  const identityRecords = hasIdentity ? findQuoteIdentityRecords(normalizedPesel) : [];
  
  
  
  const vehicleSold = registrationRecords.some((policy) => policy?.vehicleSold === true);
  
  
  const vehicleSources = [
    ...ownRegistrationRecords,
    ...anonymousRegistrationRecords,
    ...otherClientRegistrationRecords,
  ];
  
  
  
  
  const clientSources = hasIdentity
    ? identityRecords
    : registrationRecords;
  return {
    vehicleSources,
    clientSources,
    registrationKnown: registrationRecords.length > 0,
    
    ownerConflict: !vehicleSold
      && hasIdentity
      && registrationRecords.length > 0
      && ownRegistrationRecords.length === 0
      && anonymousRegistrationRecords.length === 0,
    
    clientFromOtherVehicle: hasIdentity
      && identityRecords.length > 0
      && ownRegistrationRecords.length === 0,
    
    
    vehicleOfOtherClient: !vehicleSold
      && hasIdentity
      && ownRegistrationRecords.length === 0
      && otherClientRegistrationRecords.length > 0,
    
    clientKnownByPesel: identityRecords.length > 0,
    vehicleSold,
    identityType,
  };
}

function findStoredVinForQuote(registration, pesel) {
  const { vehicleSources } = buildQuoteRecordSources(registration, pesel);
  const source = vehicleSources.find((policy) => normalizeVehicleIdentifier(policy?.vin));
  return normalizeVehicleIdentifier(source?.vin);
}

const VEHICLE_MAKE_NAMES = [
  "ALFA ROMEO", "LAND ROVER", "MERCEDES-BENZ", "MERCEDES BENZ", "HARLEY-DAVIDSON",
  "AUDI", "BMW", "CHEVROLET", "CHRYSLER", "CITROEN", "CUPRA", "DACIA", "DAEWOO", "DAF",
  "DODGE", "DUCATI", "FIAT", "FORD", "HONDA", "HYUNDAI", "ISUZU", "IVECO", "JAGUAR",
  "JEEP", "JUNAK", "KAWASAKI", "KIA", "KTM", "LANCIA", "LEXUS", "MAN", "MAZDA",
  "MERCEDES", "MINI", "MITSUBISHI", "NISSAN", "OPEL", "PEUGEOT", "PIAGGIO", "PORSCHE",
  "RENAULT", "ROMET", "SAAB", "SEAT", "SKODA", "SMART", "SSANGYONG", "SUBARU", "SUZUKI",
  "TESLA", "TOYOTA", "TRIUMPH", "VOLKSWAGEN", "VOLVO", "YAMAHA", "VW",
];

const VEHICLE_MODEL_STOP_WORDS = new Set([
  "OC", "AC", "NNW", "ASSISTANCE", "POLISA", "UBEZPIECZENIE", "UBEZPIECZENIA", "SKLADKA",
  "SKŁADKA", "PLN", "ZL", "ZŁ", "ROK", "NR", "VIN", "PESEL", "REJ", "KOMUNIKACYJNE",
  "POJAZD", "POJAZDU", "SAMOCHOD", "SAMOCHÓD", "OSOBOWY", "RYZYKA", "PAKIET", "Z", "O", "W",
]);



function extractVehicleMakeModelFromText(text) {
  const haystack = ` ${String(text || "").toUpperCase().replace(/\s+/g, " ")} `;
  for (const makeName of VEHICLE_MAKE_NAMES) {
    const position = haystack.indexOf(` ${makeName} `);
    if (position < 0) continue;
    const after = haystack.slice(position + makeName.length + 2).trim();
    const modelTokens = [];
    for (const token of after.split(" ").slice(0, 2)) {
      const cleaned = token.replace(/[^0-9A-ZĄĆĘŁŃÓŚŹŻ.-]/g, "");
      if (cleaned.length < 2 && !/^\d$/.test(cleaned)) break;
      if (VEHICLE_MODEL_STOP_WORDS.has(cleaned)) break;
      if (/^\d{4}$/.test(cleaned) && Number(cleaned) > 1950) break;
      modelTokens.push(cleaned);
    }
    return {
      make: makeName === "VW" ? "VOLKSWAGEN" : makeName.replace("MERCEDES BENZ", "MERCEDES-BENZ"),
      model: modelTokens.join(" "),
    };
  }
  return null;
}

const QUOTE_CLIENT_FIELD_NAMES = [
  "clientName", "identityNumber", "clientMaidenName", "clientAddress", "clientPostalCode",
  "clientPhone", "clientEmail", "contact", "driverLicenseDate",
];

const QUOTE_VEHICLE_FIELD_NAMES = [
  "insurer", "policyNumber", "vehicleMake", "vehicleModel", "vehicleType", "vin", "firstRegistrationDate",
  "productionYear", "fuelType", "seats", "grossWeight",
  "engineCapacity", "enginePower", "mileage", "premium", "validFrom", "validUntil",
];

function pickQuoteFieldValue(records, fieldName) {
  const source = records.find((record) => String(record?.[fieldName] ?? "").trim());
  return source ? String(source[fieldName]).trim() : "";
}






const QUOTE_CLIENT_NAME_ORDER_BY_INSURER = new Map([
  ["warta", "last-first"],
  ["trasti", "first-last"],
]);

function splitQuoteClientName(clientSources) {
  const source = clientSources.find((record) => String(record?.clientName ?? "").trim());
  if (!source) return null;
  const order = QUOTE_CLIENT_NAME_ORDER_BY_INSURER.get(String(source.insurer || "").trim().toLowerCase());
  if (!order) return null;
  const parts = String(source.clientName).trim().split(/\s+/);
  
  
  if (parts.length !== 2 || parts.some((part) => /[\d.]/.test(part))) return null;
  return order === "last-first"
    ? { firstName: parts[1], lastName: parts[0] }
    : { firstName: parts[0], lastName: parts[1] };
}

function mergeQuoteInfoFromSources(clientSources, vehicleSources) {
  if (clientSources.length === 0 && vehicleSources.length === 0) return null;
  const merged = {};
  QUOTE_CLIENT_FIELD_NAMES.forEach((fieldName) => {
    merged[fieldName] = pickQuoteFieldValue(clientSources, fieldName);
  });
  QUOTE_VEHICLE_FIELD_NAMES.forEach((fieldName) => {
    merged[fieldName] = pickQuoteFieldValue(vehicleSources, fieldName);
  });
  merged.clientPostalCode = normalizeClientPostalCode(merged.clientPostalCode)
    || extractClientPostalCode(merged.clientAddress);
  const clientNameParts = splitQuoteClientName(clientSources);
  if (clientNameParts) {
    merged.clientFirstName = clientNameParts.firstName;
    merged.clientLastName = clientNameParts.lastName;
  }
  if (!merged.vehicleMake) {
    const textPool = vehicleSources
      .map((record) => `${record?.description || ""}\n${record?.riskSummary || ""}`)
      .join("\n");
    const extracted = extractVehicleMakeModelFromText(textPool);
    if (extracted) {
      merged.vehicleMake = extracted.make;
      if (!merged.vehicleModel && extracted.model) merged.vehicleModel = extracted.model;
    }
  }
  return merged;
}

function buildQuoteClientInfo(registration, pesel) {
  const sources = buildQuoteRecordSources(registration, pesel);
  const merged = mergeQuoteInfoFromSources(sources.clientSources, sources.vehicleSources);
  if (!merged) return null;
  return {
    merged,
    newestRecord: sources.vehicleSources[0] || sources.clientSources[0] || null,
    clientRecord: sources.clientSources[0] || null,
    vehicleRecord: sources.vehicleSources[0] || null,
    registrationKnown: sources.registrationKnown,
    ownerConflict: sources.ownerConflict,
    clientFromOtherVehicle: sources.clientFromOtherVehicle,
    vehicleOfOtherClient: sources.vehicleOfOtherClient,
    clientKnownByPesel: sources.clientKnownByPesel,
    vehicleSold: sources.vehicleSold,
    identityType: sources.identityType,
  };
}

function moveQuoteDateByCalendarYear(value) {
  const sourceDate = parseLocalDate(value);
  if (!sourceDate) return null;
  const targetYear = sourceDate.getFullYear() + 1;
  const month = sourceDate.getMonth();
  const lastDayInMonth = new Date(targetYear, month + 1, 0).getDate();
  return new Date(targetYear, month, Math.min(sourceDate.getDate(), lastDayInMonth));
}

function buildNextQuoteInsurancePeriod(merged) {
  const currentStart = parseLocalDate(merged?.validFrom);
  const currentEnd = parseLocalDate(merged?.validUntil);
  let nextStart = moveQuoteDateByCalendarYear(merged?.validFrom);
  let nextEnd = moveQuoteDateByCalendarYear(merged?.validUntil);

  if (!nextStart && currentEnd) {
    nextStart = new Date(currentEnd);
    nextStart.setDate(nextStart.getDate() + 1);
  }
  if (!nextEnd && nextStart) {
    nextEnd = calculateEndDate(formatDateForInput(nextStart));
  }
  if (!nextStart || !nextEnd) return "";

  
  
  if (nextEnd.getTime() < nextStart.getTime()
    || (!currentStart && currentEnd)) {
    nextEnd = calculateEndDate(formatDateForInput(nextStart));
  }
  return `${formatDate(formatDateForInput(nextStart))} – ${formatDate(formatDateForInput(nextEnd))}`;
}




function quoteNumericCopyValue(value) {
  const match = String(value ?? "").trim().match(/^(\d(?:[\d\s.,]*\d)?)/);
  return match ? match[1].replace(/\s+/g, "") : "";
}




function buildQuoteIdentityNumberRows(baseIdentity) {
  const baseValue = String(baseIdentity ?? "").trim();
  if (!baseValue) return [];
  const baseKey = getClientProfileIdentityKey(baseValue);
  const baseType = getIdentityNumberType(baseKey);
  if (!baseType) return [["PESEL / NIP / REGON", baseValue]];
  const equivalentKeys = getQuoteEquivalentIdentityKeys(baseKey);
  const valuesByType = new Map([[baseType, baseValue]]);
  collectQuoteIdentityIndexEntries(getQuoteIdentityIndex(), equivalentKeys).forEach((entry) => {
    entry.identityPairs.forEach(([key, value]) => {
      const type = getIdentityNumberType(key);
      if (!type || valuesByType.has(type) || !equivalentKeys.has(key)) return;
      valuesByType.set(type, String(value).trim());
    });
  });
  
  equivalentKeys.forEach((key) => {
    const type = getIdentityNumberType(key);
    if (type && !valuesByType.has(type)) valuesByType.set(type, key);
  });
  return ["PESEL", "NIP", "REGON"]
    .filter((type) => valuesByType.has(type))
    .map((type) => [type, valuesByType.get(type)]);
}





function resolveQuotePeselForPolicy(policy) {
  const digits = String(policy?.identityNumber ?? "").replace(/\D/g, "");
  const type = getIdentityNumberType(digits);
  if (type === "PESEL") return digits;
  if (!type) return "";
  const equivalentKeys = getQuoteEquivalentIdentityKeys(digits);
  if (!equivalentKeys) return "";
  for (const key of equivalentKeys) {
    if (getIdentityNumberType(key) === "PESEL") return key;
  }
  return "";
}

function buildQuoteClientInfoRows(merged) {
  const rawContact = String(merged.contact ?? "").trim();
  const phone = normalizeClientPhone(merged.clientPhone) || extractClientPhone(rawContact);
  const email = normalizeClientEmail(merged.clientEmail) || extractClientEmail(rawContact);
  const contactNotes = rawContact
    .split("\n")
    .map((part) => part
      .replace(/[\w.!#$%&'*+/=?^`{|}~-]+@[a-z0-9-]+(?:\.[a-z0-9-]+)+/gi, "")
      .replace(/(?:\+?\d[\d\s()-]{7,}\d)/g, "")
      .replace(/^\s*(?:(?:Telefon|Tel\.?|E-?mail)\s*:?\s*)+/i, "")
      .replace(/^[\s·,;|/-]+|[\s·,;|/-]+$/g, "")
      .trim())
    .filter(Boolean)
    .join(" · ");
  const previousPolicy = [merged.insurer, merged.policyNumber].filter(Boolean).join(" ");
  const vehicle = [
    [merged.vehicleMake, merged.vehicleModel].filter(Boolean).join(" "),
    merged.vehicleType,
  ].filter(Boolean).join(" · ");
  return [
    ["Klient", merged.clientName],
    ["Adres", merged.clientAddress],
    ["Kod pocztowy", merged.clientPostalCode],
    ...buildQuoteIdentityNumberRows(merged.identityNumber),
    ["Nazwisko rodowe", merged.clientMaidenName],
    ["Telefon", phone, "plain"],
    ["E-mail", email, "email"],
    ["Kontakt", contactNotes],
    ["Pojazd", vehicle],
    ["VIN", merged.vin],
    ["Pierwsza rejestracja", merged.firstRegistrationDate ? formatDate(merged.firstRegistrationDate) : ""],
    ["Rok produkcji", merged.productionYear],
    ["Paliwo", merged.fuelType],
    ["Pojemność silnika", merged.engineCapacity, "copy", quoteNumericCopyValue(merged.engineCapacity)],
    ["Moc silnika", merged.enginePower, "copy", quoteNumericCopyValue(merged.enginePower)],
    ["Liczba miejsc", merged.seats],
    ["DMC", merged.grossWeight, "copy", quoteNumericCopyValue(merged.grossWeight)],
    ["Przebieg", merged.mileage, "copy", quoteNumericCopyValue(merged.mileage)],
    ["Prawo jazdy od", formatDriverLicenseDateDisplay(merged.driverLicenseDate)],
    ["Ostatnia polisa", previousPolicy],
    ["Poprzednia składka", merged.premium ? `${merged.premium} zł` : "", "copy", quoteNumericCopyValue(merged.premium)],
    ["Koniec ochrony", merged.validUntil ? formatDate(merged.validUntil) : ""],
  ].filter(([, value]) => String(value ?? "").trim());
}

function formatQuoteSourcePolicyLabel(record) {
  const policyLabel = [record.insurer, record.policyNumber].filter(Boolean).join(" ") || "bez numeru";
  const endDate = record.validUntil ? formatDate(record.validUntil) : "";
  return `${policyLabel}${endDate && endDate !== "-" ? ` (do ${endDate})` : ""}`;
}

function buildQuoteClientInfoSourceLabel(info) {
  
  
  if (info.vehicleRecord && info.clientRecord && info.vehicleRecord !== info.clientRecord) {
    return `Pojazd z polisy: ${formatQuoteSourcePolicyLabel(info.vehicleRecord)} · `
      + `Klient z polisy: ${formatQuoteSourcePolicyLabel(info.clientRecord)}`;
  }
  const record = info.vehicleRecord || info.clientRecord || info.newestRecord;
  if (!record) return "";
  return `Z polisy: ${formatQuoteSourcePolicyLabel(record)}`;
}

function buildQuoteClientInfoNote(info, registration) {
  if (info.vehicleSold) return "";
  if (info.vehicleOfOtherClient) {
    
    
    if (info.clientKnownByPesel) {
      if (info.identityType && info.identityType !== "PESEL") {
        return `Ten pojazd jest w bazie zapisany na inny numer niż wpisany ${info.identityType}. `
          + "Dane pojazdu i ostatniej polisy pochodzą z polis pojazdu, a dane klienta z polis wpisanego numeru. "
          + "Sprawdź, czy oba numery dotyczą tej samej sprawy.";
      }
      return "Ten pojazd jest w bazie zapisany na inną osobę niż wpisany PESEL. "
        + "Dane pojazdu i ostatniej polisy pochodzą z polis tej osoby, a dane klienta z polis wpisanego PESEL-u. "
        + "Sprawdź, czy oba numery dotyczą tej samej sprawy.";
    }
    return "Polisy tego numeru rejestracyjnego są w bazie zapisane na inną osobę. Dane klienta sprawdź ręcznie.";
  }
  
  
  if (!info.registrationKnown && String(registration || "").length >= 4) {
    return `Numeru ${registration} nie ma jeszcze w bazie. Poniżej dane klienta z jego ostatniej polisy.`;
  }
  return "";
}

function renderQuoteClientInfo() {
  const panel = elements.quoteClientInfoPanel;
  if (!panel) return;
  const registration = normalizeQuoteRegistration(elements.quoteRegistration.value);
  const pesel = normalizeQuotePesel(elements.quotePesel.value);
  const info = buildQuoteClientInfo(registration, pesel);
  const rows = info ? buildQuoteClientInfoRows(info.merged) : [];
  const hasRows = rows.length > 0;
  
  
  const offer = syncQuoteClientCardOffer(registration, pesel, info);
  const panelVisible = hasRows || Boolean(offer);
  panel.hidden = !panelVisible;
  elements.quoteCalculatorContent.classList.toggle("quote-calculator-content--with-info", panelVisible);
  elements.quoteCalculatorDialog.classList.toggle("quote-calculator-dialog--with-info", panelVisible);
  if (elements.quoteClientInfoTitle) {
    elements.quoteClientInfoTitle.textContent = hasRows ? "Dane z bazy polis" : "Klient spoza bazy polis";
  }
  if (elements.quoteClientInfoHint) elements.quoteClientInfoHint.hidden = !hasRows;
  if (!hasRows) {
    quoteClientInfoVehiclePolicyId = "";
    syncQuoteClientInfoActions();
    elements.quoteClientInfoList.replaceChildren();
    elements.quoteClientInfoSource.textContent = "";
    if (elements.quoteClientInfoNote) {
      elements.quoteClientInfoNote.textContent = "";
      elements.quoteClientInfoNote.hidden = true;
      elements.quoteClientInfoNote.classList.remove("quote-client-info-note--conflict");
    }
    return;
  }
  
  
  const vehiclePolicy = info.vehicleRecord && hasRegistrationNumber(info.vehicleRecord)
    ? info.vehicleRecord
    : null;
  quoteClientInfoVehiclePolicyId = String(vehiclePolicy?.id || "");
  syncQuoteClientInfoActions();
  elements.quoteClientInfoSource.textContent = buildQuoteClientInfoSourceLabel(info);
  if (elements.quoteClientInfoNote) {
    const note = buildQuoteClientInfoNote(info, registration);
    elements.quoteClientInfoNote.textContent = note;
    elements.quoteClientInfoNote.hidden = !note;
    elements.quoteClientInfoNote.classList.toggle(
      "quote-client-info-note--conflict",
      Boolean(note && info.vehicleOfOtherClient),
    );
  }
  elements.quoteClientInfoList.innerHTML = rows.map(([label, value, displayType = "copy", copyValue = ""]) => {
    let displayedValue;
    if (displayType === "email") {
      displayedValue = `<a class="quote-client-info-email" href="mailto:${escapeHtml(value)}">${escapeHtml(value)}</a>`;
    } else if (displayType === "plain") {
      displayedValue = `<span class="quote-client-info-text">${escapeHtml(value)}</span>`;
    } else {
      displayedValue = `<button type="button" class="quote-client-info-value" data-copy-value="${escapeHtml(copyValue || value)}" title="Kliknij, aby skopiować">${escapeHtml(value)}</button>`;
    }
    return `
      <div class="quote-client-info-item">
        <dt>${escapeHtml(label)}</dt>
        <dd>${displayedValue}</dd>
      </div>
    `;
  }).join("");
}

async function copyQuoteClientInfoValue(event) {
  const valueButton = event.target?.closest?.("[data-copy-value]");
  if (!valueButton) return;
  const value = String(valueButton.dataset.copyValue || "");
  if (!value) return;
  try {
    await navigator.clipboard.writeText(value);
    showToast(`Skopiowano: ${value.length > 40 ? `${value.slice(0, 40)}…` : value}`);
  } catch {
    showToast("Nie udało się skopiować do schowka", "error");
  }
}




let quoteClientInfoVehiclePolicyId = "";
let quoteClientInfoHistoryBusy = false;

function syncQuoteClientInfoActions() {
  if (!elements.quoteClientInfoActions) return;
  elements.quoteClientInfoActions.hidden = !quoteClientInfoVehiclePolicyId;
  const locked = quoteCalculationActive || quoteCancellationPending;
  elements.quoteClientInfoHistory.disabled = quoteClientInfoHistoryBusy || locked;
  elements.quoteClientInfoHistory.textContent = quoteClientInfoHistoryBusy ? "Pobieranie..." : "Historia pojazdu";
  elements.quoteClientInfoEdit.disabled = quoteClientInfoHistoryBusy || locked;
}




function openQuoteClientInfoVehicleEdit() {
  if (!quoteClientInfoVehiclePolicyId || quoteClientInfoHistoryBusy) return;
  if (quoteCalculationActive || quoteCancellationPending) return;
  openVehicleDetailsDialog(quoteClientInfoVehiclePolicyId);
}





async function fetchQuoteClientInfoVehicleHistory() {
  if (quoteClientInfoHistoryBusy || !quoteClientInfoVehiclePolicyId) return;
  if (quoteCalculationActive || quoteCancellationPending) return;
  const policy = policies.find((item) => item.id === quoteClientInfoVehiclePolicyId);
  if (!policy) {
    showToast("Nie znaleziono polisy pojazdu w bazie", "error");
    return;
  }
  const registration = normalizeVehicleIdentifier(policy.registration);
  const vin = normalizeVehicleIdentifier(policy.vin);
  const firstRegistrationDate = normalizeFirstRegistrationDate(policy.firstRegistrationDate);
  if (!registration || !vin || !firstRegistrationDate) {
    openVehicleDetailsDialog(policy.id);
    setVehicleDetailsHistoryMissingHighlights({ vin: !vin, firstRegistrationDate: !firstRegistrationDate });
    showToast(buildVehicleHistoryMissingMessage({ registration, vin, firstRegistrationDate }), "error");
    return;
  }
  quoteClientInfoHistoryBusy = true;
  syncQuoteClientInfoActions();
  let vehicleData = null;
  try {
    vehicleData = await requestVehicleHistoryData(policy);
  } catch (error) {
    quoteClientInfoHistoryBusy = false;
    syncQuoteClientInfoActions();
    showToast(error?.message || "Nie udało się pobrać danych z HistoriaPojazdu.gov.", "error");
    return;
  }
  const nextValues = buildVehicleHistoryValues(policy, vehicleData);
  if (Object.keys(nextValues).length === 0) {
    quoteClientInfoHistoryBusy = false;
    syncQuoteClientInfoActions();
    showToast("Dane pojazdu są już zgodne z HistoriaPojazdu.gov");
    return;
  }
  const groupPolicies = getSameClientVehiclePolicies(policy);
  const policyIds = (groupPolicies.length > 0 ? groupPolicies : [policy]).map((item) => item.id);
  let mutationSnapshots = new Map();
  const applyVehicleHistoryValues = () => {
    const currentPolicies = policyIds
      .map((policyId) => policies.find((item) => item.id === policyId))
      .filter(Boolean);
    if (currentPolicies.length === 0) return false;
    mutationSnapshots = captureClientProfilePolicySnapshots(currentPolicies.map((item) => item.id));
    currentPolicies.forEach((item) => {
      Object.assign(item, nextValues);
      item.updatedAt = Date.now();
    });
    return true;
  };
  try {
    if (!(await ensureWritableDataFile({ deferFreshnessCheck: true }))) return;
    if (!applyVehicleHistoryValues()) {
      showToast("Nie znaleziono polis pojazdu w bazie", "error");
      return;
    }
    saveStatusPopupSuccessText = "Dane pojazdu z HistoriaPojazdu.gov zapisane";
    if (!(await persistPolicies({
      reapplyAfterConflict: applyVehicleHistoryValues,
      reapplyFailureMessage: "Polisy pojazdu zmieniły się w nowszej bazie. Dane z HistoriaPojazdu.gov nie zostały zapisane.",
    }))) {
      restoreClientProfilePolicySnapshots(mutationSnapshots);
      markPoliciesRolledBack();
      render();
      return;
    }
    render();
    if (elements.clientProfileDialog.open) renderClientProfile();
    showToast(`Pojazd ${policy.registration}: dane uzupełnione z HistoriaPojazdu.gov`);
  } catch (error) {
    restoreClientProfilePolicySnapshots(mutationSnapshots);
    markPoliciesRolledBack();
    render();
    showToast(error?.message || "Nie udało się zapisać danych z HistoriaPojazdu.gov.", "error");
  } finally {
    quoteClientInfoHistoryBusy = false;
    
    renderQuoteClientInfo();
  }
}




const MANUAL_OVERLAY_CLIENT_FIELDS = new Set([
  "clientName",
  "identityNumber",
  "clientAddress",
  "clientPostalCode",
  "clientMaidenName",
  "clientPhone",
  "clientEmail",
  "driverLicenseDate",
]);
const MANUAL_OVERLAY_VEHICLE_FIELDS = new Set([
  "vehicleMake",
  "vehicleModel",
  "vehicleType",
  "vin",
  "firstRegistrationDate",
  "productionYear",
  "fuelType",
  "engineCapacity",
  "enginePower",
  "seats",
  "grossWeight",
  "mileage",
]);
let manualOverlayActionsBusy = false;

function normalizeManualOverlayFieldValue(fieldName, rawValue) {
  const value = String(rawValue ?? "").trim();
  if (!value) return "";
  if (fieldName === "clientName") {
    const compactName = value.replace(/\s+/g, " ").slice(0, 160);
    return compactName.length >= 2 ? compactName : "";
  }
  if (fieldName === "identityNumber") {
    const digits = value.replace(/\D/g, "");
    return getIdentityNumberType(digits) ? digits : "";
  }
  if (fieldName === "clientAddress") return normalizeClientAddress(value);
  if (fieldName === "clientPostalCode") return normalizeClientPostalCode(value);
  if (fieldName === "clientPhone") return normalizeClientPhone(value);
  if (fieldName === "clientEmail") return normalizeClientEmail(value);
  if (fieldName === "vin") return normalizeVehicleIdentifier(value);
  if (fieldName === "firstRegistrationDate") return normalizeFirstRegistrationDate(value);
  if (fieldName === "driverLicenseDate") return normalizeDriverLicenseDate(value);
  if (fieldName === "productionYear") {
    return value.match(/^(?:19|20)\d{2}$/)?.[0] || "";
  }
  if (["engineCapacity", "enginePower", "seats", "grossWeight", "mileage"].includes(fieldName)) {
    const numericValue = value.replace(/[^\d.,]/g, "").replace(",", ".");
    return /^\d+(?:\.\d+)?$/.test(numericValue) ? numericValue : "";
  }
  return normalizeVehicleDetail(value);
}

function buildManualOverlayVehicleInfo(registration, pesel) {
  const info = buildQuoteClientInfo(registration, pesel);
  if (!info) return null;
  return {
    ...info.merged,
    registration: normalizeQuoteRegistration(registration),
    driverLicenseDate: formatDriverLicenseDateDisplay(info.merged.driverLicenseDate),
  };
}

async function saveMissingManualOverlayField(request) {
  const fieldName = String(request?.fieldName || "");
  const isClientField = MANUAL_OVERLAY_CLIENT_FIELDS.has(fieldName);
  const isVehicleField = MANUAL_OVERLAY_VEHICLE_FIELDS.has(fieldName);
  if (!isClientField && !isVehicleField) {
    return { ok: false, error: "Tego pola nie można uzupełnić z pływającego okna." };
  }
  const nextValue = normalizeManualOverlayFieldValue(fieldName, request?.value);
  if (!nextValue) {
    return { ok: false, error: "Wpisz prawidłową wartość." };
  }
  const registration = normalizeQuoteRegistration(request?.registration);
  const pesel = normalizeQuotePesel(request?.pesel);
  const sources = buildQuoteRecordSources(registration, pesel);
  let targetPolicies = [];
  if (isClientField) {
    
    
    targetPolicies = getIdentityNumberType(pesel)
      ? sources.clientSources
      : sources.clientSources.slice(0, 1);
  } else {
    const anchorPolicy = sources.vehicleSources
      .find((record) => !isQuoteRecordOwnedByOtherClient(record, pesel))
      || null;
    if (anchorPolicy) {
      const groupPolicies = getSameClientVehiclePolicies(anchorPolicy);
      targetPolicies = groupPolicies.length > 0 ? groupPolicies : [anchorPolicy];
    }
  }
  const policyIds = [...new Set(targetPolicies.map((policy) => String(policy?.id || "")).filter(Boolean))];
  if (policyIds.length === 0) {
    return { ok: false, error: "Nie znaleziono rekordu, do którego można dopisać te dane." };
  }
  
  
  const existingValue = targetPolicies
    .map((policy) => String(policy?.[fieldName] ?? "").trim())
    .find(Boolean);
  if (existingValue) {
    return {
      ok: true,
      message: "To pole jest już uzupełnione w bazie.",
      vehicleInfo: buildManualOverlayVehicleInfo(registration, pesel),
    };
  }
  let mutationSnapshots = new Map();
  const applyMissingValue = () => {
    const currentPolicies = policyIds
      .map((policyId) => policies.find((policy) => policy.id === policyId))
      .filter(Boolean);
    if (currentPolicies.length === 0) return false;
    mutationSnapshots = captureClientProfilePolicySnapshots(currentPolicies.map((policy) => policy.id));
    let changed = false;
    currentPolicies.forEach((policy) => {
      if (String(policy?.[fieldName] ?? "").trim()) return;
      markImportedPolicyFieldsManuallyEdited(policy, { [fieldName]: nextValue });
      policy[fieldName] = nextValue;
      policy.updatedAt = Date.now();
      changed = true;
    });
    return changed;
  };
  try {
    if (!(await ensureWritableDataFile({ deferFreshnessCheck: true }))) {
      return { ok: false, error: "Nie udało się połączyć z plikiem bazy." };
    }
    if (!applyMissingValue()) {
      return {
        ok: true,
        message: "To pole jest już uzupełnione w bazie.",
        vehicleInfo: buildManualOverlayVehicleInfo(registration, pesel),
      };
    }
    saveStatusPopupSuccessText = "Brakujące dane zapisane";
    if (!(await persistPolicies({
      reapplyAfterConflict: applyMissingValue,
      reapplyFailureMessage: "Rekord zmienił się w nowszej bazie. Dane z pływającego okna nie zostały zapisane.",
    }))) {
      restoreClientProfilePolicySnapshots(mutationSnapshots);
      markPoliciesRolledBack();
      render();
      return { ok: false, error: "Nie udało się zapisać danych w bazie." };
    }
    render();
    if (elements.clientProfileDialog.open) renderClientProfile();
    if (elements.quoteCalculatorDialog.open) renderQuoteClientInfo();
    return {
      ok: true,
      message: "Dane zapisane w bazie Iseca.",
      vehicleInfo: buildManualOverlayVehicleInfo(registration, pesel),
    };
  } catch (error) {
    restoreClientProfilePolicySnapshots(mutationSnapshots);
    markPoliciesRolledBack();
    render();
    return { ok: false, error: error?.message || "Nie udało się zapisać danych w bazie." };
  }
}

async function saveManualOverlayVehicleHistory(request) {
  const registration = normalizeQuoteRegistration(request?.registration);
  const pesel = normalizeQuotePesel(request?.pesel);
  const sources = buildQuoteRecordSources(registration, pesel);
  const anchorPolicy = sources.vehicleSources
    .find((record) => !isQuoteRecordOwnedByOtherClient(record, pesel))
    || null;
  if (!anchorPolicy) return { ok: false, error: "Nie znaleziono pojazdu w bazie." };
  const normalizedRegistration = normalizeVehicleIdentifier(anchorPolicy.registration);
  const vin = normalizeVehicleIdentifier(anchorPolicy.vin);
  const firstRegistrationDate = normalizeFirstRegistrationDate(anchorPolicy.firstRegistrationDate);
  if (!normalizedRegistration || !vin || !firstRegistrationDate) {
    return {
      ok: false,
      error: buildVehicleHistoryMissingMessage({
        registration: normalizedRegistration,
        vin,
        firstRegistrationDate,
      }),
    };
  }
  let vehicleData;
  try {
    vehicleData = await requestVehicleHistoryData(anchorPolicy);
  } catch (error) {
    return { ok: false, error: error?.message || "Nie udało się pobrać danych z HistoriaPojazdu.gov." };
  }
  const nextValues = buildVehicleHistoryValues(anchorPolicy, vehicleData);
  if (Object.keys(nextValues).length === 0) {
    return {
      ok: true,
      message: "Dane są już zgodne z HistoriaPojazdu.gov.",
      vehicleInfo: buildManualOverlayVehicleInfo(registration, pesel),
    };
  }
  const groupPolicies = getSameClientVehiclePolicies(anchorPolicy);
  const policyIds = (groupPolicies.length > 0 ? groupPolicies : [anchorPolicy]).map((policy) => policy.id);
  let mutationSnapshots = new Map();
  const applyVehicleHistoryValues = () => {
    const currentPolicies = policyIds
      .map((policyId) => policies.find((policy) => policy.id === policyId))
      .filter(Boolean);
    if (currentPolicies.length === 0) return false;
    mutationSnapshots = captureClientProfilePolicySnapshots(currentPolicies.map((policy) => policy.id));
    currentPolicies.forEach((policy) => {
      Object.assign(policy, nextValues);
      policy.updatedAt = Date.now();
    });
    return true;
  };
  try {
    if (!(await ensureWritableDataFile({ deferFreshnessCheck: true }))) {
      return { ok: false, error: "Nie udało się połączyć z plikiem bazy." };
    }
    if (!applyVehicleHistoryValues()) return { ok: false, error: "Nie znaleziono pojazdu w bazie." };
    saveStatusPopupSuccessText = "Dane z HistoriaPojazdu.gov zapisane";
    if (!(await persistPolicies({
      reapplyAfterConflict: applyVehicleHistoryValues,
      reapplyFailureMessage: "Polisy pojazdu zmieniły się w nowszej bazie. Dane z HistoriaPojazdu.gov nie zostały zapisane.",
    }))) {
      restoreClientProfilePolicySnapshots(mutationSnapshots);
      markPoliciesRolledBack();
      render();
      return { ok: false, error: "Nie udało się zapisać danych z HistoriaPojazdu.gov." };
    }
    render();
    if (elements.clientProfileDialog.open) renderClientProfile();
    if (elements.quoteCalculatorDialog.open) renderQuoteClientInfo();
    return {
      ok: true,
      message: "Brakujące dane uzupełniono z HistoriaPojazdu.gov.",
      vehicleInfo: buildManualOverlayVehicleInfo(registration, pesel),
    };
  } catch (error) {
    restoreClientProfilePolicySnapshots(mutationSnapshots);
    markPoliciesRolledBack();
    render();
    return { ok: false, error: error?.message || "Nie udało się zapisać danych z HistoriaPojazdu.gov." };
  }
}

async function resolveManualOverlayAction(request, result) {
  try {
    await apiFetch(`/api/manual-quote/overlay-actions/${encodeURIComponent(request.id)}/resolve`, {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify(result),
    });
  } catch {
  }
}

function hasManualQuoteOverlaySession() {
  
  
  return quoteCalculationActive
    || activeQuoteBatch?.manualMode === true
    || [...quoteJobStates.values()].some((job) =>
      job?.manualMode === true
      || job?.status === "manual_ready"
      || job?.status === "manual_required");
}

async function processManualOverlayActions() {
  if (manualOverlayActionsBusy || !hasManualQuoteOverlaySession()) return;
  manualOverlayActionsBusy = true;
  try {
    const response = await apiFetch("/api/manual-quote/overlay-actions", { cache: "no-store" });
    if (!response.ok) return;
    const data = await response.json().catch(() => ({}));
    const requests = Array.isArray(data?.requests) ? data.requests : [];
    for (const request of requests) {
      let result;
      if (request?.type === "save_missing") {
        result = await saveMissingManualOverlayField(request);
      } else if (request?.type === "vehicle_history") {
        result = await saveManualOverlayVehicleHistory(request);
      } else {
        result = { ok: false, error: "Nieznana akcja pływającego okna." };
      }
      await resolveManualOverlayAction(request, result);
    }
  } catch {
  } finally {
    manualOverlayActionsBusy = false;
  }
}









const processedQuoteVehicleDataJobs = new Map();

function canonicalVehicleNumberValue(value) {
  const text = String(value ?? "").trim();
  const valueBeforeUnit = text.match(/(\d(?:[\d\s\u00a0\u202f.,']*\d)?)\s*(?:km|kg|cm)\b/i)?.[1];
  const leadingValue = text.match(/^\s*(\d(?:[\d\s\u00a0\u202f.,']*\d)?)/)?.[1];
  return String(valueBeforeUnit || leadingValue || "").replace(/\D/g, "");
}

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



function enginePowersMatchCepik(baseValue, cepikKilowatts) {
  const cepikNumber = Number(cepikKilowatts);
  if (!Number.isFinite(cepikNumber) || cepikNumber <= 0) return true;
  const parsed = parseEnginePowerDisplayValue(String(baseValue ?? "").trim());
  if (!parsed) {
    const baseNumber = canonicalVehicleNumberValue(baseValue);
    return Boolean(baseNumber) && baseNumber === String(cepikNumber);
  }
  const amount = Number(String(parsed.value).replace(",", "."));
  if (!Number.isFinite(amount)) return false;
  const baseKilowatts = parsed.unit === "kW" ? amount : amount / 1.35962;
  return Math.abs(baseKilowatts - cepikNumber) <= Math.max(1, cepikNumber * 0.02);
}

function buildQuoteCepikVehicleValues(policy, vehicleData) {
  const nextValues = {};
  const baseValueOf = (fieldName) => String(policy?.[fieldName] ?? "").trim();
  const isCalculatorInputField = (fieldName) =>
    vehicleData?.fieldSources?.[fieldName] === "calculator-input";
  const setValue = (fieldName, rawValue) => {
    const cleanValue = normalizeVehicleDetail(rawValue);
    
    
    
    if (isCalculatorInputField(fieldName) && baseValueOf(fieldName)) return;
    if (!cleanValue || baseValueOf(fieldName) === cleanValue) return;
    nextValues[fieldName] = cleanValue;
  };

  const cepikVin = normalizeVehicleIdentifier(vehicleData.vin);
  if (cepikVin && normalizeVehicleIdentifier(policy?.vin) !== cepikVin) setValue("vin", cepikVin);

  const cepikDate = normalizeFirstRegistrationDate(vehicleData.firstRegistrationDate);
  if (cepikDate && normalizeFirstRegistrationDate(policy?.firstRegistrationDate) !== cepikDate) {
    setValue("firstRegistrationDate", cepikDate);
  }

  const cepikYear = String(vehicleData.productionYear || "").trim().match(/^(?:19|20)\d{2}$/)?.[0] || "";
  const baseYear = baseValueOf("productionYear").match(/(?:19|20)\d{2}/)?.[0] || "";
  if (cepikYear && baseYear !== cepikYear) setValue("productionYear", cepikYear);

  const cepikFuel = String(vehicleData.fuelType || vehicleData.fuel || "").trim();
  if (cepikFuel && !baseValueOf("fuelType")) setValue("fuelType", cepikFuel);

  const cepikCapacity = canonicalVehicleNumberValue(vehicleData.engineCapacity);
  if (cepikCapacity && canonicalVehicleNumberValue(baseValueOf("engineCapacity")) !== cepikCapacity) {
    setValue("engineCapacity", `${cepikCapacity} cm³`);
  }

  const cepikPower = canonicalVehicleNumberValue(vehicleData.enginePower);
  if (cepikPower && isCalculatorInputField("enginePower")) {
    setValue("enginePower", vehicleData.enginePower);
  } else if (cepikPower && !enginePowersMatchCepik(baseValueOf("enginePower"), Number(cepikPower))) {
    setValue("enginePower", `${cepikPower} kW`);
  }

  const cepikWeight = canonicalVehicleNumberValue(vehicleData.grossWeight);
  if (cepikWeight && canonicalVehicleNumberValue(baseValueOf("grossWeight")) !== cepikWeight) {
    setValue("grossWeight", `${cepikWeight} kg`);
  }

  const cepikSeats = canonicalVehicleNumberValue(vehicleData.seats);
  if (cepikSeats && canonicalVehicleNumberValue(baseValueOf("seats")) !== cepikSeats) {
    setValue("seats", cepikSeats);
  }

  const calculatorMileage = canonicalVehicleNumberValue(vehicleData.mileage);
  if (calculatorMileage && canonicalVehicleNumberValue(baseValueOf("mileage")) !== calculatorMileage) {
    setValue("mileage", `${calculatorMileage} km`);
  }

  
  
  const applyNameValue = (fieldName, rawValue) => {
    const cepikName = canonicalVehicleTextValue(rawValue);
    if (!cepikName) return;
    const baseName = canonicalVehicleTextValue(policy?.[fieldName]);
    if (baseName && (baseName.includes(cepikName) || cepikName.includes(baseName))) return;
    setValue(fieldName, rawValue);
  };
  applyNameValue("vehicleMake", vehicleData.vehicleMake);
  applyNameValue("vehicleModel", vehicleData.vehicleModel);
  applyNameValue("vehicleType", vehicleData.vehicleType);

  return nextValues;
}

async function applyQuoteCepikVehicleData(job) {
  const jobId = String(job?.id || "");
  const vehicleData = job?.vehicleData;
  if (!jobId || !vehicleData || typeof vehicleData !== "object") return;
  const dataSignature = JSON.stringify(vehicleData);
  const hasCalculatorInput = Object.values(vehicleData.fieldSources || {})
    .includes("calculator-input");
  if (processedQuoteVehicleDataJobs.get(jobId) === dataSignature) return;
  processedQuoteVehicleDataJobs.set(jobId, dataSignature);
  const registration = normalizeQuoteRegistration(vehicleData.registration || activeQuoteBatch?.registration || "");
  const pesel = normalizeQuotePesel(activeQuoteBatch?.pesel || "");
  if (registration.length < 4) {
    processedQuoteVehicleDataJobs.delete(jobId);
    return;
  }
  
  
  
  
  
  const anchorPolicy = buildQuoteRecordSources(registration, pesel).vehicleSources
    .find((record) => !isQuoteRecordOwnedByOtherClient(record, pesel)) || null;
  if (!anchorPolicy) {
    rememberQuoteClientCardOffer(registration, pesel, vehicleData);
    return;
  }
  const groupPolicies = getSameClientVehiclePolicies(anchorPolicy);
  const targetPolicies = groupPolicies.length > 0 ? groupPolicies : [anchorPolicy];
  if (!targetPolicies.some((item) =>
    Object.keys(buildQuoteCepikVehicleValues(item, vehicleData)).length > 0)) return;
  const policyIds = targetPolicies.map((item) => item.id);
  let mutationSnapshots = new Map();
  const applyCepikValues = () => {
    const currentPolicies = policyIds
      .map((policyId) => policies.find((item) => item.id === policyId))
      .filter(Boolean);
    if (currentPolicies.length === 0) return false;
    mutationSnapshots = captureClientProfilePolicySnapshots(currentPolicies.map((item) => item.id));
    currentPolicies.forEach((item) => {
      const currentNextValues = buildQuoteCepikVehicleValues(item, vehicleData);
      if (Object.keys(currentNextValues).length === 0) return;
      Object.assign(item, currentNextValues);
      item.updatedAt = Date.now();
    });
    return true;
  };
  try {
    if (!(await ensureWritableDataFile({ deferFreshnessCheck: true }))) {
      processedQuoteVehicleDataJobs.delete(jobId);
      return;
    }
    if (!applyCepikValues()) return;
    saveStatusPopupSuccessText = hasCalculatorInput
      ? "Dane pojazdu z kalkulatora zapisane"
      : "Dane pojazdu z CEPiK zapisane";
    if (!(await persistPolicies({
      reapplyAfterConflict: applyCepikValues,
      reapplyFailureMessage: hasCalculatorInput
        ? "Polisy pojazdu zmieniły się w nowszej bazie. Dane z kalkulatora nie zostały zapisane."
        : "Polisy pojazdu zmieniły się w nowszej bazie. Dane z CEPiK nie zostały zapisane.",
    }))) {
      if (processedQuoteVehicleDataJobs.get(jobId) === dataSignature) {
        processedQuoteVehicleDataJobs.delete(jobId);
      }
      restoreClientProfilePolicySnapshots(mutationSnapshots);
      markPoliciesRolledBack();
      render();
      return;
    }
    render();
    if (elements.clientProfileDialog.open) renderClientProfile();
    if (elements.quoteCalculatorDialog.open) renderQuoteClientInfo();
    showToast(
      hasCalculatorInput
        ? `Pojazd ${registration}: brakujące dane z kalkulatora zapisane w bazie`
        : `Pojazd ${registration}: dane z CEPiK zaktualizowane w bazie`,
    );
  } catch {
    if (processedQuoteVehicleDataJobs.get(jobId) === dataSignature) {
      processedQuoteVehicleDataJobs.delete(jobId);
    }
    restoreClientProfilePolicySnapshots(mutationSnapshots);
    markPoliciesRolledBack();
    render();
  }
}





const quoteClientCardOffers = new Map();
let quoteClientCardSubmitting = false;

function quoteClientCardOfferKey(registration, pesel) {
  return `${registration}|${pesel}`;
}




function isQuoteRecordOwnedByOtherClient(policy, pesel) {
  const normalizedPesel = normalizeQuotePesel(pesel);
  if (!getIdentityNumberType(normalizedPesel)) return false;
  const digits = String(policy?.identityNumber ?? "").replace(/\D/g, "");
  if (!digits) return false;
  return !getQuoteEquivalentIdentityKeys(normalizedPesel).has(digits);
}

function rememberQuoteClientCardOffer(registration, pesel, vehicleData) {
  if (registration.length < 4 || !isValidPesel(pesel)) return;
  quoteClientCardOffers.set(quoteClientCardOfferKey(registration, pesel), {
    registration,
    pesel,
    vehicleData,
  });
  if (elements.quoteCalculatorDialog.open) renderQuoteClientInfo();
}



function syncQuoteClientCardOffer(registration, pesel, info) {
  const section = elements.quoteClientCardOffer;
  if (!section) return null;
  const offerKey = quoteClientCardOfferKey(registration, pesel);
  let offer = quoteClientCardOffers.get(offerKey) || null;
  if (offer && info?.vehicleRecord && !isQuoteRecordOwnedByOtherClient(info.vehicleRecord, pesel)) {
    quoteClientCardOffers.delete(offerKey);
    offer = null;
  }
  section.hidden = !offer;
  if (!offer) return null;
  const vehicleLabel = [offer.vehicleData?.vehicleMake, offer.vehicleData?.vehicleModel]
    .map((part) => String(part || "").trim())
    .filter(Boolean)
    .join(" ");
  const yearLabel = String(offer.vehicleData?.productionYear || "").trim();
  const vehicleText = vehicleLabel
    ? `${vehicleLabel}${yearLabel ? ` (${yearLabel})` : ""}, nr rej. ${offer.registration}`
    : `nr rej. ${offer.registration}`;
  elements.quoteClientCardOfferSummary.textContent =
    `Kalkulacja rozpoznała pojazd: ${vehicleText}. Dodaj kartę klienta, aby zapisać go w bazie razem z pojazdem.`;
  
  
  if (elements.quoteClientCardName && !elements.quoteClientCardName.value.trim()) {
    const knownName = String(info?.merged?.clientName || "").trim();
    if (knownName) elements.quoteClientCardName.value = knownName;
  }
  elements.quoteClientCardAdd.disabled = quoteClientCardSubmitting;
  elements.quoteClientCardAdd.textContent = quoteClientCardSubmitting
    ? "Dodawanie..."
    : "Dodaj kartę klienta do bazy";
  return offer;
}

async function addQuoteClientCardRecord() {
  if (quoteClientCardSubmitting) return;
  const registration = normalizeQuoteRegistration(elements.quoteRegistration.value);
  const pesel = normalizeQuotePesel(elements.quotePesel.value);
  const offer = quoteClientCardOffers.get(quoteClientCardOfferKey(registration, pesel));
  if (!offer) return;
  const clientName = String(elements.quoteClientCardName?.value || "").trim();
  if (!clientName) {
    showToast("Wpisz imię i nazwisko / nazwę klienta, aby dodać kartę", "error");
    elements.quoteClientCardName?.focus();
    return;
  }
  quoteClientCardSubmitting = true;
  renderQuoteClientInfo();
  try {
    if (!(await ensureWritableDataFile({ deferFreshnessCheck: true }))) return;
    const newPolicy = {
      id: globalThis.crypto?.randomUUID?.() ?? `${Date.now()}-${Math.random()}`,
      ownerId: currentAccount?.id || "",
      clientName,
      identityNumber: offer.pesel,
      secondaryIdentityNumber: "",
      contact: "",
      insurer: "",
      policyNumber: "",
      registration: offer.registration,
      vehicleMake: "",
      vehicleModel: "",
      vin: "",
      firstRegistrationDate: "",
      clientAddress: "",
      clientPostalCode: "",
      clientPhone: "",
      clientEmail: "",
      validFrom: "",
      validFromManuallyEdited: false,
      validUntil: "",
      premium: "",
      renewalStatus: null,
      attachments: [],
      createdAt: Date.now(),
      
      
      ...buildQuoteCepikVehicleValues({}, offer.vehicleData || {}),
    };
    
    
    markImportedPolicyFieldsManuallyEdited(
      newPolicy,
      { identityNumber: newPolicy.identityNumber, registration: newPolicy.registration },
      { markNonEmpty: true },
    );
    const reapplyNewPolicy = () => {
      if (!policies.some((policy) => policy.id === newPolicy.id)) policies.push(newPolicy);
      return true;
    };
    reapplyNewPolicy();
    saveStatusPopupSuccessText = "Karta klienta dodana do bazy";
    if (!(await persistPolicies({ reapplyAfterConflict: reapplyNewPolicy }))) {
      policies = policies.filter((policy) => policy.id !== newPolicy.id);
      markPoliciesRolledBack();
      render();
      return;
    }
    quoteClientCardOffers.delete(quoteClientCardOfferKey(registration, pesel));
    if (elements.quoteClientCardName) elements.quoteClientCardName.value = "";
    render();
    flashRecordCounterPlusOne();
    showToast(`Karta klienta ${clientName} z pojazdem ${offer.registration} dodana do bazy`, "success");
  } finally {
    quoteClientCardSubmitting = false;
    
    
    renderQuoteClientInfo();
  }
}

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

function hasWartaCredentials() {
  return Boolean(uiSettings.calculatorAccounts?.warta?.username && wartaPasswordSaved);
}

function hasGeneraliCredentials() {
  return Boolean(uiSettings.calculatorAccounts?.generali?.username && generaliPasswordSaved);
}

function hasMtuCredentials() {
  return Boolean(uiSettings.calculatorAccounts?.mtu?.username && mtuPasswordSaved);
}

function hasHestiaCredentials() {
  return Boolean(uiSettings.calculatorAccounts?.hestia?.username && hestiaPasswordSaved);
}

function hasTrastiCredentials() {
  return Boolean(uiSettings.calculatorAccounts?.trasti?.username && trastiPasswordSaved);
}

function hasWienerCredentials() {
  return Boolean(uiSettings.calculatorAccounts?.wiener?.username && wienerPasswordSaved);
}

function hasCompensaCredentials() {
  return Boolean(uiSettings.calculatorAccounts?.compensa?.username && compensaPasswordSaved);
}

function hasAllianzCredentials() {
  return Boolean(uiSettings.calculatorAccounts?.allianz?.username && allianzPasswordSaved);
}

function renderWartaAutomationAvailability(state = wartaAutomationAvailable ? "ready" : "missing") {
  const ready = state === "ready";
  const checking = state === "checking";
  
  
  
  const bridgeDownText = globalThis.location.protocol === "file:"
    ? "Wymaga uruchomienia przez plik Uruchom Baza Polis.cmd"
    : "Brak połączenia z serwerem - ponawiam próbę…";
  elements.quoteBridgeBadge.dataset.state = state;
  elements.quoteBridgeBadge.textContent = checking
    ? "Sprawdzanie…"
    : ready ? "Gotowe" : "Nieaktywne";
  elements.wartaAutomationStatus.textContent = checking
    ? "Sprawdzanie automatyzacji…"
    : ready
      ? "Automatyzacja jest gotowa."
      : globalThis.location.protocol === "file:"
        ? "Uruchom aplikację plikiem „Uruchom Baza Polis.cmd”, aby włączyć automatyzację."
        : "Automatyzacja nie odpowiada - łączę ponownie. Jeśli to potrwa, uruchom ponownie Bazę Polis.";
  elements.generaliAutomationStatus.textContent = elements.wartaAutomationStatus.textContent;
  elements.mtuAutomationStatus.textContent = elements.wartaAutomationStatus.textContent;
  elements.hestiaAutomationStatus.textContent = elements.wartaAutomationStatus.textContent;
  elements.trastiAutomationStatus.textContent = elements.wartaAutomationStatus.textContent;
  elements.wienerAutomationStatus.textContent = elements.wartaAutomationStatus.textContent;
  elements.compensaAutomationStatus.textContent = elements.wartaAutomationStatus.textContent;
  elements.allianzAutomationStatus.textContent = elements.wartaAutomationStatus.textContent;

  if (!quoteCalculationActive && quoteJobStates.size === 0) {
    resetQuoteInsurerCard("warta");
    resetQuoteInsurerCard("generali");
    resetQuoteInsurerCard("mtu");
    resetQuoteInsurerCard("trasti");
    resetQuoteInsurerCard("wiener");
    resetQuoteInsurerCard("compensa");
    resetQuoteInsurerCard("allianz");
    if (!ready) {
      elements.quoteWartaStatus.textContent = checking
        ? ""
        : bridgeDownText;
    } else if (!uiSettings.calculatorAccounts?.warta?.username) {
      elements.quoteWartaStatus.textContent = "Uzupełnij login i hasło w ustawieniach użytkownika";
    } else if (!wartaPasswordSaved) {
      elements.quoteWartaStatus.textContent = "Wpisz i zapisz hasło w ustawieniach użytkownika";
    } else {
      elements.quoteWartaStatus.textContent = "";
    }
    if (!ready) {
      elements.quoteGeneraliStatus.textContent = checking
        ? ""
        : bridgeDownText;
    } else if (!uiSettings.calculatorAccounts?.generali?.username) {
      elements.quoteGeneraliStatus.textContent = "Uzupełnij login i hasło w ustawieniach użytkownika";
    } else if (!generaliPasswordSaved) {
      elements.quoteGeneraliStatus.textContent = "Wpisz i zapisz hasło w ustawieniach użytkownika";
    } else {
      elements.quoteGeneraliStatus.textContent = "";
    }
    if (!ready) {
      elements.quoteMtuStatus.textContent = checking
        ? ""
        : bridgeDownText;
    } else if (!uiSettings.calculatorAccounts?.mtu?.username) {
      elements.quoteMtuStatus.textContent = "Uzupełnij login i hasło w ustawieniach użytkownika";
    } else if (!mtuPasswordSaved) {
      elements.quoteMtuStatus.textContent = "Wpisz i zapisz hasło w ustawieniach użytkownika";
    } else {
      elements.quoteMtuStatus.textContent = "";
    }
    if (!ready) {
      elements.quoteTrastiStatus.textContent = checking
        ? ""
        : bridgeDownText;
    } else if (!uiSettings.calculatorAccounts?.trasti?.username) {
      elements.quoteTrastiStatus.textContent = "Uzupełnij adres e-mail i hasło w ustawieniach użytkownika";
    } else if (!trastiPasswordSaved) {
      elements.quoteTrastiStatus.textContent = "Wpisz i zapisz hasło w ustawieniach użytkownika";
    } else {
      elements.quoteTrastiStatus.textContent = "";
    }
    if (!ready) {
      elements.quoteWienerStatus.textContent = checking
        ? ""
        : bridgeDownText;
    } else if (!uiSettings.calculatorAccounts?.wiener?.username) {
      elements.quoteWienerStatus.textContent = "Uzupełnij login i hasło w ustawieniach użytkownika";
    } else if (!wienerPasswordSaved) {
      elements.quoteWienerStatus.textContent = "Wpisz i zapisz hasło w ustawieniach użytkownika";
    } else {
      elements.quoteWienerStatus.textContent = "";
    }
    if (!ready) {
      elements.quoteCompensaStatus.textContent = checking
        ? ""
        : bridgeDownText;
    } else if (!uiSettings.calculatorAccounts?.compensa?.username) {
      elements.quoteCompensaStatus.textContent = "Uzupe\u0142nij login i has\u0142o w ustawieniach u\u017cytkownika";
    } else if (!compensaPasswordSaved) {
      elements.quoteCompensaStatus.textContent = "Wpisz i zapisz has\u0142o w ustawieniach u\u017cytkownika";
    } else {
      elements.quoteCompensaStatus.textContent = "";
    }
    if (!ready) {
      elements.quoteAllianzStatus.textContent = checking
        ? ""
        : bridgeDownText;
    } else if (!uiSettings.calculatorAccounts?.allianz?.username) {
      elements.quoteAllianzStatus.textContent = "Uzupe\u0142nij login i has\u0142o w ustawieniach u\u017cytkownika";
    } else if (!allianzPasswordSaved) {
      elements.quoteAllianzStatus.textContent = "Wpisz i zapisz has\u0142o w ustawieniach u\u017cytkownika";
    } else {
      elements.quoteAllianzStatus.textContent = "";
    }
  }
  syncQuoteStartButton(ready);
}

function renderAutomationAvailability(state = wartaAutomationAvailable ? "ready" : "missing") {
  renderWartaAutomationAvailability(state);
}

function createQuoteRequestTimeoutError(message = "Serwer kalkulacji nie odpowiedział w wyznaczonym czasie.") {
  const error = new Error(message);
  error.code = "QUOTE_REQUEST_TIMEOUT";
  return error;
}

async function quoteApiRequest(
  input,
  init = {},
  {
    timeoutMs = QUOTE_JOB_REQUEST_TIMEOUT_MS,
    timeoutMessage,
    replayAfterPin = false,
  } = {},
) {
  const controller = typeof globalThis.AbortController === "function"
    ? new globalThis.AbortController()
    : null;
  let didTimeout = false;
  let timeoutId = null;
  let timeoutStartedAt = 0;
  let remainingTimeoutMs = Math.max(1, Number(timeoutMs) || QUOTE_JOB_REQUEST_TIMEOUT_MS);
  const pauseTimeout = () => {
    if (timeoutId === null) return;
    globalThis.clearTimeout(timeoutId);
    timeoutId = null;
    remainingTimeoutMs = Math.max(1, remainingTimeoutMs - (Date.now() - timeoutStartedAt));
  };
  const armTimeout = () => {
    if (!controller || didTimeout || timeoutId !== null) return;
    timeoutStartedAt = Date.now();
    timeoutId = globalThis.setTimeout(() => {
      timeoutId = null;
      didTimeout = true;
      controller.abort();
    }, remainingTimeoutMs);
  };
  armTimeout();
  try {
    const response = await apiFetch(
      input,
      controller ? { ...init, signal: controller.signal } : init,
      {
        replayAfterPin,
        
        
        onPinWaitStart: pauseTimeout,
        onPinWaitEnd: armTimeout,
      },
    );
    const data = await response.json().catch(() => null);
    if (didTimeout) throw createQuoteRequestTimeoutError(timeoutMessage);
    return { response, data };
  } catch (error) {
    if (didTimeout) throw createQuoteRequestTimeoutError(timeoutMessage);
    throw error;
  } finally {
    if (timeoutId !== null) globalThis.clearTimeout(timeoutId);
  }
}

async function checkWartaAutomationBridge(options = {}) {
  
  
  if (quoteBridgeCheckPromise) return quoteBridgeCheckPromise;
  quoteBridgeCheckPromise = runQuoteBridgeCheck(options).finally(() => {
    quoteBridgeCheckPromise = null;
  });
  return quoteBridgeCheckPromise;
}




async function runQuoteBridgeCheck({ quiet = false } = {}) {
  const previouslyAvailable = wartaAutomationAvailable;
  if (!quiet) renderWartaAutomationAvailability("checking");
  try {
    const username = uiSettings.calculatorAccounts?.warta?.username || "";
    const { response, data: status } = await quoteApiRequest(
      `/api/automation/status?username=${encodeURIComponent(username)}`,
      { cache: "no-store" },
      {
        timeoutMs: QUOTE_BRIDGE_REQUEST_TIMEOUT_MS,
        timeoutMessage: "Lokalny serwer kalkulacji nie odpowiedział na czas.",
      },
    );
    wartaAutomationAvailable = response.ok && status?.available === true && status?.browser === "Google Chrome";
    wartaPasswordSaved = response.ok && status?.credentials?.wartaPasswordSaved === true;
    wartaPathSaved = response.ok && status?.credentials?.wartaPathSaved === true;
    generaliPasswordSaved = response.ok && status?.credentials?.generaliPasswordSaved === true;
    generaliPathSaved = response.ok && status?.credentials?.generaliPathSaved === true;
    mtuPasswordSaved = response.ok && status?.credentials?.mtuPasswordSaved === true;
    mtuPathSaved = response.ok && status?.credentials?.mtuPathSaved === true;
    hestiaPasswordSaved = response.ok && status?.credentials?.hestiaPasswordSaved === true;
    trastiPasswordSaved = response.ok && status?.credentials?.trastiPasswordSaved === true;
    trastiPathSaved = response.ok && status?.credentials?.trastiPathSaved === true;
    wienerPasswordSaved = response.ok && status?.credentials?.wienerPasswordSaved === true;
    wienerPathSaved = response.ok && status?.credentials?.wienerPathSaved === true;
    compensaPasswordSaved = response.ok && status?.credentials?.compensaPasswordSaved === true;
    compensaPathSaved = response.ok && status?.credentials?.compensaPathSaved === true;
    allianzPasswordSaved = response.ok && status?.credentials?.allianzPasswordSaved === true;
    inslyPasswordSaved = response.ok && status?.credentials?.inslyPasswordSaved === true;
    pzuPasswordSaved = response.ok && status?.credentials?.pzuPasswordSaved === true;
  } catch {
    wartaAutomationAvailable = false;
  }
  if (wartaAutomationAvailable) {
    quoteBridgeRetryAttempts = 0;
    
    if (!quiet || !previouslyAvailable) renderWartaAutomationAvailability("ready");
  } else {
    
    
    
    if (!quiet) {
      renderWartaAutomationAvailability(
        shouldAutoRecheckQuoteBridge() && quoteBridgeRetryAttempts < QUOTE_BRIDGE_SILENT_RECHECK_LIMIT
          ? "checking"
          : "missing",
      );
    } else if (quoteBridgeRetryAttempts === QUOTE_BRIDGE_SILENT_RECHECK_LIMIT) {
      renderWartaAutomationAvailability("missing");
    }
    scheduleQuoteBridgeRecheck();
  }
  updateWartaNavigationHint();
  updateGeneraliNavigationHint();
  updateMtuNavigationHint();
  updateTrastiNavigationHint();
  updateWienerNavigationHint();
  updateCompensaNavigationHint();
  return wartaAutomationAvailable;
}





const QUOTE_BRIDGE_RECHECK_DELAY_MS = 4_000;
const QUOTE_BRIDGE_SILENT_RECHECK_LIMIT = 7;
let quoteBridgeCheckPromise = null;
let quoteBridgeRecheckTimer = null;
let quoteBridgeRetryAttempts = 0;

function shouldAutoRecheckQuoteBridge() {
  return Boolean(elements.quoteCalculatorDialog?.open)
    && globalThis.location.protocol !== "file:";
}

function scheduleQuoteBridgeRecheck() {
  if (!shouldAutoRecheckQuoteBridge()) return;
  if (quoteBridgeRecheckTimer !== null) return;
  quoteBridgeRecheckTimer = globalThis.setTimeout(() => {
    quoteBridgeRecheckTimer = null;
    if (!shouldAutoRecheckQuoteBridge() || wartaAutomationAvailable) return;
    quoteBridgeRetryAttempts += 1;
    checkWartaAutomationBridge({ quiet: true });
  }, QUOTE_BRIDGE_RECHECK_DELAY_MS);
}

function setQuoteProgress(title, detail = "", state = "running") {
  elements.quoteProgress.hidden = false;
  elements.quoteProgress.dataset.state = state;
  elements.quoteProgressTitle.textContent = title;
  elements.quoteProgressDetail.textContent = detail;
}

function getQuoteInsurerUi(insurerId) {
  const normalizedId = normalize(insurerId);
  if (normalizedId === "warta") {
    return {
      id: "warta",
      card: elements.quoteWartaCard,
      status: elements.quoteWartaStatus,
      detail: elements.quoteWartaDetail,
      manualButton: elements.quoteWartaManualRepair,
    };
  }
  if (normalizedId === "mtu") {
    return {
      id: "mtu",
      card: elements.quoteMtuCard,
      status: elements.quoteMtuStatus,
      detail: elements.quoteMtuDetail,
      manualButton: elements.quoteMtuManualRepair,
    };
  }
  if (normalizedId === "generali") {
    return {
      id: "generali",
      card: elements.quoteGeneraliCard,
      status: elements.quoteGeneraliStatus,
      detail: elements.quoteGeneraliDetail,
      manualButton: elements.quoteGeneraliManualRepair,
    };
  }
  if (normalizedId === "trasti") {
    return {
      id: "trasti",
      card: elements.quoteTrastiCard,
      status: elements.quoteTrastiStatus,
      detail: elements.quoteTrastiDetail,
      manualButton: elements.quoteTrastiManualRepair,
    };
  }
  if (normalizedId === "wiener") {
    return {
      id: "wiener",
      card: elements.quoteWienerCard,
      status: elements.quoteWienerStatus,
      detail: elements.quoteWienerDetail,
      manualButton: elements.quoteWienerManualRepair,
    };
  }
  if (normalizedId === "compensa") {
    return {
      id: "compensa",
      card: elements.quoteCompensaCard,
      status: elements.quoteCompensaStatus,
      detail: elements.quoteCompensaDetail,
      manualButton: elements.quoteCompensaManualRepair,
    };
  }
  if (normalizedId === "allianz") {
    return {
      id: "allianz",
      card: elements.quoteAllianzCard,
      status: elements.quoteAllianzStatus,
      detail: elements.quoteAllianzDetail,
      manualButton: elements.quoteAllianzManualRepair,
    };
  }
  return null;
}

function resetQuoteInsurerCard(insurerId) {
  const ui = getQuoteInsurerUi(insurerId);
  if (!ui) return;
  ui.card.dataset.state = "idle";
  ui.detail.textContent = "";
  ui.detail.hidden = true;
  ui.manualButton.hidden = true;
  ui.manualButton.disabled = false;
  delete ui.manualButton.dataset.jobId;
  removeQuoteInputForm(ui.id);
}

function syncQuoteCalculationInputLock() {
  const inputsLocked = quoteCalculationActive || quoteCancellationPending;
  for (const input of [elements.quoteRegistration, elements.quotePesel]) {
    input.readOnly = inputsLocked;
    input.setAttribute("aria-readonly", inputsLocked ? "true" : "false");
  }
  for (const checkbox of [
    elements.quoteInsurerWarta,
    elements.quoteInsurerMtu,
    elements.quoteInsurerGenerali,
    elements.quoteInsurerTrasti,
    elements.quoteInsurerWiener,
    elements.quoteInsurerCompensa,
    elements.quoteInsurerAllianz,
  ]) {
    if (checkbox) checkbox.disabled = inputsLocked;
  }
  
  
  syncQuoteClientInfoActions();
  syncQuoteCancellationControls();
  syncQuoteStartButton();
}

function getCancelableQuoteJobIds() {
  const jobIds = new Set(activeQuoteJobIds);
  for (const [jobId, job] of quoteJobStates) {
    if (QUOTE_CANCELABLE_JOB_STATUSES.has(String(job?.status || ""))) jobIds.add(jobId);
  }
  return [...jobIds].map((jobId) => String(jobId || "")).filter(Boolean);
}

function hasRunningQuoteJobs() {
  
  
  
  
  for (const job of quoteJobStates.values()) {
    if (QUOTE_RUNNING_JOB_STATUSES.has(String(job?.status || ""))) return true;
  }
  return false;
}

function syncQuoteCancellationControls() {
  if (!elements.stopQuoteCalculation) return;
  
  
  
  
  
  const canStop = quoteCalculationActive;
  elements.stopQuoteCalculation.hidden = !canStop && !quoteCancellationPending;
  elements.stopQuoteCalculation.disabled = quoteCancellationPending;
  elements.stopQuoteCalculation.textContent = quoteCancellationPending
    ? "Zatrzymywanie…"
    : "Zatrzymaj kalkulację";
}

function syncQuoteStartButton(automationReady = wartaAutomationAvailable) {
  
  
  
  
  const bridgeRecoveryPending = quoteBridgeCheckPromise !== null
    || quoteBridgeRecheckTimer !== null;
  const startDisabled = (!automationReady && !bridgeRecoveryPending)
    || quoteCalculationActive
    || quoteCancellationPending
    || hasRunningQuoteJobs();
  elements.startQuoteCalculation.disabled = startDisabled;
  if (elements.startManualQuoteCalculation) {
    elements.startManualQuoteCalculation.disabled = startDisabled;
  }
}

async function cancelQuoteJobRequest(jobId) {
  const { response, data } = await quoteApiRequest(
    `/api/automation/jobs/${encodeURIComponent(jobId)}/cancel`,
    {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: "{}",
    },
    {
      timeoutMs: QUOTE_CANCEL_REQUEST_TIMEOUT_MS,
      timeoutMessage: "Serwer nie potwierdził zatrzymania kalkulacji na czas.",
      replayAfterPin: true,
    },
  );
  
  
  if (!response.ok && response.status !== 404 && response.status !== 409) {
    throw new Error(data?.error || "Nie udało się zatrzymać kalkulacji.");
  }
  return data?.job || null;
}

async function cancelQuoteBatchRequest(batchId) {
  let lastError = null;
  for (let attempt = 0; attempt < 2; attempt += 1) {
    try {
      const { response, data } = await quoteApiRequest(
        `/api/automation/quote-batches/${encodeURIComponent(batchId)}/cancel`,
        {
          method: "POST",
          headers: { "Content-Type": "application/json" },
          body: "{}",
        },
        {
          timeoutMs: QUOTE_CANCEL_REQUEST_TIMEOUT_MS,
          timeoutMessage: "Serwer nie potwierdził zatrzymania paczki kalkulacji na czas.",
          replayAfterPin: true,
        },
      );
      if (!response.ok || data?.cancelled !== true) {
        throw new Error(data?.error || "Nie udało się zatrzymać paczki kalkulacji.");
      }
      return Array.isArray(data.jobs) ? data.jobs : [];
    } catch (error) {
      lastError = error;
    }
  }
  throw lastError || new Error("Nie udało się zatrzymać paczki kalkulacji.");
}

async function performQuoteCancellation(batchId, jobIds = []) {
  const normalizedBatchId = String(batchId || "").trim();
  const normalizedJobIds = [...new Set(jobIds.map((jobId) => String(jobId || "")).filter(Boolean))];
  let cancelledJobs = [];
  if (normalizedBatchId) {
    try {
      cancelledJobs = await cancelQuoteBatchRequest(normalizedBatchId);
    } catch (batchError) {
      
      
      await Promise.allSettled(normalizedJobIds.map((jobId) => cancelQuoteJobRequest(jobId)));
      throw batchError;
    }
  }
  const cancelledJobIds = new Set(cancelledJobs.map((job) => String(job?.id || "")).filter(Boolean));
  const remainingJobIds = normalizedJobIds.filter((jobId) => !cancelledJobIds.has(jobId));
  const individualResults = await Promise.allSettled(
    remainingJobIds.map((jobId) => cancelQuoteJobRequest(jobId)),
  );
  const failedCancellation = individualResults.find((result) => result.status === "rejected");
  if (failedCancellation) throw failedCancellation.reason;
  cancelledJobs.push(...individualResults
    .filter((result) => result.status === "fulfilled" && result.value)
    .map((result) => result.value));
  return cancelledJobs;
}

function runPendingQuoteContextCleanups() {
  if (quoteContextCleanupRun) return quoteContextCleanupRun;
  const operation = (async () => {
    while (pendingQuoteContextCleanups.size > 0) {
      const [cleanupKey, cleanup] = pendingQuoteContextCleanups.entries().next().value;
      const requestedJobIds = [...cleanup.jobIds];
      await performQuoteCancellation(cleanup.batchId, requestedJobIds);
      if (cleanup.batchId) cleanup.jobIds.clear();
      else requestedJobIds.forEach((jobId) => cleanup.jobIds.delete(jobId));
      if (cleanup.jobIds.size === 0 && pendingQuoteContextCleanups.get(cleanupKey) === cleanup) {
        pendingQuoteContextCleanups.delete(cleanupKey);
      }
    }
  })();
  const trackedOperation = operation.finally(() => {
    if (quoteContextCleanupRun === trackedOperation) quoteContextCleanupRun = null;
  });
  quoteContextCleanupRun = trackedOperation;
  trackedOperation.catch(() => {});
  return trackedOperation;
}





function reflectQuoteCleanupOnStartButton(operation) {
  const button = elements.startQuoteCalculation;
  if (!(button instanceof HTMLElement)) return;
  if (quoteCalculationActive || quoteCancellationPending) return;
  button.disabled = true;
  button.textContent = "Zamykanie poprzedniej kalkulacji…";
  operation.catch(() => {}).finally(() => {
    
    
    
    
    if (quoteContextCleanupRun) return;
    button.textContent = "Policz składki";
    syncQuoteStartButton();
  });
}

function scheduleQuoteContextCleanup(batchId, jobIds) {
  const normalizedBatchId = String(batchId || "").trim();
  const normalizedJobIds = [...new Set(jobIds.map((jobId) => String(jobId || "")).filter(Boolean))];
  if (!normalizedBatchId && normalizedJobIds.length === 0) return Promise.resolve();
  const cleanupKey = normalizedBatchId || `jobs:${normalizedJobIds.sort().join(",")}`;
  const cleanup = pendingQuoteContextCleanups.get(cleanupKey) || {
    batchId: normalizedBatchId,
    jobIds: new Set(),
  };
  normalizedJobIds.forEach((jobId) => cleanup.jobIds.add(jobId));
  pendingQuoteContextCleanups.set(cleanupKey, cleanup);
  const operation = runPendingQuoteContextCleanups();
  reflectQuoteCleanupOnStartButton(operation);
  operation.catch(() => {
    showToast("Nie udało się potwierdzić zamknięcia poprzedniej kalkulacji. Ponowimy próbę przed następnym startem.", "error");
  });
  return operation;
}

async function waitForPendingQuoteContextCleanups() {
  let lastError = null;
  for (let attempt = 0; attempt < 2 && pendingQuoteContextCleanups.size > 0; attempt += 1) {
    try {
      await runPendingQuoteContextCleanups();
      lastError = null;
    } catch (error) {
      lastError = error;
    }
  }
  if (pendingQuoteContextCleanups.size > 0) {
    throw lastError || new Error("Nie udało się zamknąć poprzedniej kalkulacji.");
  }
}

function quoteDisplayedContextMatches(registration, pesel) {
  const context = activeQuoteBatch || renderedQuoteResultsContext;
  if (!context) return quoteJobStates.size === 0;
  return normalizeQuoteRegistration(context.registration) === normalizeQuoteRegistration(registration)
    && normalizeQuotePesel(context.pesel) === normalizeQuotePesel(pesel);
}

function clearQuoteDisplayedContext() {
  if (quoteCalculationActive || quoteCancellationPending) return false;
  const cleanupJobIds = getCancelableQuoteJobIds();
  const cleanupBatchId = String(activeQuoteBatch?.id || "");
  if (cleanupJobIds.length > 0) {
    if (activeQuoteBatch) activeQuoteBatch.cancellationRequested = true;
    scheduleQuoteContextCleanup(cleanupBatchId, cleanupJobIds);
  }
  quoteResultsRestoreToken += 1;
  activeQuoteJobIds.clear();
  quoteJobStates = new Map();
  quoteJobPollFailures = new Map();
  quoteCalculationErrors = [];
  activeQuoteBatch = null;
  renderedQuoteResultsContext = null;
  renderedQuotePremiums = [];
  quotePrintGroups = [];
  expandedQuoteResultInsurers = new Set();
  expandedQuoteArchiveGroupKey = null;
  setQuoteArchiveActiveEntry(null);
  elements.quoteResults.hidden = true;
  elements.quoteResultsSummary.textContent = "";
  elements.quoteResultsList.replaceChildren();
  elements.quoteProgress.hidden = true;
  syncQuoteResultsColumn();
  renderWartaAutomationAvailability(wartaAutomationAvailable ? "ready" : "missing");
  syncQuoteCancellationControls();
  return true;
}

function renderQuoteInsurerJob(job, fallbackInsurerId = "") {
  const insurerId = normalize(job?.insurer || fallbackInsurerId);
  const ui = getQuoteInsurerUi(insurerId);
  if (!ui) return;
  const status = String(job?.status || "error");
  const state = status === "completed"
    ? "completed"
    : status === "manual_ready"
      ? "manual-ready"
    : status === "manual_required"
      ? "manual"
      : status === "action_required" || status === "input_required"
        ? "action"
        : status === "queued" || status === "running"
          ? status
          : "error";
  const premiumCount = Array.isArray(job?.premiums) ? job.premiums.length : 0;
  ui.card.dataset.state = state;
  
  
  
  ui.status.textContent = status === "completed"
    ? `Gotowe - ${premiumCount} ${premiumCount === 1 ? "wariant" : "wariantów"}`
    : status === "manual_ready"
      ? String(job?.title || "Karta gotowa do ręcznego liczenia")
    : state === "running"
      ? (/logow|przełącz/i.test(String(job?.title || "")) ? "Logowanie…" : "Kalkulowanie…")
      : state === "queued"
        ? "Oczekiwanie…"
        : String(job?.title || (state === "error" ? "Kalkulacja nie powiodła się" : "Kalkulowanie…"));
  const detail = state === "running" || state === "queued" ? "" : String(job?.detail || "").trim();
  ui.detail.textContent = detail;
  ui.detail.hidden = !detail;
  const showManualButton = status === "manual_required" && job?.manualAvailable === true && Boolean(job?.id);
  ui.manualButton.hidden = !showManualButton;
  ui.manualButton.disabled = false;
  if (showManualButton) ui.manualButton.dataset.jobId = String(job.id);
  else delete ui.manualButton.dataset.jobId;
  renderQuoteJobInputForm(job, insurerId);
}

function getQuoteInputRequestsContainer() {
  let container = document.getElementById("quoteInputRequests");
  if (!container) {
    
    
    container = document.createElement("section");
    container.id = "quoteInputRequests";
    container.className = "quote-input-requests";
    container.hidden = true;
    const mainColumn = elements.quoteCalculatorContent.querySelector(".quote-calculator-main");
    (mainColumn || elements.quoteCalculatorContent).insertBefore(container, elements.quoteProgress);
  }
  return container;
}

function syncQuoteInputRequestsVisibility() {
  const container = document.getElementById("quoteInputRequests");
  if (container) container.hidden = container.childElementCount === 0;
}

function removeQuoteInputForm(insurerId) {
  const container = document.getElementById("quoteInputRequests");
  if (!container) return;
  for (const form of [...container.querySelectorAll("form.quote-input-form")]) {
    if (!insurerId || form.dataset.insurerId === insurerId) form.remove();
  }
  syncQuoteInputRequestsVisibility();
}

function normalizeQuoteTemporalInputValue(value, kind) {
  const text = String(value || "").trim();
  if (!text) return "";
  const polishDate = text.match(/^(\d{1,2})[.\-/](\d{1,2})[.\-/](\d{4})(?:\s+(\d{1,2}):(\d{2}))?$/);
  if (polishDate) {
    const isoDate = `${polishDate[3]}-${polishDate[2].padStart(2, "0")}-${polishDate[1].padStart(2, "0")}`;
    if (kind === "datetime") {
      return `${isoDate}T${String(polishDate[4] || "00").padStart(2, "0")}:${polishDate[5] || "00"}`;
    }
    return kind === "month" ? isoDate.slice(0, 7) : isoDate;
  }
  if (kind === "date") return text.match(/^\d{4}-\d{2}-\d{2}/)?.[0] || "";
  if (kind === "month") return text.match(/^\d{4}-\d{2}/)?.[0] || "";
  if (kind === "datetime") return text.replace(" ", "T").match(/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}/)?.[0] || "";
  return text;
}

function buildQuoteInputControl(field) {
  if (field.kind === "checkbox") {
    const wrapper = document.createElement("label");
    wrapper.className = "quote-input-form-checkbox";
    const checkbox = document.createElement("input");
    checkbox.type = "checkbox";
    checkbox.dataset.fieldId = field.id;
    wrapper.append(checkbox, document.createTextNode(" Zaznacz"));
    return wrapper;
  }
  const options = Array.isArray(field.options) ? field.options : [];
  if ((field.kind === "select" || field.kind === "radio" || field.kind === "combobox") && options.length > 0) {
    const select = document.createElement("select");
    select.dataset.fieldId = field.id;
    const placeholder = document.createElement("option");
    placeholder.value = "";
    placeholder.textContent = "- wybierz -";
    select.append(placeholder);
    for (const option of options) {
      const text = String(option?.text || option?.value || "").trim();
      if (!text) continue;
      const optionElement = document.createElement("option");
      optionElement.value = String(option?.value || text);
      optionElement.textContent = text;
      if (field.currentValue && optionElement.value === field.currentValue) optionElement.selected = true;
      select.append(optionElement);
    }
    return select;
  }
  const input = document.createElement("input");
  input.type = field.kind === "date"
    ? "date"
    : field.kind === "datetime"
      ? "datetime-local"
      : field.kind === "month"
        ? "month"
        : "text";
  input.dataset.fieldId = field.id;
  if (field.kind === "number") input.inputMode = "decimal";
  if (field.kind === "combobox") input.placeholder = "Wpisz dokładną treść opcji z listy";
  else if (input.type === "text" && field.placeholder) input.placeholder = String(field.placeholder);
  if (field.formatHint) input.title = `Format: ${field.formatHint}`;
  input.value = ["date", "datetime", "month"].includes(field.kind)
    ? normalizeQuoteTemporalInputValue(field.currentValue, field.kind)
    : String(field.currentValue || "");
  return input;
}

function renderQuoteJobInputForm(job, insurerId) {
  const normalizedInsurerId = normalize(insurerId || job?.insurer || "");
  if (!normalizedInsurerId) return;
  const container = getQuoteInputRequestsContainer();
  const existing = container.querySelector(`form.quote-input-form[data-insurer-id="${normalizedInsurerId}"]`);
  const inputRequest = job?.status === "input_required" ? job?.inputRequest : null;
  const fields = Array.isArray(inputRequest?.fields) ? inputRequest.fields.slice(0, 25) : [];
  if (!inputRequest?.id || fields.length === 0 || !job?.id) {
    if (existing) existing.remove();
    syncQuoteInputRequestsVisibility();
    return;
  }
  if (existing?.dataset.requestId === String(inputRequest.id)) return;
  existing?.remove();
  const form = document.createElement("form");
  form.className = "quote-input-form";
  form.dataset.insurerId = normalizedInsurerId;
  form.dataset.jobId = String(job.id);
  form.dataset.requestId = String(inputRequest.id);
  const heading = document.createElement("strong");
  heading.className = "quote-input-form-title";
  heading.textContent = inputRequest.title
    ? `${job.insurer} czeka na dane - ekran „${inputRequest.title}”`
    : `${job.insurer} czeka na uzupełnienie pól`;
  const hint = document.createElement("small");
  hint.className = "quote-input-form-hint";
  hint.textContent = "Uzupełnij pola, które znasz (pola z błędem oznaczono kolorem), i kliknij „Wyślij i kontynuuj”.";
  form.append(heading, hint);
  const grid = document.createElement("div");
  grid.className = "quote-input-form-grid";
  for (const field of fields) {
    const row = document.createElement("label");
    row.className = "quote-input-form-row";
    if (field.invalid) row.dataset.invalid = "true";
    const caption = document.createElement("span");
    caption.className = "quote-input-form-label";
    caption.textContent = field.required ? `${field.label} *` : String(field.label || "");
    row.append(caption, buildQuoteInputControl(field));
    if (field.formatHint) {
      const formatHint = document.createElement("small");
      formatHint.className = "quote-input-form-format";
      formatHint.textContent = `Format: ${field.formatHint}`;
      row.append(formatHint);
    }
    grid.append(row);
  }
  form.append(grid);
  const actions = document.createElement("div");
  actions.className = "quote-input-form-actions";
  const submit = document.createElement("button");
  submit.type = "submit";
  submit.className = "settings-save-button";
  submit.textContent = "Wyślij i kontynuuj";
  const skip = document.createElement("button");
  skip.type = "button";
  skip.className = "settings-secondary-button";
  skip.textContent = "Pomiń - poprawię w Chrome";
  actions.append(submit, skip);
  form.append(actions);
  form.addEventListener("submit", (event) => {
    event.preventDefault();
    submitQuoteJobInput(form, { cancel: false });
  });
  skip.addEventListener("click", () => submitQuoteJobInput(form, { cancel: true }));
  container.append(form);
  syncQuoteInputRequestsVisibility();
}

async function submitQuoteJobInput(form, { cancel }) {
  if (quoteCancellationPending || activeQuoteBatch?.cancellationRequested === true) return;
  const jobId = String(form?.dataset?.jobId || "");
  const requestId = String(form?.dataset?.requestId || "");
  if (!jobId || !requestId) return;
  const values = {};
  if (!cancel) {
    for (const control of form.querySelectorAll("[data-field-id]")) {
      const fieldId = control.dataset.fieldId;
      if (!fieldId) continue;
      if (control.type === "checkbox") {
        if (control.checked) values[fieldId] = { value: "tak", checked: true };
        continue;
      }
      const value = String(control.value || "").trim();
      if (value) values[fieldId] = { value, checked: false };
    }
    if (Object.keys(values).length === 0) {
      showToast("Uzupełnij przynajmniej jedno pole albo użyj „Pomiń”", "warning");
      return;
    }
  }
  for (const button of form.querySelectorAll("button")) button.disabled = true;
  try {
    const { response, data } = await quoteApiRequest(
      `/api/automation/jobs/${encodeURIComponent(jobId)}/input`,
      {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify(cancel ? { requestId, cancel: true } : { requestId, values }),
      },
      {
        timeoutMessage: "Serwer nie potwierdził przekazania danych do kalkulatora na czas.",
      },
    );
    if (!response.ok) throw new Error(data?.error || "Nie udało się przekazać danych do kalkulatora.");
    form.remove();
    syncQuoteInputRequestsVisibility();
    if (data?.job) applyParallelQuoteJobState(data.job);
  } catch (error) {
    for (const button of form.querySelectorAll("button")) button.disabled = false;
    showToast(String(error?.message || "Nie udało się przekazać danych do kalkulatora."), "error");
  }
}

function renderQuoteInsurerFailure(insurerId, message) {
  renderQuoteInsurerJob({
    insurer: insurerId,
    status: "error",
    title: "Nie udało się uruchomić kalkulacji",
    detail: String(message || "Nieznany błąd"),
    premiums: [],
  }, insurerId);
}

function compactQuoteRiskText(value) {
  return String(value || "")
    .replace(/[\u00a0\u202f]/g, " ")
    .replace(/\s+/g, " ")
    .trim();
}

function normalizeQuoteRiskText(value) {
  return compactQuoteRiskText(value)
    .normalize("NFD")
    .replace(/[\u0300-\u036f]/g, "")
    .toLocaleLowerCase("pl-PL");
}

const QUOTE_RISK_MONEY_SOURCE = String.raw`(?:\d{1,3}(?:[ .]\d{3})*|\d+)(?:,\d{2})?\s*(?:zł|PLN)`;
const QUOTE_RISK_MONEY_PATTERN = new RegExp(QUOTE_RISK_MONEY_SOURCE, "i");
const QUOTE_RISK_MONEY_GLOBAL_PATTERN = new RegExp(QUOTE_RISK_MONEY_SOURCE, "gi");

function classifyQuoteRiskLabel(label, insurer) {
  const normalizedLabel = normalizeQuoteRiskText(label);
  if (!normalizedLabel) return "";
  if (normalizeQuoteRiskText(insurer) === "mtu" && /\bminicasco\b/.test(normalizedLabel)) return "minicasco";
  if (/\bszyb(?:y|a|ami|owe)?\b|autoszyb/.test(normalizedLabel)) return "szyby";
  if (/\bnnw\b/.test(normalizedLabel)) return "nnw";
  if (/\bassistance\b/.test(normalizedLabel)) return "assistance";
  if (/^autocasco\b|^ac\b(?!\s*(?:[/+]|\bi\b))/.test(normalizedLabel)) return "ac";
  if (/^oc\b(?!\s*(?:[/+]|\bi\b))|^odpowiedzialnosc cywilna\b/.test(normalizedLabel)) return "oc";
  return "";
}

function splitQuoteRiskAmountNote(value) {
  const amount = compactQuoteRiskText(value);
  const match = amount.match(/^(.*\S)\s*\(([^()]*)\)\s*$/);
  if (!match || !QUOTE_RISK_MONEY_PATTERN.test(match[1])) {
    return { amount, note: "" };
  }
  return {
    amount: compactQuoteRiskText(match[1]),
    note: compactQuoteRiskText(match[2]),
  };
}

function extractQuoteRiskSum(...values) {
  for (const value of values) {
    const text = compactQuoteRiskText(value);
    if (!text) continue;
    const explicit = text.match(new RegExp(
      String.raw`(?:\bSU\b|suma\s+ubezpieczenia|wartość\s+pojazdu)\s*:?\s*(${QUOTE_RISK_MONEY_SOURCE})`,
      "i",
    ));
    if (explicit?.[1]) return compactQuoteRiskText(explicit[1]).replace(/PLN/i, "zł");
    for (const parenthetical of text.matchAll(/\(([^()]*)\)/g)) {
      const amount = parenthetical[1].match(QUOTE_RISK_MONEY_PATTERN)?.[0];
      if (amount) return compactQuoteRiskText(amount).replace(/PLN/i, "zł");
    }
  }
  return "";
}

function extractQuoteAssistanceName(label, amountNote) {
  let name = compactQuoteRiskText(label)
    .replace(/^.*?\bassistance\b/i, "")
    .replace(new RegExp(String.raw`(?:\bSU\b|suma\s+ubezpieczenia)\s*:?\s*${QUOTE_RISK_MONEY_SOURCE}`, "ig"), " ")
    .replace(QUOTE_RISK_MONEY_GLOBAL_PATTERN, " ")
    .replace(/[()[\]{}]/g, " ")
    .replace(/\b(?:wariant|pakiet|zakres)\b\s*:?\s*/ig, " ")
    .replace(/^[\s:;,./+–—-]+|[\s:;,./+–—-]+$/g, "");
  name = compactQuoteRiskText(name || amountNote);
  if (!name || /^(?:w cenie|składka|ubezpieczenie)$/i.test(name)) return "";
  return name.slice(0, 40);
}

function normalizeQuoteAcRepairVariant(insurer, ...values) {
  const text = normalizeQuoteRiskText(values.filter(Boolean).join(" • "));
  if (!text) return "";
  if (/\bwarsztat(?:\s+|-)?partnersk|\bsiec(?:i)?\s+partnersk/.test(text)) {
    return "warsztat partnerski";
  }
  if (/\bkosztorys|\bwycena\b/.test(text)) return "kosztorys";
  if (/^\s*warsztat\s*$|\bnaprawa\s*:\s*warsztat\b/.test(text)) return "warsztat";
  if (/\bbez\s+(?:naprawy\s+)?w\s+aso\b|\bpoza\s+aso\b|\bnie\s+aso\b/.test(text)) {
    return "poza ASO";
  }
  if (/\baso\b|\bserwisow|\bserwis\b|\bnaprawa\s*:\s*serwis\b|\bac\s+serwis\b/.test(text)) {
    return "ASO/serwisowy";
  }
  
  
  if (normalizeQuoteRiskText(insurer) === "warta"
    && /\b(?:bez|brak)\s+amortyzacji\s+czesci\b/.test(text)) {
    return "ASO/serwisowy";
  }
  return "";
}

function buildCanonicalQuoteRiskRows(entry) {
  const components = entry?.components && typeof entry.components === "object"
    ? entry.components
    : {};
  const sourceRows = (Array.isArray(entry?.componentsList) ? entry.componentsList : [])
    .slice(0, 30)
    .map((component) => ({
      label: compactQuoteRiskText(component?.label).slice(0, 120),
      amount: compactQuoteRiskText(component?.amount).slice(0, 120),
    }))
    .filter((component) => component.label && component.amount);
  const fallbackRows = [
    ["OC", components.oc],
    ["AC", components.ac],
    ["Assistance", components.assistance],
    ["NNW", components.nnw],
    ["Szyby", components.szyby],
  ].filter(([, amount]) => compactQuoteRiskText(amount))
    .map(([label, amount]) => ({ label, amount: compactQuoteRiskText(amount) }));

  const rowsByRisk = new Map();
  for (const row of [...sourceRows, ...fallbackRows]) {
    const risk = classifyQuoteRiskLabel(row.label, entry?.insurer);
    if (risk && !rowsByRisk.has(risk)) rowsByRisk.set(risk, row);
  }

  
  const normalizedVariantLabel = normalizeQuoteRiskText(entry?.label);
  if (rowsByRisk.size === 0
    && /^pakiet oc\b|^oc\b/.test(normalizedVariantLabel)
    && !/\b(?:ac|autocasco|nnw|assistance|minicasco|szyb)\b/.test(
      normalizedVariantLabel.replace(/^pakiet oc\b|^oc\b/, ""),
    )
    && compactQuoteRiskText(entry?.amount)) {
    rowsByRisk.set("oc", { label: "OC", amount: compactQuoteRiskText(entry.amount) });
  }

  const result = [];
  for (const risk of ["oc", "ac", "minicasco", "nnw", "assistance", "szyby"]) {
    const row = rowsByRisk.get(risk);
    if (!row) continue;
    const leadingSum = compactQuoteRiskText(row.amount).match(
      new RegExp(String.raw`^\((${QUOTE_RISK_MONEY_SOURCE})\)\s*(.+)$`, "i"),
    );
    const amountWithNote = splitQuoteRiskAmountNote(leadingSum?.[3] || row.amount);
    const sum = extractQuoteRiskSum(
      row.label,
      leadingSum?.[1],
      (risk === "ac" || risk === "minicasco") && components.vehicleValue
        ? `SU: ${components.vehicleValue}`
        : "",
    );
    const acRepairVariant = risk === "ac"
      ? normalizeQuoteAcRepairVariant(
        entry?.insurer,
        components.acVariant,
        amountWithNote.note,
        row.label,
        entry?.label,
        entry?.details,
      )
      : "";
    let label = risk === "minicasco"
      ? "Minicasco"
      : risk === "szyby"
        ? "Szyby"
        : risk === "assistance"
          ? "Assistance"
          : risk.toUpperCase();
    if (risk === "ac") {
      const acDetails = [sum, acRepairVariant].filter(Boolean);
      if (acDetails.length > 0) label += ` (${acDetails.join(", ")})`;
    } else if ((risk === "minicasco" || risk === "szyby") && sum) {
      label += ` (${sum})`;
    } else if (risk === "assistance") {
      const name = extractQuoteAssistanceName(row.label, amountWithNote.note);
      if (name) label += ` (${name})`;
    }
    result.push({
      label,
      amount: amountWithNote.amount.replace(/PLN/i, "zł").slice(0, 60),
    });
  }
  return result;
}

function calculateMtuCanonicalQuoteTotal(entry) {
  if (normalizeQuoteRiskText(entry?.insurer) !== "mtu"
    || normalizeQuoteRiskText(entry?.label) !== "kalkulacja komunikacyjna"
    || !Array.isArray(entry?.componentsList)
    || entry.componentsList.length === 0) {
    return "";
  }
  const amounts = entry.componentsList.map((component) => {
    const value = compactQuoteRiskText(component?.amount);
    if (/^w cenie$/i.test(value)) return 0;
    const match = value.match(
      /^(\d{1,3}(?:[ .]\d{3})*|\d+)(?:,(\d{2}))?\s*(?:zł|PLN)$/i,
    );
    if (!match) return null;
    return Number(match[1].replace(/[ .]/g, "")) + (Number(match[2] || 0) / 100);
  });
  if (amounts.some((amount) => amount === null)) return "";
  const totalParts = (Math.round(amounts.reduce((sum, amount) => sum + amount, 0) * 100) / 100)
    .toFixed(2)
    .split(".");
  const grouped = totalParts[0].replace(/\B(?=(\d{3})+(?!\d))/g, " ");
  return totalParts[1] === "00" ? `${grouped} zł` : `${grouped},${totalParts[1]} zł`;
}

function normalizeLegacyGeneraliQuoteEntries(entries) {
  const generaliOcEntries = entries.filter((entry) => {
    if (entry.insurer.toLocaleLowerCase("pl-PL") !== "generali") return false;
    const label = entry.label.toLocaleLowerCase("pl-PL");
    return label.includes("pakiet oc") || label.includes("rozszerzenia pakiet");
  });
  if (generaliOcEntries.length === 0) return entries;

  const amountValue = (amount) => {
    const compact = String(amount || "").replace(/\s/g, "").replace(",", ".");
    const parsed = Number.parseFloat(compact.replace(/[^\d.-]/g, ""));
    return Number.isFinite(parsed) ? parsed : Number.POSITIVE_INFINITY;
  };
  const sortedVariants = [...generaliOcEntries].sort((left, right) => (
    amountValue(left.amount) - amountValue(right.amount)
  ));
  const variantNumbers = new Map(sortedVariants.map((entry, index) => [entry, index + 1]));

  return entries.map((entry) => {
    const variantNumber = variantNumbers.get(entry);
    if (!variantNumber) return entry;
    const otherComponents = entry.componentsList.filter((component) => (
      component.label.toLocaleLowerCase("pl-PL") !== "oc"
    ));
    return {
      ...entry,
      label: `Pakiet OC – wariant ${variantNumber}`,
      details: "",
      components: {
        ...entry.components,
        oc: entry.amount,
      },
      componentsList: [{ label: "OC", amount: entry.amount }, ...otherComponents].slice(0, 12),
    };
  });
}

function normalizeQuotePremiumEntries(premiums) {
  const insurerEntryCounts = new Map();
  const normalizedEntries = (Array.isArray(premiums) ? premiums : []).map((entry, index) => {
    const normalizedEntry = {
      insurer: String(entry?.insurer || "Warta").trim().slice(0, 60) || "Warta",
      label: String(entry?.label || `Wariant ${index + 1}`).trim().slice(0, 120),
      amount: String(entry?.amount || "").trim().slice(0, 60),
      details: String(entry?.details || "").trim().slice(0, 180),
      components: {
        oc: String(entry?.components?.oc || "").trim().slice(0, 60),
        ac: String(entry?.components?.ac || "").trim().slice(0, 60),
        acVariant: String(entry?.components?.acVariant || "").trim().slice(0, 60),
        vehicleValue: String(entry?.components?.vehicleValue || "").trim().slice(0, 60),
        assistance: String(entry?.components?.assistance || "").trim().slice(0, 60),
        nnw: String(entry?.components?.nnw || "").trim().slice(0, 60),
        szyby: String(entry?.components?.szyby || "").trim().slice(0, 60),
      },
      componentsList: [],
    };
    normalizedEntry.componentsList = buildCanonicalQuoteRiskRows({
      ...entry,
      insurer: normalizedEntry.insurer,
      label: normalizedEntry.label,
      amount: normalizedEntry.amount,
      components: normalizedEntry.components,
    });
    const mtuCanonicalTotal = calculateMtuCanonicalQuoteTotal(normalizedEntry);
    if (mtuCanonicalTotal) normalizedEntry.amount = mtuCanonicalTotal;
    
    
    if (normalizedEntry.componentsList.length > 0) normalizedEntry.details = "";
    return normalizedEntry;
  })
    .filter((entry) => {
      if (!entry.amount) return false;
      const insurerKey = entry.insurer.toLocaleLowerCase("pl-PL");
      const count = insurerEntryCounts.get(insurerKey) || 0;
      if (count >= QUOTE_PREMIUM_ENTRY_LIMIT_PER_INSURER) return false;
      insurerEntryCounts.set(insurerKey, count + 1);
      return true;
    })
    
    
    
    .slice(0, QUOTE_PREMIUM_ENTRY_LIMIT);
  return normalizeLegacyGeneraliQuoteEntries(normalizedEntries);
}

function formatQuoteCalculationDate(isoString) {
  const timestamp = Date.parse(String(isoString || ""));
  if (!Number.isFinite(timestamp)) return "";
  return SHORT_DATE_TIME_FORMAT.format(new Date(timestamp));
}



function syncQuoteResultsColumn() {
  const hasResults = !elements.quoteResults.hidden;
  elements.quoteCalculatorContent.classList.toggle("quote-calculator-content--with-results", hasResults);
  elements.quoteCalculatorDialog.classList.toggle("quote-calculator-dialog--with-results", hasResults);
}

function renderQuoteResults(premiums, meta = null) {
  const normalizedPremiums = normalizeQuotePremiumEntries(premiums).filter((entry) => isInsurerServed(entry.insurer));
  const resultRegistration = normalizeQuoteRegistration(meta?.registration);
  const resultPesel = String(meta?.pesel || "");
  
  if (!renderedQuoteResultsContext
    || renderedQuoteResultsContext.registration !== resultRegistration
    || renderedQuoteResultsContext.pesel !== resultPesel) {
    expandedQuoteResultInsurers = new Set();
  }
  renderedQuoteResultsContext = {
    registration: resultRegistration,
    pesel: resultPesel,
    calculatedAt: String(meta?.calculatedAt || ""),
    savedFromHistory: meta?.savedFromHistory === true,
  };
  renderedQuotePremiums = normalizedPremiums;
  elements.quoteResults.hidden = normalizedPremiums.length === 0;
  syncQuoteResultsColumn();
  const countLabel = normalizedPremiums.length === 1
    ? "1 składkę"
    : `${normalizedPremiums.length} wariantów`;
  const calculationDate = formatQuoteCalculationDate(meta?.calculatedAt);
  const registrationLabel = resultRegistration ? ` dla ${resultRegistration}` : "";
  elements.quoteResultsSummary.textContent = !calculationDate
    ? `Znaleziono ${countLabel}${registrationLabel}.`
    : meta?.savedFromHistory
      ? `Zapisana kalkulacja${registrationLabel} z ${calculationDate} - znaleziono ${countLabel}.`
      : `Znaleziono ${countLabel}${registrationLabel} - kalkulacja z ${calculationDate}.`;
  
  
  const insurerGroups = [];
  const groupsByKey = new Map();
  for (const entry of normalizedPremiums) {
    const key = normalize(entry.insurer) || entry.insurer.toLocaleLowerCase("pl-PL");
    let group = groupsByKey.get(key);
    if (!group) {
      group = { key, insurer: entry.insurer, entries: [] };
      groupsByKey.set(key, group);
      insurerGroups.push(group);
    }
    group.entries.push(entry);
  }
  for (const group of insurerGroups) group.entries.sort(compareQuoteEntriesByTotal);
  insurerGroups.sort((first, second) => getQuoteGroupLowestOc(first) - getQuoteGroupLowestOc(second));
  elements.quoteResultsList.innerHTML = insurerGroups
    .map((group) => renderQuoteResultInsurerCard(group))
    .join("");
  return normalizedPremiums.length;
}

function getQuoteInsurerMarkModifier(insurerName) {
  const normalizedInsurer = normalize(insurerName);
  return normalizedInsurer === "generali"
    ? " quote-insurer-mark--generali"
    : normalizedInsurer === "mtu"
      ? " quote-insurer-mark--mtu"
      : normalizedInsurer === "trasti"
        ? " quote-insurer-mark--trasti"
        : normalizedInsurer === "wiener"
          ? " quote-insurer-mark--wiener"
          : normalizedInsurer === "compensa" ? " quote-insurer-mark--compensa" : "";
}

function stripQuoteAmountNote(amount) {
  const noteMatch = String(amount || "").match(/^(.*\S)\s*\((.+)\)\s*$/);
  return noteMatch ? noteMatch[1] : String(amount || "").trim();
}

function findQuoteEntryOcAmount(entry) {
  if (entry.componentsList.length > 0) {
    const ocComponent = entry.componentsList.find((component) => /^oc\b(?!\s*[/+])/i.test(component.label.trim()));
    if (ocComponent?.amount) return ocComponent.amount;
  }
  return entry.components.oc || "";
}

function getQuoteEntryOcSortValue(entry) {
  const ocValue = parsePremiumValue(stripQuoteAmountNote(findQuoteEntryOcAmount(entry)));
  if (ocValue !== null) return ocValue;
  const totalValue = parsePremiumValue(stripQuoteAmountNote(entry?.amount));
  return totalValue ?? Number.POSITIVE_INFINITY;
}

function compareQuoteEntriesByOc(first, second) {
  return getQuoteEntryOcSortValue(first) - getQuoteEntryOcSortValue(second);
}

function getQuoteEntryTotalSortValue(entry) {
  return parsePremiumValue(stripQuoteAmountNote(entry?.amount)) ?? Number.POSITIVE_INFINITY;
}

function compareQuoteEntriesByTotal(first, second) {
  const totalDifference = getQuoteEntryTotalSortValue(first) - getQuoteEntryTotalSortValue(second);
  if (totalDifference !== 0) return totalDifference;
  const ocDifference = getQuoteEntryOcSortValue(first) - getQuoteEntryOcSortValue(second);
  if (ocDifference !== 0) return ocDifference;
  return String(first?.label || "").localeCompare(String(second?.label || ""), "pl");
}

function getQuoteGroupLowestOc(group) {
  return group.entries.reduce(
    (lowest, entry) => Math.min(lowest, getQuoteEntryOcSortValue(entry)),
    Number.POSITIVE_INFINITY,
  );
}



function getQuoteResultHeadlinePremium(entries) {
  for (const entry of entries) {
    const ocAmount = findQuoteEntryOcAmount(entry);
    if (ocAmount) return { label: "Składka OC", amount: stripQuoteAmountNote(ocAmount) };
  }
  let cheapestEntry = null;
  let cheapestValue = Infinity;
  for (const entry of entries) {
    const value = parsePremiumValue(entry.amount);
    if (value !== null && value < cheapestValue) {
      cheapestValue = value;
      cheapestEntry = entry;
    }
  }
  const fallbackEntry = cheapestEntry || entries[0];
  return { label: "Łączna składka", amount: stripQuoteAmountNote(fallbackEntry?.amount || "") };
}

function buildQuoteExpandHint(variantCount, expanded) {
  const action = expanded ? "kliknij, aby zwinąć szczegóły" : "kliknij, aby zobaczyć szczegóły";
  if (!Number.isFinite(variantCount) || variantCount <= 0) return action;
  return `${formatQuoteVariantCount(variantCount)} - ${action}`;
}

function getQuoteEntryComponentRows(entry) {
  if (Array.isArray(entry?.componentsList) && entry.componentsList.length > 0) {
    return entry.componentsList
      .map((component) => [
        String(component?.label || "").trim(),
        String(component?.amount || "").trim(),
      ])
      .filter(([label, amount]) => label && amount);
  }
  const components = entry?.components || {};
  return [
    ["OC", components.oc],
    ["AC", components.ac],
    ["Assistance", components.assistance],
    ["NNW", components.nnw],
    ["Szyby", components.szyby],
  ].filter(([, amount]) => amount);
}

function getQuoteEntryScopeSummary(entry) {
  const rows = getQuoteEntryComponentRows(entry);
  if (rows.length > 0) return rows.map(([label, amount]) => `${label}: ${amount}`).join(" · ");
  return String(entry?.details || "Brak rozbicia zakresu").trim();
}

function renderQuoteResultVariantSection(entry) {
  const componentRows = getQuoteEntryComponentRows(entry);
  const breakdown = componentRows.length > 0
    ? `<dl class="quote-result-breakdown">${componentRows.map(([label, amount]) => {
        const noteMatch = amount.match(/^(.*\S)\s*\((.+)\)\s*$/);
        const mainValue = noteMatch ? noteMatch[1] : amount;
        const note = noteMatch ? noteMatch[2] : "";
        return `
        <div><dt>${escapeHtml(label)}</dt><dd>${escapeHtml(mainValue)}${note ? `<small>${escapeHtml(note)}</small>` : ""}</dd></div>
      `;
      }).join("")}</dl>`
    : "";
  const detailsLine = entry.details || (componentRows.length === 0 ? `${entry.insurer} - ubezpieczenie komunikacyjne` : "");
  return `
      <section class="quote-result-variant">
        <span class="quote-result-copy">
          <strong>${escapeHtml(entry.label)}</strong>
          ${detailsLine ? `<small>${escapeHtml(detailsLine)}</small>` : ""}
        </span>
        <span class="quote-result-total">
          <small>Łączna składka</small>
          <span class="quote-result-price">${escapeHtml(entry.amount)}</span>
        </span>
        ${breakdown}
      </section>`;
}

function renderQuoteResultInsurerCard(group) {
  const expanded = expandedQuoteResultInsurers.has(group.key);
  const variantsMarkup = group.entries.map((entry) => renderQuoteResultVariantSection(entry)).join("");
  const headline = getQuoteResultHeadlinePremium(group.entries);
  return `
      <article class="quote-result-card${expanded ? " quote-result-card--expanded" : ""}" data-insurer="${escapeHtml(group.insurer)}" data-insurer-key="${escapeHtml(group.key)}" data-variant-count="${group.entries.length}" role="button" tabindex="0" aria-expanded="${expanded ? "true" : "false"}" title="Oferta ${escapeHtml(group.insurer)} - kliknij, aby pokazać albo ukryć szczegóły">
        <span class="quote-insurer-mark quote-insurer-mark--wide${getQuoteInsurerMarkModifier(group.insurer)}">${escapeHtml(group.insurer)}</span>
        <span class="quote-result-copy">
          <strong>Ubezpieczenie OC</strong>
          <small data-quote-expand-hint>${escapeHtml(buildQuoteExpandHint(group.entries.length, expanded))}</small>
        </span>
        <span class="quote-result-total">
          <small>${escapeHtml(headline.label)}</small>
          <span class="quote-result-price">${escapeHtml(headline.amount)}</span>
        </span>
        <span class="quote-result-chevron" aria-hidden="true"></span>
        <div class="quote-result-variants">
          ${variantsMarkup}
          <button type="button" class="quote-result-open" data-quote-open-offer title="Otwórz ofertę ${escapeHtml(group.insurer)} - okno kalkulatora albo stronę towarzystwa">Otwórz ofertę ${escapeHtml(group.insurer)}</button>
        </div>
      </article>`;
}

function buildQuotePrintGroups(premiums = renderedQuotePremiums) {
  const groups = [];
  const groupsByKey = new Map();
  for (const entry of normalizeQuotePremiumEntries(premiums).filter((item) => isInsurerServed(item.insurer))) {
    const key = normalize(entry.insurer) || entry.insurer.toLocaleLowerCase("pl-PL");
    let group = groupsByKey.get(key);
    if (!group) {
      group = {
        id: `company-${groups.length}`,
        insurer: entry.insurer,
        entries: [],
      };
      groupsByKey.set(key, group);
      groups.push(group);
    }
    group.entries.push({
      id: `${group.id}-variant-${group.entries.length}`,
      ...entry,
      ocAmount: stripQuoteAmountNote(findQuoteEntryOcAmount(entry)),
    });
  }
  for (const group of groups) group.entries.sort(compareQuoteEntriesByTotal);
  return groups.sort((first, second) => getQuoteGroupLowestOc(first) - getQuoteGroupLowestOc(second));
}

function renderQuotePrintOptions() {
  elements.quotePrintOptionsList.innerHTML = quotePrintGroups.map((group) => `
    <section class="quote-print-insurer" data-quote-print-group="${escapeHtml(group.id)}">
      <label class="quote-print-insurer-heading">
        <input type="checkbox" data-quote-print-insurer="${escapeHtml(group.id)}" checked />
        <span>${escapeHtml(group.insurer)}</span>
        <small>${escapeHtml(formatQuoteVariantCount(group.entries.length))}</small>
      </label>
      <div class="quote-print-variants">
        ${group.entries.map((entry) => `
          <div class="quote-print-variant">
            <label class="quote-print-variant-selection">
              <input type="checkbox" data-quote-print-variant="${escapeHtml(entry.id)}" data-quote-print-group-id="${escapeHtml(group.id)}" checked />
              <span>
                <strong>${escapeHtml(entry.label)}</strong>
                <small class="quote-print-variant-scope">${escapeHtml(getQuoteEntryScopeSummary(entry))}</small>
              </span>
            </label>
            <label class="quote-print-recommendation" title="Wyróżnij ten wariant na wydruku jako polecany przez agenta">
              <input type="checkbox" data-quote-print-recommended="${escapeHtml(entry.id)}" data-quote-print-group-id="${escapeHtml(group.id)}" />
              <span>Rekomendowany</span>
            </label>
            <b>${escapeHtml(entry.amount)}</b>
          </div>
        `).join("")}
      </div>
    </section>
  `).join("");
}

function getQuotePrintVariantInputs(groupId = "") {
  const selector = groupId
    ? `[data-quote-print-variant][data-quote-print-group-id="${CSS.escape(groupId)}"]`
    : "[data-quote-print-variant]";
  return [...elements.quotePrintOptionsList.querySelectorAll(selector)];
}

function updateQuotePrintSelectionState() {
  for (const group of quotePrintGroups) {
    const insurerInput = elements.quotePrintOptionsList.querySelector(
      `[data-quote-print-insurer="${CSS.escape(group.id)}"]`,
    );
    const variantInputs = getQuotePrintVariantInputs(group.id);
    const selectedCount = variantInputs.filter((input) => input.checked).length;
    if (insurerInput) {
      insurerInput.checked = selectedCount > 0 && selectedCount === variantInputs.length;
      insurerInput.indeterminate = selectedCount > 0 && selectedCount < variantInputs.length;
    }
  }
  const selectedCount = getQuotePrintVariantInputs().filter((input) => input.checked).length;
  const agencyDetailsComplete = isAgencyPrintDetailsComplete();
  elements.quotePrintAgencyWarning.hidden = agencyDetailsComplete;
  elements.confirmQuotePrint.disabled = selectedCount === 0 || !agencyDetailsComplete;
  elements.quotePrintSelectionSummary.textContent = selectedCount === 1
    ? "Wybrano 1 wariant"
    : `Wybrano ${selectedCount} wariantów`;
  elements.confirmQuotePrint.textContent = selectedCount === 0
    ? "Wybierz co najmniej jeden wariant"
    : !agencyDetailsComplete
      ? "Uzupełnij dane agencji"
      : `Otwórz PDF (${selectedCount})`;
}

function setAllQuotePrintVariants(checked) {
  for (const input of getQuotePrintVariantInputs()) input.checked = checked;
  if (!checked) {
    for (const input of elements.quotePrintOptionsList.querySelectorAll("[data-quote-print-recommended]")) {
      input.checked = false;
    }
  }
  updateQuotePrintSelectionState();
}

function handleQuotePrintOptionChange(event) {
  const input = event.target;
  if (!(input instanceof HTMLInputElement) || input.type !== "checkbox") return;
  if (input.matches("[data-quote-print-insurer]")) {
    for (const variantInput of getQuotePrintVariantInputs(input.dataset.quotePrintInsurer || "")) {
      variantInput.checked = input.checked;
    }
    if (!input.checked) {
      const groupId = input.dataset.quotePrintInsurer || "";
      for (const recommendedInput of elements.quotePrintOptionsList.querySelectorAll(
        `[data-quote-print-recommended][data-quote-print-group-id="${CSS.escape(groupId)}"]`,
      )) {
        recommendedInput.checked = false;
      }
    }
  } else if (input.matches("[data-quote-print-recommended]") && input.checked) {
    const variantInput = elements.quotePrintOptionsList.querySelector(
      `[data-quote-print-variant="${CSS.escape(input.dataset.quotePrintRecommended || "")}"]`,
    );
    if (variantInput) variantInput.checked = true;
  } else if (input.matches("[data-quote-print-variant]") && !input.checked) {
    const recommendedInput = elements.quotePrintOptionsList.querySelector(
      `[data-quote-print-recommended="${CSS.escape(input.dataset.quotePrintVariant || "")}"]`,
    );
    if (recommendedInput) recommendedInput.checked = false;
  }
  updateQuotePrintSelectionState();
}

function closeQuotePrintDialog() {
  if (elements.quotePrintDialog.open) elements.quotePrintDialog.close();
}

function openQuotePrintDialog() {
  quotePrintGroups = buildQuotePrintGroups();
  if (quotePrintGroups.length === 0) {
    showToast("Brak składek do wydruku", "warning");
    return;
  }
  renderQuotePrintOptions();
  updateQuotePrintSelectionState();
  elements.quotePrintDialog.showModal();
}

function openAgencyPrintDetailsSettings() {
  closeQuotePrintDialog();
  openSettingsDialog();
  setSettingsTab("print-details");
  globalThis.setTimeout(() => {
    const details = normalizeAgencyPrintDetails(uiSettings.agencyPrintDetails);
    (details.name
      ? details.address
        ? details.email
          ? elements.agencyPrintPhone
          : elements.agencyPrintEmail
        : elements.agencyPrintAddress
      : elements.agencyPrintName)?.focus();
  }, 0);
}

function collectSelectedQuotePrintGroups() {
  return quotePrintGroups.map((group) => ({
    insurer: group.insurer,
    entries: group.entries.filter((entry) => (
      elements.quotePrintOptionsList.querySelector(
        `[data-quote-print-variant="${CSS.escape(entry.id)}"]`,
      )?.checked === true
    )).map((entry) => ({
      ...entry,
      recommended: elements.quotePrintOptionsList.querySelector(
        `[data-quote-print-recommended="${CSS.escape(entry.id)}"]`,
      )?.checked === true,
    })),
  })).filter((group) => group.entries.length > 0);
}

async function createQuoteOfferPdf() {
  const agency = normalizeAgencyPrintDetails(uiSettings.agencyPrintDetails);
  if (!isAgencyPrintDetailsComplete(agency)) {
    updateQuotePrintSelectionState();
    showToast("Uzupełnij wszystkie dane agencji przed wydrukiem", "warning");
    return;
  }
  const insurers = collectSelectedQuotePrintGroups();
  if (insurers.length === 0) {
    updateQuotePrintSelectionState();
    showToast("Wybierz co najmniej jeden wariant", "warning");
    return;
  }
  if (!globalThis.QuoteOfferPdfRenderer?.create) {
    showToast("Brakuje modułu wydruku kalkulacji", "error");
    return;
  }

  const context = renderedQuoteResultsContext || {};
  const registration = normalizeQuoteRegistration(context.registration);
  const clientInfo = buildQuoteClientInfo(registration, normalizeQuotePesel(context.pesel));
  const vehicleName = [
    clientInfo?.merged?.vehicleMake,
    clientInfo?.merged?.vehicleModel,
  ].filter(Boolean).join(" ").trim();
  const calculatedAt = String(context.calculatedAt || activeQuoteBatch?.startedAt || "");
  const now = new Date();
  const previewWindow = globalThis.open("", "_blank");
  if (previewWindow) {
    showPreviewLoadingMessage(previewWindow, "Przygotowywanie PDF", "Przygotowywanie zestawienia składek…");
  }
  closeQuotePrintDialog();

  try {
    const pdfBytes = await globalThis.QuoteOfferPdfRenderer.create({
      agency: {
        ...agency,
        displayName: normalizeDatabaseName(uiSettings.databaseName),
        logoDataUrl: uiSettings.logoDataUrl || "",
      },
      quote: {
        clientName: String(clientInfo?.merged?.clientName || "").trim(),
        registration,
        vehicleName,
        insurancePeriod: buildNextQuoteInsurancePeriod(clientInfo?.merged),
        calculatedAt,
        generatedAt: now,
      },
      insurers,
      disclaimer: QUOTE_OFFER_DISCLAIMER,
    });
    const registrationPart = registration ? `-${registration.toLocaleLowerCase("pl-PL")}` : "";
    const fileName = `zestawienie-skladek${registrationPart}-${formatDateForInput(now)}.pdf`;
    const openedInNewTab = openOrDownloadPoliciesPdf(pdfBytes, previewWindow, fileName);
    showToast(openedInNewTab
      ? "Zestawienie składek otwarto w nowej karcie"
      : "Zestawienie składek jest gotowe do zapisu");
  } catch (error) {
    if (previewWindow && !previewWindow.closed) previewWindow.close();
    console.error(error);
    showToast(error?.message || "Nie udało się przygotować zestawienia składek", "error");
  }
}

function normalizeQuoteHistoryEntries(rawEntries) {
  if (!Array.isArray(rawEntries)) return [];
  const oldestAllowedTimestamp = Date.now() - (QUOTE_HISTORY_RETENTION_DAYS * DAY_IN_MILLISECONDS);
  return rawEntries
    .filter((entry) => {
      if (!entry
        || typeof entry !== "object"
        || !Array.isArray(entry.premiums)
        || entry.premiums.length === 0) return false;
      const savedAtTimestamp = Date.parse(String(entry.savedAt || ""));
      return Number.isFinite(savedAtTimestamp) && savedAtTimestamp >= oldestAllowedTimestamp;
    })
    .slice(0, QUOTE_HISTORY_LIMIT);
}

function saveActiveQuoteBatchToHistory() {
  const batch = activeQuoteBatch;
  if (!batch) return;
  const premiums = normalizeQuotePremiumEntries(getParallelQuotePremiums());
  if (premiums.length === 0) return;
  const entry = {
    id: getQuoteBatchHistoryEntryId(batch),
    savedAt: batch.startedAt,
    registration: batch.registration,
    pesel: batch.pesel,
    premiums,
  };
  quoteHistorySaveQueue = quoteHistorySaveQueue
    .catch(() => {})
    .then(async () => {
      const stored = await getRememberedFileSnapshot(QUOTE_HISTORY_SNAPSHOT_KEY);
      
      
      
      const entries = normalizeQuoteHistoryEntries(stored?.entries)
        .filter((existing) => existing.id !== entry.id);
      entries.unshift(entry);
      await rememberFileSnapshot(QUOTE_HISTORY_SNAPSHOT_KEY, {
        version: 1,
        updatedAt: new Date().toISOString(),
        entries: entries.slice(0, QUOTE_HISTORY_LIMIT),
      });
      
      
      if (getQuoteBatchHistoryEntryId(activeQuoteBatch) === entry.id || activeQuoteArchiveEntryId === entry.id) {
        activeQuoteArchiveEntryId = String(entry.id || "") || null;
      }
      await renderQuoteArchiveList().catch(() => {});
    })
    .catch(() => {});
}




function getQuoteBatchHistoryEntryId(batch) {
  return String(batch?.historyEntryId || batch?.id || "");
}

async function findSavedQuoteCalculation({ registration = "", pesel = "" } = {}) {
  let stored = null;
  try {
    stored = await getRememberedFileSnapshot(QUOTE_HISTORY_SNAPSHOT_KEY);
  } catch {
    return null;
  }
  const entries = normalizeQuoteHistoryEntries(stored?.entries);
  if (entries.length === 0) return null;
  if (!registration && !pesel) return entries[0];
  return entries.find((entry) => (!registration || normalizeQuoteRegistration(entry.registration) === registration)
    && (!pesel || normalizeQuotePesel(entry.pesel) === pesel)) || null;
}

async function restoreSavedQuoteResultsIntoDialog() {
  if (quoteCalculationActive || quoteCancellationPending) return;
  const token = ++quoteResultsRestoreToken;
  const registration = normalizeQuoteRegistration(elements.quoteRegistration.value);
  const pesel = normalizeQuotePesel(elements.quotePesel.value);
  if ((registration && registration.length < 4) || (pesel && pesel.length !== 11)) return;
  const hasQuery = registration.length >= 4 || pesel.length === 11;
  
  if (!hasQuery) return;
  const entry = await findSavedQuoteCalculation({
    registration: registration.length >= 4 ? registration : "",
    pesel: pesel.length === 11 ? pesel : "",
  });
  const currentRegistration = normalizeQuoteRegistration(elements.quoteRegistration.value);
  const currentPesel = normalizeQuotePesel(elements.quotePesel.value);
  if (token !== quoteResultsRestoreToken
    || quoteCalculationActive
    || quoteCancellationPending
    || currentRegistration !== registration
    || currentPesel !== pesel
    || !entry) return;
  if (quoteJobStates.size > 0 && !elements.quoteResults.hidden) return;
  if (!elements.quoteRegistration.value && entry.registration) {
    elements.quoteRegistration.value = normalizeQuoteRegistration(entry.registration);
  }
  if (!elements.quotePesel.value && entry.pesel) {
    elements.quotePesel.value = normalizeQuotePesel(entry.pesel);
  }
  renderQuoteClientInfo();
  renderQuoteResults(entry.premiums, {
    calculatedAt: entry.savedAt,
    savedFromHistory: true,
    registration: entry.registration,
    pesel: entry.pesel,
  });
  setQuoteArchiveActiveEntry(String(entry.id || ""));
  renderQuoteArchiveList().catch(() => {});
}

function formatQuoteVariantCount(count) {
  if (count === 1) return "1 wariant";
  const lastTwoDigits = count % 100;
  const lastDigit = count % 10;
  if (lastDigit >= 2 && lastDigit <= 4 && !(lastTwoDigits >= 12 && lastTwoDigits <= 14)) {
    return `${count} warianty`;
  }
  return `${count} wariantów`;
}

function setQuoteArchiveActiveEntry(entryId) {
  activeQuoteArchiveEntryId = String(entryId || "") || null;
  if (!elements.quoteArchiveList) return;
  for (const button of elements.quoteArchiveList.querySelectorAll("button[data-archive-id]")) {
    button.dataset.active = button.dataset.archiveId === activeQuoteArchiveEntryId ? "true" : "false";
  }
}



function buildQuoteArchiveClientNameIndexes() {
  const byRegistration = new Map();
  const byPesel = new Map();
  for (const policy of policies) {
    if (!String(policy?.clientName || "").trim()) continue;
    const registration = normalizeQuoteRegistration(policy?.registration);
    if (registration.length >= 4) {
      const current = byRegistration.get(registration);
      if (!current || compareQuotePolicyRecency(policy, current) < 0) byRegistration.set(registration, policy);
    }
    const pesel = getQuoteRecordPesel(policy);
    if (pesel) {
      const current = byPesel.get(pesel);
      if (!current || compareQuotePolicyRecency(policy, current) < 0) byPesel.set(pesel, policy);
    }
  }
  return { byRegistration, byPesel };
}



function findQuoteArchiveClientName(entry, nameIndexes) {
  const pesel = normalizeQuotePesel(entry.pesel);
  const registration = normalizeQuoteRegistration(entry.registration);
  const record = (pesel.length === 11 ? nameIndexes.byPesel.get(pesel) : null)
    || (registration.length >= 4 ? nameIndexes.byRegistration.get(registration) : null)
    || null;
  return String(record?.clientName || "").trim();
}

function formatQuoteArchiveHiddenCountLabel(count) {
  if (count === 1) return "1 starsza kalkulacja";
  const lastTwoDigits = count % 100;
  const lastDigit = count % 10;
  if (lastDigit >= 2 && lastDigit <= 4 && !(lastTwoDigits >= 12 && lastTwoDigits <= 14)) {
    return `${count} starsze kalkulacje`;
  }
  return `${count} starszych kalkulacji`;
}

function renderQuoteArchiveItemMarkup({ entryKey, entry }, { groupKey, clientName = "", hiddenCount = 0, sub = false }) {
  const savedAtTimestamp = Date.parse(String(entry.savedAt || ""));
  const dateLabel = SHORT_DATE_TIME_FORMAT.format(new Date(savedAtTimestamp));
  const premiums = normalizeQuotePremiumEntries(entry.premiums).filter((premium) => isInsurerServed(premium.insurer));
  const insurerNames = [...new Set(premiums.map((premium) => premium.insurer))];
  const premiumsLabel = `${insurerNames.join(", ")} - ${formatQuoteVariantCount(premiums.length)}`;
  const isActive = entryKey === activeQuoteArchiveEntryId;
  const sharedAttributes = `data-archive-id="${escapeHtml(entryKey)}" data-group-key="${escapeHtml(groupKey)}" data-active="${isActive ? "true" : "false"}"`;
  
  
  const deleteButtonMarkup = `<button type="button" class="quote-archive-delete" data-archive-delete="${escapeHtml(entryKey)}" title="Usuń tę kalkulację z archiwum" aria-label="Usuń tę kalkulację z archiwum">×</button>`;
  if (sub) {
    return `
      <div class="quote-archive-entry">
      <button type="button" class="quote-archive-item quote-archive-item--sub" ${sharedAttributes} title="Pokaż składki z tej kalkulacji">
        <strong>${escapeHtml(dateLabel)}</strong>
        <small>${escapeHtml(premiumsLabel)}</small>
      </button>
      ${deleteButtonMarkup}
      </div>`;
  }
  const clientLabel = [entry.registration, entry.pesel]
    .map((value) => String(value || "").trim())
    .filter(Boolean)
    .join(" · ");
  const headline = clientName || clientLabel || dateLabel;
  const detailLine = headline === dateLabel ? premiumsLabel : `${dateLabel} · ${premiumsLabel}`;
  const title = hiddenCount > 0
    ? "Pokaż składki i rozwiń starsze kalkulacje tego numeru rejestracyjnego"
    : "Pokaż składki z tej kalkulacji";
  return `
    <div class="quote-archive-entry">
    <button type="button" class="quote-archive-item" ${sharedAttributes} title="${title}">
      <strong>${escapeHtml(headline)}</strong>
      ${clientName && clientLabel ? `<small>${escapeHtml(clientLabel)}</small>` : ""}
      <small>${escapeHtml(detailLine)}</small>
      ${hiddenCount > 0 ? `<small class="quote-archive-more">+${escapeHtml(formatQuoteArchiveHiddenCountLabel(hiddenCount))}</small>` : ""}
    </button>
    ${deleteButtonMarkup}
    </div>`;
}

async function renderQuoteArchiveList() {
  const token = ++quoteArchiveRenderToken;
  let stored = null;
  try {
    stored = await getRememberedFileSnapshot(QUOTE_HISTORY_SNAPSHOT_KEY);
  } catch {
    stored = null;
  }
  if (token !== quoteArchiveRenderToken) return;
  
  
  
  const registrationFilter = normalizeQuoteRegistration(elements.quoteRegistration.value);
  const allEntries = normalizeQuoteHistoryEntries(stored?.entries).filter((entry) => (
    normalizeQuotePremiumEntries(entry.premiums).some((premium) => isInsurerServed(premium.insurer))
  ));
  const entries = registrationFilter
    ? allEntries.filter((entry) => normalizeQuoteRegistration(entry.registration) === registrationFilter)
    : allEntries;
  quoteArchiveEntriesById = new Map();
  const groups = new Map();
  entries.forEach((entry, index) => {
    const entryKey = String(entry.id || `wpis-${index}`);
    quoteArchiveEntriesById.set(entryKey, entry);
    const registrationKey = normalizeQuoteRegistration(entry.registration);
    const groupKey = registrationKey || `bez-numeru:${entryKey}`;
    if (!groups.has(groupKey)) groups.set(groupKey, []);
    groups.get(groupKey).push({ entryKey, entry });
  });
  elements.quoteArchive.hidden = groups.size === 0;
  const nameIndexes = buildQuoteArchiveClientNameIndexes();
  elements.quoteArchiveList.innerHTML = [...groups.entries()].map(([groupKey, groupEntries]) => {
    const [main, ...older] = groupEntries;
    const containsActiveOlder = older.some((item) => item.entryKey === activeQuoteArchiveEntryId);
    const expanded = older.length > 0
      && (groupKey === registrationFilter || groupKey === expandedQuoteArchiveGroupKey || containsActiveOlder);
    const mainMarkup = renderQuoteArchiveItemMarkup(main, {
      groupKey,
      clientName: findQuoteArchiveClientName(main.entry, nameIndexes),
      hiddenCount: expanded ? 0 : older.length,
    });
    const olderMarkup = expanded
      ? older.map((item) => renderQuoteArchiveItemMarkup(item, { groupKey, sub: true })).join("")
      : "";
    return `<div class="quote-archive-group" data-expanded="${expanded ? "true" : "false"}">${mainMarkup}${olderMarkup}</div>`;
  }).join("");
}

function openQuoteArchiveEntry(entryId, groupKey = "") {
  const entry = quoteArchiveEntriesById.get(String(entryId || ""));
  if (!entry) return;
  if (quoteCalculationActive || quoteCancellationPending) {
    showToast("Poczekaj na zakończenie trwającej kalkulacji", "warning");
    return;
  }
  clearQuoteDisplayedContext();
  expandedQuoteArchiveGroupKey = String(groupKey || "") || normalizeQuoteRegistration(entry.registration) || null;
  elements.quoteRegistration.value = normalizeQuoteRegistration(entry.registration);
  elements.quotePesel.value = normalizeQuotePesel(entry.pesel);
  renderQuoteClientInfo();
  renderQuoteResults(entry.premiums, {
    calculatedAt: entry.savedAt,
    savedFromHistory: true,
    registration: entry.registration,
    pesel: entry.pesel,
  });
  setQuoteArchiveActiveEntry(String(entryId || ""));
  renderQuoteArchiveList().catch(() => {});
}

function handleQuoteArchiveActivation(event) {
  const deleteButton = event.target?.closest?.("button[data-archive-delete]");
  if (deleteButton) {
    void deleteQuoteArchiveEntry(deleteButton.dataset.archiveDelete || "");
    return;
  }
  const button = event.target?.closest?.("button[data-archive-id]");
  if (!button) return;
  openQuoteArchiveEntry(button.dataset.archiveId || "", button.dataset.groupKey || "");
}

function findInsurerWebsiteUrl(insurerName) {
  const insurerKey = normalize(insurerName);
  if (!insurerKey || !isInsurerServed(insurerName)) return "";
  const configuredInsurers = normalizeInsurerSettings(uiSettings.insurers);
  const configuredInsurer = configuredInsurers.find((entry) => normalize(entry.name) === insurerKey)
    || (insurerKey === normalize("ERGO Hestia")
      ? configuredInsurers.find((entry) => normalize(entry.name) === normalize("Hestia"))
      : null);
  return configuredInsurer?.url || "";
}





async function deleteQuoteArchiveEntry(entryKey) {
  const entry = quoteArchiveEntriesById.get(String(entryKey || ""));
  if (!entry) return;
  const savedAtTimestamp = Date.parse(String(entry.savedAt || ""));
  const dateLabel = Number.isFinite(savedAtTimestamp)
    ? SHORT_DATE_TIME_FORMAT.format(new Date(savedAtTimestamp))
    : "";
  const clientLabel = [entry.registration, entry.pesel]
    .map((value) => String(value || "").trim())
    .filter(Boolean)
    .join(" · ");
  const confirmed = await requestDeleteConfirmation({
    title: "Usunięcie kalkulacji z archiwum",
    message: `Usunąć kalkulację${clientLabel ? ` ${clientLabel}` : ""}${dateLabel ? ` z ${dateLabel}` : ""}? Zapisane składki znikną z archiwum.`,
    confirmLabel: "Usuń kalkulację",
  });
  if (!confirmed) return;
  const entryId = String(entry.id || "");
  const matchesDeletedEntry = (existing) => {
    if (entryId || String(existing.id || "")) return String(existing.id || "") === entryId;
    return String(existing.savedAt || "") === String(entry.savedAt || "")
      && String(existing.registration || "") === String(entry.registration || "")
      && String(existing.pesel || "") === String(entry.pesel || "");
  };
  quoteHistorySaveQueue = quoteHistorySaveQueue
    .catch(() => {})
    .then(async () => {
      const stored = await getRememberedFileSnapshot(QUOTE_HISTORY_SNAPSHOT_KEY);
      const entries = normalizeQuoteHistoryEntries(stored?.entries);
      const remaining = entries.filter((existing) => !matchesDeletedEntry(existing));
      if (remaining.length === entries.length) return;
      await rememberFileSnapshot(QUOTE_HISTORY_SNAPSHOT_KEY, {
        version: 1,
        updatedAt: new Date().toISOString(),
        entries: remaining,
      });
    });
  try {
    await quoteHistorySaveQueue;
  } catch {
    showToast("Nie udało się usunąć kalkulacji z archiwum", "error");
    return;
  }
  
  
  if (activeQuoteArchiveEntryId === String(entryKey || "")) activeQuoteArchiveEntryId = null;
  await renderQuoteArchiveList().catch(() => {});
}

async function openQuoteOffer(insurerName) {
  const name = String(insurerName || "").trim();
  if (!name) return;
  const insurerId = normalize(name);
  if (QUOTE_AUTOMATION_INSURER_IDS.has(insurerId)) {
    try {
      const { response, data } = await quoteApiRequest(
        `/api/automation/windows/${encodeURIComponent(insurerId)}/focus`,
        {
          method: "POST",
          headers: { "Content-Type": "application/json" },
          body: JSON.stringify({
            registration: renderedQuoteResultsContext?.registration || "",
            pesel: renderedQuoteResultsContext?.pesel || "",
          }),
        },
        { timeoutMessage: `Okno ${name} nie odpowiedziało na czas.` },
      );
      if (response.ok && data?.focused === true) return;
    } catch {
    }
  }
  const websiteUrl = findInsurerWebsiteUrl(name);
  if (!websiteUrl) {
    showToast(`Brak adresu strony ${name} - uzupełnij go w Ustawieniach użytkownika`, "warning");
    return;
  }
  globalThis.open(websiteUrl, "_blank", "noopener");
}



function handleQuoteResultCardActivation(event) {
  const card = event.target?.closest?.(".quote-result-card");
  if (!card) return;
  const openOfferTrigger = event.target?.closest?.("[data-quote-open-offer]");
  if (event.type === "keydown") {
    
    if (openOfferTrigger) return;
    if (event.key !== "Enter" && event.key !== " ") return;
    event.preventDefault();
  }
  if (openOfferTrigger) {
    openQuoteOffer(card.dataset.insurer || "");
    return;
  }
  
  
  if (event.type === "click" && event.target?.closest?.(".quote-result-variants")) return;
  toggleQuoteResultCardExpansion(card);
}

function toggleQuoteResultCardExpansion(card) {
  const key = String(card.dataset.insurerKey || "") || normalize(card.dataset.insurer || "");
  if (!key) return;
  const expanded = !expandedQuoteResultInsurers.has(key);
  if (expanded) expandedQuoteResultInsurers.add(key);
  else expandedQuoteResultInsurers.delete(key);
  card.classList.toggle("quote-result-card--expanded", expanded);
  card.setAttribute("aria-expanded", expanded ? "true" : "false");
  const hintElement = card.querySelector("[data-quote-expand-hint]");
  if (hintElement) hintElement.textContent = buildQuoteExpandHint(Number(card.dataset.variantCount || "0"), expanded);
}

function openQuoteCalculatorDialog(prefill = null) {
  
  
  if (!quoteCalculationActive && !quoteCancellationPending) {
    restoreQuoteInsurerSelection();
    quoteCalculatorManualMode = false;
  }
  syncQuoteCalculatorMode();
  applyAgencyInsurerVisibility();
  expandedQuoteArchiveGroupKey = null;
  setQuoteCalculatorError();
  if (!quoteCalculationActive && !quoteCancellationPending) {
    elements.quoteProgress.hidden = true;
    elements.quoteProgress.dataset.state = "running";
  }
  const hasRecordPrefill = prefill
    && typeof prefill === "object"
    && ("registration" in prefill || "pesel" in prefill);
  if (hasRecordPrefill && (quoteCalculationActive || quoteCancellationPending)) {
    const requestedRegistration = normalizeQuoteRegistration(prefill.registration);
    const requestedPesel = normalizeQuotePesel(prefill.pesel);
    if (!quoteDisplayedContextMatches(requestedRegistration, requestedPesel)) {
      showToast(
        `Trwa kalkulacja dla ${activeQuoteBatch?.registration || "innego klienta"}. Poczekaj na jej zakończenie.`,
        "warning",
      );
    }
  } else if (hasRecordPrefill) {
    const requestedRegistration = normalizeQuoteRegistration(prefill.registration);
    const requestedPesel = normalizeQuotePesel(prefill.pesel);
    if (!quoteDisplayedContextMatches(requestedRegistration, requestedPesel)) {
      clearQuoteDisplayedContext();
    }
    elements.quoteRegistration.value = requestedRegistration;
    elements.quotePesel.value = requestedPesel;
  } else {
    const formRegistration = normalizeQuoteRegistration(elements.registrationInput.value);
    const formPesel = normalizeQuotePesel(elements.identityNumberInput.value);
    if (!elements.quoteRegistration.value && formRegistration.length >= 4) {
      elements.quoteRegistration.value = formRegistration;
    }
    if (!elements.quotePesel.value && /^\d{11}$/.test(formPesel)) {
      elements.quotePesel.value = formPesel;
    }
  }
  syncQuoteCalculationInputLock();
  
  quoteBridgeRetryAttempts = 0;
  if (wartaAutomationAvailable) {
    
    
    
    
    
    renderWartaAutomationAvailability("ready");
    checkWartaAutomationBridge({ quiet: true });
  } else {
    
    renderWartaAutomationAvailability("checking");
    checkWartaAutomationBridge();
  }
  renderQuoteClientInfo();
  elements.quoteCalculatorDialog.showModal();
  if (!quoteCalculationActive && !quoteCancellationPending) {
    requestAnimationFrame(() => elements.quoteRegistration.focus());
  }
  restoreSavedQuoteResultsIntoDialog().catch(() => {});
  renderQuoteArchiveList().catch(() => {});
}

function closeQuoteCalculatorDialog() {
  elements.quoteCalculatorDialog.close();
}

function syncQuoteCalculatorMode() {
  if (elements.quoteCalculatorEyebrow) {
    elements.quoteCalculatorEyebrow.textContent = quoteCalculatorManualMode
      ? "Ręczne kalkulacje"
      : "Automatyczne kalkulacje";
  }
  if (elements.quoteCalculatorTitle) {
    elements.quoteCalculatorTitle.textContent = quoteCalculatorManualMode
      ? "Policz ręcznie składkę komunikacyjną"
      : "Policz składkę komunikacyjną";
  }
  if (elements.startQuoteCalculation && !quoteCalculationActive && !quoteCancellationPending) {
    elements.startQuoteCalculation.textContent = "Policz składki";
  }
  if (elements.startManualQuoteCalculation && !quoteCalculationActive && !quoteCancellationPending) {
    elements.startManualQuoteCalculation.textContent = "Policz ręcznie";
  }
}

function finishQuoteCalculation() {
  globalThis.clearTimeout(quoteJobPollTimer);
  quoteJobPollTimer = null;
  quoteCalculationActive = false;
  activeQuoteJobIds.clear();
  syncQuoteCalculationInputLock();
  syncQuoteStartButton();
}

function getParallelQuotePremiums() {
  return [...quoteJobStates.values()].flatMap((job) => {
    if (job?.status !== "completed") return [];
    const insurerName = String(job.insurer || "Towarzystwo");
    return (Array.isArray(job.premiums) ? job.premiums : []).map((premium) => ({
      ...premium,
      insurer: premium?.insurer || insurerName,
    }));
  });
}

function getQuoteJobInsurerId(job) {
  return normalize(job?.insurerId || job?.insurer);
}

function hasQuoteJobStateForInsurer(insurerId) {
  const normalizedId = normalize(insurerId);
  if (!normalizedId) return false;
  for (const job of quoteJobStates.values()) {
    if (getQuoteJobInsurerId(job) === normalizedId) return true;
  }
  return false;
}




function removeSupersededQuoteJobStates(insurerId, currentJobId) {
  const normalizedId = normalize(insurerId);
  if (!normalizedId) return;
  for (const [jobId, job] of [...quoteJobStates]) {
    if (jobId === currentJobId || activeQuoteJobIds.has(jobId)) continue;
    if (getQuoteJobInsurerId(job) !== normalizedId) continue;
    quoteJobStates.delete(jobId);
    quoteJobPollFailures.delete(jobId);
  }
}

function applyCancelledQuoteJobs(jobs) {
  for (const job of jobs) {
    const jobId = String(job?.id || "");
    if (!jobId) continue;
    quoteJobStates.set(jobId, job);
    activeQuoteJobIds.delete(jobId);
    renderQuoteInsurerJob(job, job.insurerId);
  }
}

function finalizeStoppedQuoteBatch(batch, cancelledJobs, message) {
  if (activeQuoteBatch !== batch) return;
  applyCancelledQuoteJobs(cancelledJobs);
  const representedInsurerIds = new Set(
    [...quoteJobStates.values()].map((job) => normalize(job?.insurerId || job?.insurer)),
  );
  for (const insurerId of Array.isArray(batch?.selectedInsurerIds) ? batch.selectedInsurerIds : []) {
    if (representedInsurerIds.has(insurerId)) continue;
    renderQuoteInsurerJob({
      insurer: insurerId,
      status: "error",
      title: "Kalkulacja zatrzymana",
      detail: "Zadanie zostało zatrzymane przed potwierdzeniem uruchomienia.",
      premiums: [],
    }, insurerId);
  }
  activeQuoteJobIds.clear();
  const resultCount = renderQuoteResults(getParallelQuotePremiums(), {
    calculatedAt: batch?.startedAt,
    registration: batch?.registration,
    pesel: batch?.pesel,
  });
  saveActiveQuoteBatchToHistory();
  elements.quoteProgress.hidden = true;
  finishQuoteCalculation();
  const summary = resultCount > 0
    ? `${message} Zachowano ukończone wcześniej oferty: ${formatQuoteVariantCount(resultCount)}.`
    : message;
  setQuoteCalculatorError(summary);
  showToast(summary, "warning");
}

function stopQuoteBatch(
  batch = activeQuoteBatch,
  {
    message = "Kalkulacja została zatrzymana na Twoje życzenie.",
  } = {},
) {
  const knownJobIds = getCancelableQuoteJobIds();
  if (!batch && knownJobIds.length === 0) return Promise.resolve();
  if (batch?.cancellationPromise) return batch.cancellationPromise;
  if (batch) batch.cancellationRequested = true;
  globalThis.clearTimeout(quoteJobPollTimer);
  quoteJobPollTimer = null;
  quoteCancellationPending = true;
  syncQuoteCalculationInputLock();
  setQuoteProgress("Zatrzymywanie kalkulacji…", "Zamykamy aktywne zadania i okna towarzystw.");

  const operation = performQuoteCancellation(batch?.id || "", knownJobIds)
    .then((cancelledJobs) => {
      finalizeStoppedQuoteBatch(batch, cancelledJobs, message);
      return cancelledJobs;
    })
    .catch((error) => {
      if (activeQuoteBatch === batch) {
        setQuoteCalculatorError(
          `${String(error?.message || "Nie udało się potwierdzić zatrzymania kalkulacji.")} Spróbuj ponownie.`,
        );
        setQuoteProgress(
          "Nie potwierdzono zatrzymania",
          "Pola pozostają zablokowane, aby nie uruchomić drugiej kalkulacji na tych samych oknach.",
          "error",
        );
      }
      throw error;
    })
    .finally(() => {
      if (batch?.cancellationPromise === operation) batch.cancellationPromise = null;
      quoteCancellationPending = false;
      syncQuoteCalculationInputLock();
    });
  if (batch) batch.cancellationPromise = operation;
  operation.catch(() => {});
  return operation;
}

function finalizeParallelQuoteBatch() {
  if (activeQuoteBatch?.cancellationRequested === true) return;
  const manualMode = activeQuoteBatch?.manualMode === true;
  const resultCount = renderQuoteResults(getParallelQuotePremiums(), {
    calculatedAt: activeQuoteBatch?.startedAt,
    registration: activeQuoteBatch?.registration,
    pesel: activeQuoteBatch?.pesel,
  });
  if (!manualMode) saveActiveQuoteBatchToHistory();
  elements.quoteProgress.hidden = true;
  finishQuoteCalculation();
  if (manualMode) {
    setQuoteCalculatorError();
    const readyCount = [...quoteJobStates.values()]
      .filter((job) => job?.status === "manual_ready").length;
    showToast(
      readyCount > 0
        ? `Otwarto ${readyCount} ${readyCount === 1 ? "kartę" : readyCount < 5 ? "karty" : "kart"} do ręcznego liczenia`
        : "Nie udało się przygotować kart do ręcznego liczenia",
      readyCount > 0 ? "success" : "warning",
    );
    return;
  }
  const errors = [...new Set(quoteCalculationErrors.map((entry) => String(entry || "").trim()).filter(Boolean))];
  if (errors.length > 0) {
    setQuoteCalculatorError(
      `${resultCount > 0 ? "Nie wszystkie kalkulacje zakończyły się poprawnie" : "Kalkulacje nie zwróciły ofert"}: `
      + errors.join(" • "),
    );
    showToast(
      resultCount > 0
        ? `Znaleziono ${resultCount} wariantów, ale część kalkulacji wymaga uwagi`
        : "Kalkulacje nie zwróciły ofert",
      resultCount > 0 ? "warning" : "error",
    );
  } else if (resultCount > 0) {
    setQuoteCalculatorError();
    showToast(`Zakończono kalkulacje - znaleziono ${resultCount} wariantów`, "success");
  }
}

function applyParallelQuoteJobState(job) {
  if (!job || !activeQuoteJobIds.has(job.id) || activeQuoteBatch?.cancellationRequested === true) return;
  quoteJobStates.set(job.id, job);
  
  
  if (job.vehicleData) void applyQuoteCepikVehicleData(job);
  const insurerName = String(job.insurer || "Towarzystwo");
  const insurerId = normalize(insurerName);
  renderQuoteInsurerJob(job, insurerId);
  if (job.navigationLearned === true) {
    if (insurerId === "generali" && !generaliPathSaved) {
      generaliPathSaved = true;
      updateGeneraliNavigationHint();
      showToast("Zapamiętano drogę do formularza Generali", "success");
    } else if (insurerId === "mtu" && !mtuPathSaved) {
      mtuPathSaved = true;
      updateMtuNavigationHint();
      showToast("Zapamiętano drogę do formularza MTU", "success");
    } else if (insurerId === "warta" && !wartaPathSaved) {
      wartaPathSaved = true;
      updateWartaNavigationHint();
      showToast("Zapamiętano drogę do formularza Warty", "success");
    } else if (insurerId === "trasti" && !trastiPathSaved) {
      trastiPathSaved = true;
      updateTrastiNavigationHint();
      showToast("Zapamiętano drogę do formularza Trasti", "success");
    } else if (insurerId === "compensa" && !compensaPathSaved) {
      compensaPathSaved = true;
      updateCompensaNavigationHint();
      showToast("Zapamiętano drogę do formularza Compensa", "success");
    } else if (insurerId === "wiener" && !wienerPathSaved) {
      wienerPathSaved = true;
      updateWienerNavigationHint();
      showToast("Zapamiętano drogę do formularza Wiener", "success");
    }
  }

  if (job.status === "completed") {
    if (!Array.isArray(job.premiums) || job.premiums.length === 0) {
      quoteCalculationErrors.push(`${insurerName}: nie udało się odczytać składki`);
    }
    activeQuoteJobIds.delete(job.id);
    renderQuoteResults(getParallelQuotePremiums(), {
      calculatedAt: activeQuoteBatch?.startedAt,
      registration: activeQuoteBatch?.registration,
      pesel: activeQuoteBatch?.pesel,
    });
    saveActiveQuoteBatchToHistory();
  } else if (job.status === "manual_ready") {
    activeQuoteJobIds.delete(job.id);
  } else if (job.status === "manual_required" || job.status === "error") {
    quoteCalculationErrors.push(`${insurerName}: ${String(job.detail || "nie udało się dokończyć kalkulacji")}`);
    activeQuoteJobIds.delete(job.id);
  }

  if (activeQuoteJobIds.size === 0) {
    finalizeParallelQuoteBatch();
    return;
  }
  elements.quoteProgress.hidden = true;
}

async function pollQuoteJobs() {
  const polledBatch = activeQuoteBatch;
  if (
    !quoteCalculationActive
    || activeQuoteJobIds.size === 0
    || !polledBatch
    || polledBatch.cancellationRequested === true
  ) return;
  const polledJobIds = [...activeQuoteJobIds];
  await Promise.all(polledJobIds.map(async (jobId) => {
    try {
      const { response, data } = await quoteApiRequest(
        `/api/automation/jobs/${encodeURIComponent(jobId)}`,
        { cache: "no-store" },
        { timeoutMessage: "Serwer nie odpowiedział na czas podczas sprawdzania kalkulacji." },
      );
      if (!response.ok) throw new Error(data?.error || "Nie udało się odczytać stanu kalkulacji.");
      quoteJobPollFailures.delete(jobId);
      applyParallelQuoteJobState(data.job);
    } catch (error) {
      if (polledBatch.cancellationRequested === true || activeQuoteBatch !== polledBatch) return;
      
      
      
      const failures = (quoteJobPollFailures.get(jobId) || 0) + 1;
      quoteJobPollFailures.set(jobId, failures);
      if (failures < 4) return;
      quoteJobPollFailures.delete(jobId);
      const insurerName = quoteJobStates.get(jobId)?.insurer || "Towarzystwo";
      quoteCalculationErrors.push(`${insurerName}: ${error?.message || "utracono połączenie z serwerem"}`);
      renderQuoteInsurerFailure(insurerName, error?.message || "Utracono połączenie z serwerem.");
      
      
      
      
      void stopQuoteBatch(polledBatch, {
        message: "Utracono kontakt z trwającą kalkulacją, więc cała paczka została bezpiecznie zatrzymana.",
      });
    }
  }));
  if (
    !quoteCalculationActive
    || activeQuoteBatch !== polledBatch
    || polledBatch.cancellationRequested === true
  ) return;
  if (activeQuoteJobIds.size === 0) {
    finalizeParallelQuoteBatch();
    return;
  }
  quoteJobPollTimer = globalThis.setTimeout(pollQuoteJobs, 800);
}

async function repairQuoteJobManually(event) {
  if (quoteCancellationPending || activeQuoteBatch?.cancellationRequested === true) {
    showToast("Najpierw dokończ zatrzymywanie poprzedniej kalkulacji.", "warning");
    return;
  }
  const button = event.currentTarget;
  const jobId = String(button?.dataset?.jobId || "");
  const previousJob = quoteJobStates.get(jobId);
  if (!jobId || !previousJob || previousJob.manualAvailable !== true) return;

  const insurerErrorPrefix = `${String(previousJob.insurer || "")}:`;
  quoteCalculationErrors = quoteCalculationErrors
    .filter((entry) => !String(entry || "").startsWith(insurerErrorPrefix));
  setQuoteCalculatorError(quoteCalculationErrors.join(" • "));
  button.disabled = true;
  const queuedJob = {
    ...previousJob,
    status: "queued",
    title: `Otwieranie ${previousJob.insurer} do poprawienia ręcznego…`,
    detail: "Google Chrome otworzy się po potwierdzeniu żądania.",
    manualAvailable: false,
  };
  quoteJobStates.set(jobId, queuedJob);
  renderQuoteInsurerJob(queuedJob);
  activeQuoteJobIds.add(jobId);
  quoteJobPollFailures.delete(jobId);
  quoteCalculationActive = true;
  syncQuoteCalculationInputLock();
  elements.startQuoteCalculation.disabled = true;
  elements.quoteProgress.hidden = true;
  const repairBatch = activeQuoteBatch;

  try {
    const { response, data } = await quoteApiRequest(
      `/api/automation/jobs/${encodeURIComponent(jobId)}/manual`,
      {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: "{}",
      },
      {
        timeoutMs: QUOTE_START_REQUEST_TIMEOUT_MS,
        timeoutMessage: "Serwer nie potwierdził uruchomienia poprawiania ręcznego na czas.",
      },
    );
    if (!response.ok) {
      const rejection = new Error(data?.error || "Nie udało się uruchomić poprawiania ręcznego.");
      rejection.code = "QUOTE_MANUAL_REJECTED";
      throw rejection;
    }
    if (repairBatch?.cancellationRequested === true || activeQuoteBatch !== repairBatch) {
      if (data?.job?.id) void cancelQuoteJobRequest(data.job.id).catch(() => {});
      return;
    }
    quoteJobStates.set(jobId, data.job);
    renderQuoteInsurerJob(data.job);
    globalThis.clearTimeout(quoteJobPollTimer);
    quoteJobPollTimer = globalThis.setTimeout(pollQuoteJobs, 400);
  } catch (error) {
    if (repairBatch?.cancellationRequested === true || activeQuoteBatch !== repairBatch) return;
    if (
      error?.code !== "QUOTE_MANUAL_REJECTED"
      && error?.code !== PIN_SESSION_MANUAL_RETRY_CODE
    ) {
      void stopQuoteBatch(repairBatch, {
        message: "Nie udało się jednoznacznie potwierdzić startu poprawiania ręcznego, więc paczka została bezpiecznie zatrzymana.",
      });
      return;
    }
    activeQuoteJobIds.delete(jobId);
    quoteJobPollFailures.delete(jobId);
    const failedJob = {
      ...previousJob,
      status: "manual_required",
      title: `${previousJob.insurer} nadal wymaga poprawienia ręcznego`,
      detail: String(error?.message || "Nie udało się otworzyć Google Chrome."),
      manualAvailable: true,
    };
    quoteJobStates.set(jobId, failedJob);
    renderQuoteInsurerJob(failedJob);
    quoteCalculationErrors.push(`${previousJob.insurer}: ${failedJob.detail}`);
    if (activeQuoteJobIds.size === 0) finalizeParallelQuoteBatch();
  }
}




const QUOTE_INSURER_SELECTION_STORAGE_KEY = "iseca-kalkulacja-towarzystwa-v1";

function getQuoteInsurerCheckboxEntries() {
  return [
    ["warta", elements.quoteInsurerWarta],
    ["mtu", elements.quoteInsurerMtu],
    ["generali", elements.quoteInsurerGenerali],
    ["trasti", elements.quoteInsurerTrasti],
    ["wiener", elements.quoteInsurerWiener],
    ["compensa", elements.quoteInsurerCompensa],
    ["allianz", elements.quoteInsurerAllianz],
  ];
}

function saveQuoteInsurerSelection(selectedInsurerIds) {
  try {
    globalThis.localStorage?.setItem(
      QUOTE_INSURER_SELECTION_STORAGE_KEY,
      JSON.stringify([...selectedInsurerIds]),
    );
  } catch {
  }
}

function restoreQuoteInsurerSelection() {
  let storedIds = null;
  try {
    const raw = globalThis.localStorage?.getItem(QUOTE_INSURER_SELECTION_STORAGE_KEY);
    const parsed = raw ? JSON.parse(raw) : null;
    if (Array.isArray(parsed)) storedIds = new Set(parsed.filter((id) => typeof id === "string"));
  } catch {
  }
  
  if (!storedIds || storedIds.size === 0) return;
  for (const [insurerId, checkbox] of getQuoteInsurerCheckboxEntries()) {
    if (!checkbox) continue;
    checkbox.checked = storedIds.has(insurerId);
    
    
    delete checkbox.dataset.autoUnchecked;
  }
}

function getSelectedQuoteInsurerIds() {
  return [
    ["warta", "Warta", elements.quoteInsurerWarta],
    ["mtu", "MTU", elements.quoteInsurerMtu],
    ["generali", "Generali", elements.quoteInsurerGenerali],
    ["trasti", "Trasti", elements.quoteInsurerTrasti],
    ["wiener", "Wiener", elements.quoteInsurerWiener],
    ["compensa", "Compensa", elements.quoteInsurerCompensa],
    ["allianz", "Allianz", elements.quoteInsurerAllianz],
  ]
    .filter(([, insurerName, checkbox]) => isInsurerServed(insurerName) && checkbox?.checked)
    .map(([insurerId]) => insurerId);
}

async function startQuoteCalculation(event, { manualMode = false } = {}) {
  event.preventDefault();
  setQuoteCalculatorError();
  if (quoteCalculationActive || quoteCancellationPending) return;
  quoteCalculatorManualMode = manualMode;
  syncQuoteCalculatorMode();
  const selectedInsurers = [
    isInsurerServed("warta") && elements.quoteInsurerWarta.checked && {
      id: "warta",
      name: "Warta",
      endpoint: "/api/warta/quotes",
      username: uiSettings.calculatorAccounts?.warta?.username || "",
    },
    isInsurerServed("mtu") && elements.quoteInsurerMtu.checked && {
      id: "mtu",
      name: "MTU",
      endpoint: "/api/mtu/quotes",
      username: uiSettings.calculatorAccounts?.mtu?.username || "",
    },
    isInsurerServed("generali") && elements.quoteInsurerGenerali.checked && {
      id: "generali",
      name: "Generali",
      endpoint: "/api/generali/quotes",
      username: uiSettings.calculatorAccounts?.generali?.username || "",
    },
    isInsurerServed("trasti") && elements.quoteInsurerTrasti.checked && {
      id: "trasti",
      name: "Trasti",
      endpoint: "/api/trasti/quotes",
      username: uiSettings.calculatorAccounts?.trasti?.username || "",
    },
    isInsurerServed("wiener") && elements.quoteInsurerWiener.checked && {
      id: "wiener",
      name: "Wiener",
      endpoint: "/api/wiener/quotes",
      username: uiSettings.calculatorAccounts?.wiener?.username || "",
    },
    isInsurerServed("compensa") && elements.quoteInsurerCompensa.checked && {
      id: "compensa",
      name: "Compensa",
      endpoint: "/api/compensa/quotes",
      username: uiSettings.calculatorAccounts?.compensa?.username || "",
    },
    isInsurerServed("allianz") && elements.quoteInsurerAllianz.checked && {
      id: "allianz",
      name: "Allianz",
      endpoint: "/api/allianz/quotes",
      username: uiSettings.calculatorAccounts?.allianz?.username || "",
    },
  ].filter(Boolean);
  const selectedInsurerFingerprint = selectedInsurers.map((insurer) => insurer.id).join("|");
  if (selectedInsurers.length === 0) {
    setQuoteCalculatorError("Wybierz co najmniej jedno towarzystwo.");
    return;
  }
  const registration = normalizeQuoteRegistration(elements.quoteRegistration.value);
  const pesel = normalizeQuotePesel(elements.quotePesel.value);
  elements.quoteRegistration.value = registration;
  elements.quotePesel.value = pesel;
  if (registration.length < 4) {
    setQuoteCalculatorError("Wpisz prawidłowy numer rejestracyjny pojazdu.");
    elements.quoteRegistration.focus();
    return;
  }
  if ((!manualMode || pesel) && !isValidPesel(pesel)) {
    setQuoteCalculatorError("Wpisz prawidłowy numer PESEL (11 cyfr z poprawną cyfrą kontrolną).");
    elements.quotePesel.focus();
    return;
  }
  const storedQuoteVin = findStoredVinForQuote(registration, pesel);
  const quoteClientInfo = buildQuoteClientInfo(registration, pesel);
  const quoteVehicleInfo = quoteClientInfo
    ? {
      ...quoteClientInfo.merged,
      driverLicenseDate: formatDriverLicenseDateDisplay(quoteClientInfo.merged.driverLicenseDate),
      firstRegistrationDate: quoteClientInfo.merged.firstRegistrationDate,
      registration,
    }
    : null;
  const lingeringJobIds = getCancelableQuoteJobIds();
  if (lingeringJobIds.length > 0) {
    const lingeringBatchId = String(activeQuoteBatch?.id || "");
    if (activeQuoteBatch) activeQuoteBatch.cancellationRequested = true;
    scheduleQuoteContextCleanup(lingeringBatchId, lingeringJobIds);
  }
  
  
  
  
  
  
  const busyStartButton = manualMode
    ? elements.startManualQuoteCalculation
    : elements.startQuoteCalculation;
  const startButtonBusyWithCleanup = pendingQuoteContextCleanups.size > 0
    && busyStartButton instanceof HTMLElement;
  if (startButtonBusyWithCleanup) {
    elements.startQuoteCalculation.disabled = true;
    elements.startManualQuoteCalculation.disabled = true;
    busyStartButton.textContent = "Zamykanie poprzedniej kalkulacji…";
  }
  try {
    await waitForPendingQuoteContextCleanups();
  } catch (error) {
    setQuoteCalculatorError(
      `${String(error?.message || "Nie udało się zamknąć poprzedniej kalkulacji.")} Spróbuj ponownie za chwilę.`,
    );
    return;
  } finally {
    if (startButtonBusyWithCleanup) {
      syncQuoteCalculatorMode();
      syncQuoteStartButton();
    }
  }
  
  
  
  
  
  
  if (!(await checkWartaAutomationBridge())) {
    await new Promise((resolve) => globalThis.setTimeout(resolve, 1_500));
    if (!(await checkWartaAutomationBridge())) {
      
      
      setQuoteCalculatorError(globalThis.location.protocol === "file:"
        ? "Automatyzacja jest nieaktywna. Uruchom aplikację plikiem „Uruchom Baza Polis.cmd”."
        : "Serwer nie odpowiada w tej chwili. Spróbuj ponownie za moment.");
      return;
    }
  }
  if (selectedInsurers.some((insurer) => insurer.id === "warta") && !hasWartaCredentials()) {
    setQuoteCalculatorError("Uzupełnij login i hasło Warty w Ustawieniach użytkownika.");
    return;
  }
  if (selectedInsurers.some((insurer) => insurer.id === "generali") && !hasGeneraliCredentials()) {
    setQuoteCalculatorError("Uzupełnij login i hasło Generali w Ustawieniach użytkownika.");
    return;
  }
  if (selectedInsurers.some((insurer) => insurer.id === "mtu") && !hasMtuCredentials()) {
    setQuoteCalculatorError("Uzupełnij login i hasło MTU w Ustawieniach użytkownika.");
    return;
  }
  if (selectedInsurers.some((insurer) => insurer.id === "trasti") && !hasTrastiCredentials()) {
    setQuoteCalculatorError("Uzupełnij adres e-mail i hasło Trasti w Ustawieniach użytkownika.");
    return;
  }
  if (selectedInsurers.some((insurer) => insurer.id === "compensa") && !hasCompensaCredentials()) {
    setQuoteCalculatorError("Uzupełnij login i hasło Compensa w Ustawieniach użytkownika.");
    return;
  }
  if (selectedInsurers.some((insurer) => insurer.id === "wiener") && !hasWienerCredentials()) {
    setQuoteCalculatorError("Uzupełnij login i hasło Wiener w Ustawieniach użytkownika.");
    return;
  }
  if (selectedInsurers.some((insurer) => insurer.id === "allianz") && !hasAllianzCredentials()) {
    setQuoteCalculatorError("Uzupełnij login i hasło Allianz w Ustawieniach użytkownika.");
    return;
  }
  
  
  
  if (normalizeQuoteRegistration(elements.quoteRegistration.value) !== registration
    || normalizeQuotePesel(elements.quotePesel.value) !== pesel
    || getSelectedQuoteInsurerIds().join("|") !== selectedInsurerFingerprint) {
    setQuoteCalculatorError("Dane klienta lub wybór towarzystw zmieniły się podczas przygotowania kalkulacji. Kliknij „Policz składki” ponownie.");
    return;
  }
  
  
  if (quoteCalculationActive || quoteCancellationPending) return;

  quoteCalculationActive = true;
  
  saveQuoteInsurerSelection(selectedInsurers.map((insurer) => insurer.id));
  syncQuoteCalculationInputLock();
  
  
  
  
  
  const continuedBatch = activeQuoteBatch
    && normalizeQuoteRegistration(activeQuoteBatch.registration) === registration
    && normalizeQuotePesel(activeQuoteBatch.pesel) === pesel
    && Boolean(activeQuoteBatch.manualMode) === manualMode
    && quoteJobStates.size > 0
    ? activeQuoteBatch
    : null;
  activeQuoteJobIds = new Set();
  if (!continuedBatch) {
    quoteJobStates = new Map();
    renderedQuoteResultsContext = null;
    renderedQuotePremiums = [];
    quotePrintGroups = [];
  } else {
    
    
    
    for (const [jobId, job] of [...quoteJobStates]) {
      if (QUOTE_CANCELABLE_JOB_STATUSES.has(String(job?.status || ""))) quoteJobStates.delete(jobId);
    }
  }
  quoteJobPollFailures = new Map();
  quoteCalculationErrors = [];
  quoteResultsRestoreToken += 1;
  const quoteBatch = {
    
    
    id: `${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`,
    registration,
    pesel,
    startedAt: continuedBatch ? continuedBatch.startedAt : new Date().toISOString(),
    selectedInsurerIds: selectedInsurers.map((insurer) => insurer.id),
    manualMode,
    cancellationRequested: false,
    cancellationPromise: null,
  };
  quoteBatch.historyEntryId = continuedBatch
    ? getQuoteBatchHistoryEntryId(continuedBatch)
    : quoteBatch.id;
  activeQuoteBatch = quoteBatch;
  setQuoteArchiveActiveEntry(quoteBatch.historyEntryId);
  if (!continuedBatch) {
    elements.quoteResults.hidden = true;
    syncQuoteResultsColumn();
    elements.quoteResultsList.innerHTML = "";
  }
  renderWartaAutomationAvailability("ready");
  elements.quoteProgress.hidden = true;
  ["warta", "mtu", "generali", "trasti", "wiener", "compensa", "allianz"].forEach((insurerId) => {
    const selectedForThisRun = selectedInsurers.some((insurer) => insurer.id === insurerId);
    
    
    if (continuedBatch && !selectedForThisRun && hasQuoteJobStateForInsurer(insurerId)) return;
    resetQuoteInsurerCard(insurerId);
    const ui = getQuoteInsurerUi(insurerId);
    if (ui) ui.status.textContent = selectedForThisRun
      ? (manualMode ? "Oczekuje na otwarcie karty…" : "Oczekuje na uruchomienie…")
      : "Nie wybrano do tej kalkulacji";
  });
  const launchPromise = Promise.all(selectedInsurers.map(async (insurer) => {
    if (quoteBatch.cancellationRequested || activeQuoteBatch !== quoteBatch) return;
    renderQuoteInsurerJob({
      insurer: insurer.id,
      status: "queued",
      title: manualMode ? "Karta oczekuje na otwarcie" : "Kalkulacja oczekuje na uruchomienie",
      detail: "",
      premiums: [],
    }, insurer.id);
    try {
      const quoteRequestPayload = {
        registration,
        pesel,
        username: insurer.username,
        clientBatchId: quoteBatch.id,
        manualMode,
      };
      if (storedQuoteVin) quoteRequestPayload.vin = storedQuoteVin;
      if (quoteVehicleInfo) quoteRequestPayload.vehicleInfo = quoteVehicleInfo;
      const { response, data } = await quoteApiRequest(
        insurer.endpoint,
        {
          method: "POST",
          headers: { "Content-Type": "application/json" },
          body: JSON.stringify(quoteRequestPayload),
        },
        {
          timeoutMs: QUOTE_START_REQUEST_TIMEOUT_MS,
          timeoutMessage: `Serwer nie potwierdził uruchomienia kalkulacji ${insurer.name} na czas.`,
        },
      );
      if (!response.ok) {
        const rejection = new Error(data?.error || `Nie udało się uruchomić kalkulacji ${insurer.name}.`);
        rejection.code = "QUOTE_START_REJECTED";
        throw rejection;
      }
      const jobId = String(data?.job?.id || "");
      if (!jobId) throw new Error("Serwer nie zwrócił identyfikatora kalkulacji.");
      if (quoteBatch.cancellationRequested || activeQuoteBatch !== quoteBatch) {
        const cancelledJob = await cancelQuoteJobRequest(jobId).catch(() => null);
        if (cancelledJob && activeQuoteBatch === quoteBatch) {
          applyCancelledQuoteJobs([cancelledJob]);
        }
        return;
      }
      activeQuoteJobIds.add(jobId);
      
      
      removeSupersededQuoteJobStates(insurer.id, jobId);
      quoteJobStates.set(jobId, data.job);
      renderQuoteInsurerJob(data.job, insurer.id);
    } catch (error) {
      if (quoteBatch.cancellationRequested || activeQuoteBatch !== quoteBatch) return;
      if (
        error?.code !== "QUOTE_START_REJECTED"
        && error?.code !== PIN_SESSION_MANUAL_RETRY_CODE
      ) {
        void stopQuoteBatch(quoteBatch, {
          message: "Serwer nie potwierdził uruchomienia wszystkich kalkulacji, więc cała paczka została bezpiecznie zatrzymana.",
        });
        return;
      }
      quoteCalculationErrors.push(`${insurer.name}: ${error?.message || "nieznany błąd"}`);
      renderQuoteInsurerFailure(insurer.id, error?.message || "Nieznany błąd");
    }
  }));
  quoteBatch.launchPromise = launchPromise;
  await launchPromise;
  if (quoteBatch.launchPromise === launchPromise) quoteBatch.launchPromise = null;
  if (quoteBatch.cancellationRequested || activeQuoteBatch !== quoteBatch) return;
  if (activeQuoteJobIds.size === 0) {
    finalizeParallelQuoteBatch();
    return;
  }
  elements.quoteProgress.hidden = true;
  quoteJobPollTimer = globalThis.setTimeout(pollQuoteJobs, 500);
}

function formatDeletedRecordsCount(count) {
  if (count === 1) return "1 usunięty rekord";
  const lastTwo = count % 100;
  const last = count % 10;
  if (last >= 2 && last <= 4 && !(lastTwo >= 12 && lastTwo <= 14)) return `${count} usunięte rekordy`;
  return `${count} usuniętych rekordów`;
}

function getDeletedRecordRemainingDays(policy, now = Date.now()) {
  const expiresAt = Number(policy.deletedAt) + (TRASH_RETENTION_DAYS * DAY_IN_MILLISECONDS);
  return Math.max(0, Math.ceil((expiresAt - now) / DAY_IN_MILLISECONDS));
}

function getSortedDeletedPolicies() {
  return [...deletedPolicies].sort((first, second) => Number(second.deletedAt) - Number(first.deletedAt));
}

function updateDeletedRecordsSettingsSummary() {
  const count = deletedPolicies.length;
  elements.deletedRecordsSummary.textContent = count > 0
    ? `${formatDeletedRecordsCount(count)} w koszu.`
    : "Kosz jest pusty.";
}

function createDeletedRecordCard(policy) {
  const safeId = escapeHtml(policy.id);
  const safeName = escapeHtml(policy.clientName || "Bez nazwy");
  const safePolicyNumber = escapeHtml(policy.policyNumber || "Brak numeru polisy");
  const safeRegistration = escapeHtml(policy.registration || "Brak rodzaju");
  const deletedDate = formatDateForInput(new Date(Number(policy.deletedAt)));
  const remainingDays = getDeletedRecordRemainingDays(policy);
  const attachmentCount = normalizePolicyAttachments(policy.attachments).length;
  const remainingLabel = remainingDays === 1 ? "1 dzień" : `${remainingDays} dni`;
  return `
    <article class="deleted-record-card" data-deleted-policy-id="${safeId}">
      <div class="deleted-record-main">
        <span class="deleted-record-name">${safeName}</span>
        <strong>${safePolicyNumber}</strong>
        <small>${safeRegistration} · usunięto ${escapeHtml(formatDate(deletedDate))}</small>
      </div>
      <div class="deleted-record-meta">
        <span class="deleted-record-expiry">Pozostało: <strong>${remainingLabel}</strong></span>
        <small>${attachmentCount > 0 ? pluralizeAttachments(attachmentCount) : "Bez załączników"}</small>
      </div>
      <div class="deleted-record-actions">
        <button type="button" data-deleted-action="restore" data-policy-id="${safeId}">Przywróć</button>
        <button class="deleted-record-delete" type="button" data-deleted-action="delete-permanently" data-policy-id="${safeId}">Usuń trwale</button>
      </div>
    </article>
  `;
}

function renderDeletedRecords() {
  const records = getSortedDeletedPolicies();
  elements.deletedRecordsList.innerHTML = records.map(createDeletedRecordCard).join("");
  elements.deletedRecordsList.hidden = records.length === 0;
  elements.deletedRecordsEmpty.hidden = records.length > 0;
  elements.deletedRecordsCount.textContent = formatDeletedRecordsCount(records.length);
  elements.deleteAllDeletedRecords.disabled = records.length === 0;
  updateDeletedRecordsSettingsSummary();
}

async function openDeletedRecordsDialog() {
  await purgeExpiredDeletedPolicies({ quiet: true });
  renderDeletedRecords();
  elements.deletedRecordsDialog.showModal();
}

function closeDeletedRecordsDialog() {
  if (elements.deletedRecordsDialog.open) elements.deletedRecordsDialog.close();
}

function createRestoredPolicy(deletedPolicy) {
  const restoredPolicy = { ...deletedPolicy };
  delete restoredPolicy.deletedAt;
  restoredPolicy.updatedAt = Date.now();
  return restoredPolicy;
}

function getUnsharedAttachmentsForDeletion(attachments) {
  const getStorageKey = (attachment) => {
    const path = normalizeAttachmentRelativePath(attachment?.relativePath);
    return path
      ? `file:${path.map((part) => part.toLocaleLowerCase("pl")).join("/")}`
      : `embedded:${attachment?.id || ""}`;
  };
  const retainedAttachmentKeys = new Set(
    [...policies, ...deletedPolicies]
      .flatMap((policy) => normalizePolicyAttachments(policy.attachments))
      .map(getStorageKey),
  );
  const uniqueAttachments = new Map();
  normalizePolicyAttachments(attachments).forEach((attachment) => {
    const storageKey = getStorageKey(attachment);
    if (!uniqueAttachments.has(storageKey)) uniqueAttachments.set(storageKey, attachment);
  });
  return [...uniqueAttachments.entries()]
    .filter(([storageKey]) => !retainedAttachmentKeys.has(storageKey))
    .map(([, attachment]) => attachment);
}

async function restoreDeletedPolicy(policyId) {
  if (!(await ensureWritableDataFile({ deferFreshnessCheck: true }))) return;
  let rollbackPolicies = policies;
  let rollbackDeletedPolicies = deletedPolicies;
  let relationshipMutationStates = new Map();
  let restoredPolicyNumber = "";
  let restoreBlockedByDuplicate = false;
  const applyRestore = () => {
    rollbackPolicies = policies;
    rollbackDeletedPolicies = deletedPolicies;
    relationshipMutationStates = new Map();
    const deletedPolicy = deletedPolicies.find((policy) => policy.id === policyId);
    if (!deletedPolicy) return policies.some((policy) => policy.id === policyId);
    if (policies.some((policy) => doPoliciesConflictForDatabaseMerge(policy, deletedPolicy))) {
      restoreBlockedByDuplicate = true;
      return false;
    }
    restoredPolicyNumber = deletedPolicy.policyNumber || "";
    const restoredPolicy = policies.find((policy) => policy.id === policyId)
      || createRestoredPolicy(deletedPolicy);
    const nextPolicies = policies.includes(restoredPolicy)
      ? policies
      : [...policies, restoredPolicy];
    policies = nextPolicies;
    deletedPolicies = deletedPolicies.filter((policy) => policy.id !== policyId);
    reconnectPolicyRenewalRelationships(restoredPolicy, relationshipMutationStates);
    return true;
  };
  if (!applyRestore()) {
    if (restoreBlockedByDuplicate) showToast("Nie można przywrócić - taka polisa z tą samą datą końca jest już w bazie", "warning");
    return;
  }
  saveStatusPopupSuccessText = "Rekord przywrócony";
  if (!(await persistPolicies({
    reapplyAfterConflict: applyRestore,
    reapplyFailureMessage: restoreBlockedByDuplicate
      ? "W nowszej bazie jest już polisa z tym samym numerem i datą końca. Rekord nie został przywrócony."
      : "Usunięty rekord zmienił się w nowszej wersji bazy i nie został przywrócony.",
  }))) {
    restorePolicyMutationStates(relationshipMutationStates);
    policies = rollbackPolicies;
    deletedPolicies = rollbackDeletedPolicies;
    markPoliciesRolledBack();
    renderDeletedRecords();
    return;
  }
  render();
  renderDeletedRecords();
  showToast(restoredPolicyNumber ? `Przywrócono polisę ${restoredPolicyNumber}` : "Przywrócono rekord");
}

async function permanentlyDeleteDeletedPolicy(policyId) {
  const initialPolicy = deletedPolicies.find((policy) => policy.id === policyId);
  if (!initialPolicy) return;
  const recordName = initialPolicy.clientName || initialPolicy.policyNumber || "ten rekord";
  const confirmed = await requestDeleteConfirmation({
    title: "Trwałe usunięcie rekordu",
    message: `Usunąć trwale „${recordName}” wraz z jego załącznikami? Tej operacji nie można cofnąć.`,
    confirmLabel: "Usuń trwale",
  });
  if (!confirmed || !(await ensureWritableDataFile({ deferFreshnessCheck: true }))) return;

  let rollbackDeletedPolicies = deletedPolicies;
  let relationshipMutationStates = new Map();
  let attachmentsToDelete = normalizePolicyAttachments(initialPolicy.attachments);
  const applyPermanentDelete = () => {
    rollbackDeletedPolicies = deletedPolicies;
    relationshipMutationStates = new Map();
    const currentPolicy = deletedPolicies.find((policy) => policy.id === policyId);
    if (!currentPolicy) {
      detachRemovedPolicyRenewalRelationships({ id: policyId }, relationshipMutationStates);
      return true;
    }
    detachRemovedPolicyRenewalRelationships(currentPolicy, relationshipMutationStates);
    attachmentsToDelete = normalizePolicyAttachments(currentPolicy.attachments);
    deletedPolicies = deletedPolicies.filter((policy) => policy.id !== policyId);
    return true;
  };
  applyPermanentDelete();
  saveStatusPopupSuccessText = "Rekord usunięty trwale";
  if (!(await persistPolicies({ reapplyAfterConflict: applyPermanentDelete }))) {
    restorePolicyMutationStates(relationshipMutationStates);
    deletedPolicies = rollbackDeletedPolicies;
    markPoliciesRolledBack();
    renderDeletedRecords();
    return;
  }
  const deletedAttachments = await deleteExternalAttachmentFiles(
    getUnsharedAttachmentsForDeletion(attachmentsToDelete),
  );
  renderDeletedRecords();
  showToast(
    deletedAttachments ? "Rekord i załączniki usunięto trwale" : "Rekord usunięto, ale część plików pozostała w folderze",
    deletedAttachments ? "success" : "warning",
  );
}

async function deleteAllDeletedPolicies() {
  if (deletedPolicies.length === 0) return;
  const confirmed = await requestDeleteConfirmation({
    title: "Opróżnienie kosza",
    message: `Usunąć trwale wszystkie rekordy z kosza (${deletedPolicies.length}) wraz z ich załącznikami? Tej operacji nie można cofnąć.`,
    confirmLabel: "Usuń wszystkie",
  });
  if (!confirmed || !(await ensureWritableDataFile({ deferFreshnessCheck: true }))) return;

  let rollbackDeletedPolicies = deletedPolicies;
  let relationshipMutationStates = new Map();
  let attachmentsToDelete = deletedPolicies.flatMap((policy) => normalizePolicyAttachments(policy.attachments));
  const applyDeleteAll = () => {
    rollbackDeletedPolicies = deletedPolicies;
    relationshipMutationStates = new Map();
    deletedPolicies.forEach((policy) => {
      detachRemovedPolicyRenewalRelationships(policy, relationshipMutationStates);
    });
    attachmentsToDelete = deletedPolicies.flatMap((policy) => normalizePolicyAttachments(policy.attachments));
    deletedPolicies = [];
    return true;
  };
  applyDeleteAll();
  saveStatusPopupSuccessText = "Kosz opróżniony";
  if (!(await persistPolicies({ reapplyAfterConflict: applyDeleteAll }))) {
    restorePolicyMutationStates(relationshipMutationStates);
    deletedPolicies = rollbackDeletedPolicies;
    markPoliciesRolledBack();
    renderDeletedRecords();
    return;
  }
  const deletedAttachments = await deleteExternalAttachmentFiles(
    getUnsharedAttachmentsForDeletion(attachmentsToDelete),
  );
  renderDeletedRecords();
  showToast(
    deletedAttachments ? "Usunięto wszystkie rekordy z kosza" : "Kosz opróżniono, ale część plików pozostała w folderze",
    deletedAttachments ? "success" : "warning",
  );
}

async function purgeExpiredDeletedPolicies(options = {}) {
  const now = Date.now();
  const expiredPolicies = deletedPolicies.filter((policy) => getDeletedRecordRemainingDays(policy, now) <= 0);
  if (expiredPolicies.length === 0 || !dataFileHandle) return 0;

  let rollbackDeletedPolicies = deletedPolicies;
  let relationshipMutationStates = new Map();
  let attachmentsToDelete = expiredPolicies.flatMap((policy) => normalizePolicyAttachments(policy.attachments));
  const applyPurge = () => {
    rollbackDeletedPolicies = deletedPolicies;
    relationshipMutationStates = new Map();
    const currentNow = Date.now();
    const expiredIds = new Set(
      deletedPolicies
        .filter((policy) => getDeletedRecordRemainingDays(policy, currentNow) <= 0)
        .map((policy) => policy.id),
    );
    deletedPolicies
      .filter((policy) => expiredIds.has(policy.id))
      .forEach((policy) => {
        detachRemovedPolicyRenewalRelationships(policy, relationshipMutationStates);
      });
    attachmentsToDelete = deletedPolicies
      .filter((policy) => expiredIds.has(policy.id))
      .flatMap((policy) => normalizePolicyAttachments(policy.attachments));
    deletedPolicies = deletedPolicies.filter((policy) => !expiredIds.has(policy.id));
    return true;
  };
  applyPurge();
  saveStatusPopupSuccessText = "Kosz uporządkowany";
  if (!(await persistPolicies({ reapplyAfterConflict: applyPurge }))) {
    restorePolicyMutationStates(relationshipMutationStates);
    deletedPolicies = rollbackDeletedPolicies;
    markPoliciesRolledBack();
    return 0;
  }
  const deletedAttachments = await deleteExternalAttachmentFiles(
    getUnsharedAttachmentsForDeletion(attachmentsToDelete),
  );
  updateDeletedRecordsSettingsSummary();
  if (!options.quiet) {
    showToast(
      deletedAttachments
        ? `Automatycznie usunięto ${formatDeletedRecordsCount(expiredPolicies.length)} starszych niż 30 dni`
        : "Stare rekordy usunięto, ale część plików pozostała w folderze",
      deletedAttachments ? "success" : "warning",
    );
  }
  return expiredPolicies.length;
}

function updateInitialSetupState() {
  const dataFileLabel = dataFileHandle?.name || dataFileName || rememberedDataFileHandle?.name || "";
  const settingsFileLabel = settingsFileHandle?.name || settingsFileName || rememberedSettingsFileHandle?.name || "";
  const setupComplete = initialDataFileReady && initialSettingsFileReady;

  const quickSetupSupported = typeof globalThis.showDirectoryPicker === "function";
  const quickFolderConnected = Boolean(appDirectoryHandle);
  const quickFolderName = appDirectoryHandle?.name || rememberedAppDirectoryHandle?.name || "";
  elements.welcomeQuickCard.style.display = quickSetupSupported ? "" : "none";
  elements.welcomeQuickSeparator.style.display = quickSetupSupported ? "" : "none";
  elements.welcomeQuickCard.dataset.ready = String(setupComplete && quickFolderConnected);
  if (quickFolderConnected) {
    elements.welcomeQuickStatus.textContent = `Gotowe: połączono folder „${quickFolderName}”`;
    elements.welcomeQuickSetup.textContent = "Zmień folder";
  } else if (quickFolderName) {
    elements.welcomeQuickStatus.textContent = `Zapamiętany folder: „${quickFolderName}” - kliknij Połącz i zezwól na dostęp.`;
    elements.welcomeQuickSetup.textContent = "Połącz";
  } else if (setupComplete) {
    elements.welcomeQuickStatus.textContent = "Pliki zostały wskazane osobno.";
    elements.welcomeQuickSetup.textContent = "Wskaż folder";
  } else {
    elements.welcomeQuickStatus.textContent = "Wskaż folder aplikacji (np. „Baza Polis”) - baza, ustawienia i załączniki skonfigurują się same.";
    elements.welcomeQuickSetup.textContent = "Wskaż folder";
  }

  const dataFilePrefilled = initialDataFileReady || Boolean(rememberedDataFileHandle);
  const settingsFilePrefilled = initialSettingsFileReady || Boolean(rememberedSettingsFileHandle);
  const readyToFinish = dataFilePrefilled && settingsFilePrefilled;

  elements.welcomeDataFileCard.dataset.ready = String(dataFilePrefilled);
  elements.welcomeSettingsFileCard.dataset.ready = String(settingsFilePrefilled);
  elements.welcomeDataFileStatus.textContent = initialDataFileReady
    ? `Gotowe: ${dataFileLabel || "plik bazy"}`
    : rememberedDataFileHandle
      ? `Wybrany: ${dataFileLabel || "plik bazy"}`
      : "Nie wybrano pliku";
  elements.welcomeSettingsFileStatus.textContent = initialSettingsFileReady
    ? `Gotowe: ${settingsFileLabel || DEFAULT_SETTINGS_FILE_NAME}`
    : rememberedSettingsFileHandle
      ? `Wybrany: ${settingsFileLabel || DEFAULT_SETTINGS_FILE_NAME}`
      : "Nie wybrano pliku";

  elements.finishInitialSetup.disabled = !readyToFinish || initialSetupFinishInProgress;
  elements.welcomeSetupHint.textContent = welcomeSetupError || (setupComplete
    ? "Wszystko gotowe. Możesz rozpocząć pracę."
    : readyToFinish
      ? "Pliki są wybrane. Kliknij „Gotowe” i zezwól na dostęp."
      : quickSetupSupported
        ? "Wskaż folder aplikacji powyżej albo oba pliki osobno, aby odblokować aplikację."
        : "Wskaż oba pliki, aby odblokować aplikację.");
  elements.welcomeSetupHint.dataset.ready = String(setupComplete && !welcomeSetupError);
}

function setWelcomeSetupError(message) {
  welcomeSetupError = message;
  updateInitialSetupState();
}

function showRequiredFileSetup() {
  updateInitialSetupState();
  if (!initialDataFileReady || !initialSettingsFileReady) {
    hideAppBusyOverlay();
    if (!elements.welcomeDialog.open) elements.welcomeDialog.showModal();
  }
}

async function finishInitialSetup() {
  if (initialSetupFinishInProgress) return;
  initialSetupFinishInProgress = true;
  welcomeSetupError = "";
  elements.finishInitialSetup.disabled = true;
  try {
    const rememberedFolder = rememberedAppDirectoryHandle || await getRememberedAppDirectoryHandle();
    if (rememberedFolder && !appDirectoryHandle) {
      try {
        if (await requestWritePermission(rememberedFolder)) {
          appDirectoryHandle = rememberedFolder;
        }
      } catch {
      }
    }

    if (appDirectoryHandle) {
      if (!dataFileHandle && rememberedDataFileHandle?.name) {
        try {
          const derived = await appDirectoryHandle.getFileHandle(rememberedDataFileHandle.name);
          if (await derived.isSameEntry(rememberedDataFileHandle)) {
            rememberedDataFileHandle = derived;
          }
        } catch {
        }
      }
      if (!settingsFileHandle && rememberedSettingsFileHandle?.name) {
        try {
          const derived = await appDirectoryHandle.getFileHandle(rememberedSettingsFileHandle.name);
          if (await derived.isSameEntry(rememberedSettingsFileHandle)) {
            rememberedSettingsFileHandle = derived;
          }
        } catch {
        }
      }
    }

    if (!dataFileHandle && rememberedDataFileHandle) {
      try {
        if (initialDataFileReady) {
          await connectRememberedDataFile();
        } else {
          if (!(await requestWritePermission(rememberedDataFileHandle))) {
            setWelcomeSetupError("Brak zgody na dostęp do pliku bazy. Kliknij „Gotowe” jeszcze raz i zezwól na dostęp.");
            return;
          }
          await loadPoliciesFromFile(await rememberedDataFileHandle.getFile(), rememberedDataFileHandle, {
            permissionGranted: true,
            showToast: false,
            trustedSource: true,
          });
        }
      } catch (error) {
        const needsFreshClick = error?.name === "SecurityError" || error?.name === "NotAllowedError";
        const message = needsFreshClick
          ? "Przeglądarka wymaga osobnego potwierdzenia dla pliku bazy. Kliknij „Gotowe” jeszcze raz."
          : `Nie udało się połączyć z plikiem bazy: ${error?.message || "nieznany błąd"}`;
        if (!initialDataFileReady) {
          setWelcomeSetupError(message);
          return;
        }
        if (!welcomeConnectFailureAccepted) {
          welcomeConnectFailureAccepted = true;
          setWelcomeSetupError(`${message} Kliknij „Gotowe” ponownie, aby mimo to pracować na lokalnej kopii.`);
          return;
        }
        dataFileNeedsVerification = true;
        setDataIntegrityNotice(
          "error",
          "Nie udało się połączyć z plikiem bazy",
          error?.message || "Wskaż plik ponownie.",
          "Wskaż plik",
        );
      }
    }

    if (!settingsFileHandle && rememberedSettingsFileHandle) {
      try {
        if (await requestWritePermission(rememberedSettingsFileHandle)) {
          await loadSettingsFromFile(await rememberedSettingsFileHandle.getFile(), rememberedSettingsFileHandle, {
            permissionGranted: true,
            showToast: false,
          });
        } else if (!initialSettingsFileReady) {
          setWelcomeSetupError("Brak zgody na dostęp do pliku ustawień. Kliknij „Gotowe” jeszcze raz i zezwól na dostęp.");
          return;
        }
      } catch (error) {
        const needsFreshClick = error?.name === "SecurityError" || error?.name === "NotAllowedError";
        const message = needsFreshClick
          ? "Przeglądarka wymaga osobnego potwierdzenia dla pliku ustawień. Kliknij „Gotowe” jeszcze raz."
          : `Nie udało się połączyć z plikiem ustawień: ${error?.message || "nieznany błąd"}`;
        if (!initialSettingsFileReady) {
          setWelcomeSetupError(message);
          return;
        }
        showToast(message, "error");
      }
    }

    let attachmentsBase = attachmentsBaseDirectoryHandle
      || rememberedAttachmentsBaseDirectoryHandle
      || await getRememberedAttachmentsDirectoryHandle();
    if (attachmentsBase && attachmentsBase !== attachmentsBaseDirectoryHandle) {
      try {
        if (appDirectoryHandle && await appDirectoryHandle.isSameEntry(attachmentsBase)) {
          attachmentsBase = appDirectoryHandle;
        }
        if (await requestWritePermission(attachmentsBase)) {
          await resolveAttachmentsRootDirectory(attachmentsBase, { create: true });
          attachmentsBaseDirectoryHandle = attachmentsBase;
          rememberedAttachmentsBaseDirectoryHandle = attachmentsBase;
        }
      } catch {
      }
    }

    if (initialDataFileReady && initialSettingsFileReady && elements.welcomeDialog.open) {
      welcomeSetupError = "";
      elements.welcomeDialog.close();
    }
  } finally {
    initialSetupFinishInProgress = false;
    updateInitialSetupState();
  }
}

function chooseSettingsTheme(theme) {
  pendingSettingsTheme = theme === "dark" ? "dark" : "light";
  applyTheme(pendingSettingsTheme);
}

function chooseSettingsFontSize(fontSize) {
  pendingSettingsFontSize = normalizeUiFontSize(fontSize);
  updateFontSizeChoices();
  applyFontSize(pendingSettingsFontSize);
}

function chooseAppearanceDockSetting() {
  pendingShowAppearanceDock = Boolean(elements.showAppearanceDockSetting.checked);
  applyAppearanceDockSetting(pendingShowAppearanceDock);
}

function chooseStartDateInputSetting() {
  pendingShowStartDateInput = Boolean(elements.showStartDateInputSetting.checked);
  applyStartDateInputSetting(pendingShowStartDateInput);
}

function chooseUsageGuideSetting() {
  pendingShowUsageGuide = Boolean(elements.showUsageGuideSetting.checked);
  applyUsageGuideSetting(pendingShowUsageGuide);
}

function readLogoFile(file) {
  return new Promise((resolve, reject) => {
    const reader = new FileReader();
    reader.onload = () => resolve(String(reader.result ?? ""));
    reader.onerror = () => reject(new Error("Nie udało się odczytać pliku logo."));
    reader.readAsDataURL(file);
  });
}

function showSettingsLogoMessage(message, type = "error") {
  elements.settingsLogoMessage.textContent = message;
  elements.settingsLogoMessage.dataset.type = type;
  elements.settingsLogoMessage.hidden = !message;
}

async function handleSettingsLogoFile() {
  if (isEmployeeAccount()) {
    showSettingsLogoMessage("Logo ustawiła centrala agencji i nie można go zmienić.");
    elements.settingsLogoInput.value = "";
    return;
  }
  const [file] = elements.settingsLogoInput.files ?? [];
  if (!file) return;
  showSettingsLogoMessage("");
  try {
    if (!ALLOWED_LOGO_TYPES.has(String(file.type ?? ""))) {
      throw new Error("Wybierz plik graficzny PNG, JPG, WEBP lub SVG.");
    }
    if (file.size > MAX_LOGO_FILE_SIZE) {
      throw new Error("Plik logo może mieć maksymalnie 2 MB.");
    }
    pendingLogoDataUrl = await readLogoFile(file);
    elements.settingsLogoPreview.src = pendingLogoDataUrl;
    showSettingsLogoMessage("Logo zostało wczytane. Zapisz ustawienia, aby je zachować.", "success");
  } catch (error) {
    showSettingsLogoMessage(error?.message || "Nie udało się wczytać logo");
  } finally {
    elements.settingsLogoInput.value = "";
  }
}

function resetSettingsLogo() {
  if (isEmployeeAccount()) {
    showSettingsLogoMessage("Logo ustawiła centrala agencji i nie można go zmienić.");
    return;
  }
  pendingLogoDataUrl = "";
  elements.settingsLogoPreview.src = DEFAULT_LOGO_SRC;
  showSettingsLogoMessage("Przywrócono domyślne logo Iseca. Zapisz ustawienia, aby zachować zmianę.", "success");
}

async function saveSettingsChanges() {
  
  if (isEmployeeAccount()) {
    pendingLogoDataUrl = uiSettings.logoDataUrl || "";
    pendingDatabaseName = normalizeDatabaseName(uiSettings.databaseName);
  } else {
    pendingDatabaseName = String(elements.settingsDatabaseName.value ?? "")
      .replace(/\s+/g, " ")
      .trim()
      .slice(0, MAX_DATABASE_NAME_LENGTH);
    if (!pendingDatabaseName) {
      setSettingsTab("print-details");
      showToast("Wpisz nazwę agencji", "warning");
      elements.settingsDatabaseName.focus();
      return;
    }
  }
  const agencyPrintDetails = normalizeAgencyPrintDetails({
    name: elements.agencyPrintName.value,
    address: elements.agencyPrintAddress.value,
    email: elements.agencyPrintEmail.value,
    phone: elements.agencyPrintPhone.value,
  });
  if (agencyPrintDetails.email && !isAgencyPrintEmailValid(agencyPrintDetails.email)) {
    setSettingsTab("print-details");
    showToast("Wpisz prawidłowy adres e-mail do wydruku", "warning");
    elements.agencyPrintEmail.focus();
    return;
  }
  const wartaUsername = String(elements.wartaUsernameSetting.value ?? "")
    .trim()
    .slice(0, MAX_CALCULATOR_USERNAME_LENGTH);
  const pendingWartaPassword = String(isWartaPasswordMaskActive() ? "" : elements.wartaPasswordSetting.value ?? "")
    .slice(0, MAX_CALCULATOR_PASSWORD_LENGTH);
  const generaliUsername = String(elements.generaliUsernameSetting.value ?? "")
    .trim()
    .slice(0, MAX_CALCULATOR_USERNAME_LENGTH);
  const pendingGeneraliPassword = String(isGeneraliPasswordMaskActive() ? "" : elements.generaliPasswordSetting.value ?? "")
    .slice(0, MAX_CALCULATOR_PASSWORD_LENGTH);
  const mtuUsername = String(elements.mtuUsernameSetting.value ?? "")
    .trim()
    .slice(0, MAX_CALCULATOR_USERNAME_LENGTH);
  const pendingMtuPassword = String(isMtuPasswordMaskActive() ? "" : elements.mtuPasswordSetting.value ?? "")
    .slice(0, MAX_CALCULATOR_PASSWORD_LENGTH);
  const hestiaUsername = String(elements.hestiaUsernameSetting.value ?? "")
    .trim()
    .slice(0, MAX_CALCULATOR_USERNAME_LENGTH);
  const pendingHestiaPassword = String(isHestiaPasswordMaskActive() ? "" : elements.hestiaPasswordSetting.value ?? "")
    .slice(0, MAX_CALCULATOR_PASSWORD_LENGTH);
  const trastiUsername = String(elements.trastiUsernameSetting.value ?? "")
    .trim()
    .slice(0, MAX_CALCULATOR_USERNAME_LENGTH);
  const pendingTrastiPassword = String(isTrastiPasswordMaskActive() ? "" : elements.trastiPasswordSetting.value ?? "")
    .slice(0, MAX_CALCULATOR_PASSWORD_LENGTH);
  const wienerUsername = String(elements.wienerUsernameSetting.value ?? "")
    .trim()
    .slice(0, MAX_CALCULATOR_USERNAME_LENGTH);
  const pendingWienerPassword = String(isWienerPasswordMaskActive() ? "" : elements.wienerPasswordSetting.value ?? "")
    .slice(0, MAX_CALCULATOR_PASSWORD_LENGTH);
  const compensaUsername = String(elements.compensaUsernameSetting.value ?? "")
    .trim()
    .slice(0, MAX_CALCULATOR_USERNAME_LENGTH);
  const pendingCompensaPassword = String(isCompensaPasswordMaskActive() ? "" : elements.compensaPasswordSetting.value ?? "")
    .slice(0, MAX_CALCULATOR_PASSWORD_LENGTH);
  const allianzUsername = String(elements.allianzUsernameSetting.value ?? "")
    .trim()
    .slice(0, MAX_CALCULATOR_USERNAME_LENGTH);
  const pendingAllianzPassword = String(isAllianzPasswordMaskActive() ? "" : elements.allianzPasswordSetting.value ?? "")
    .slice(0, MAX_CALCULATOR_PASSWORD_LENGTH);
  const inslyUsername = String(elements.inslyUsernameSetting.value ?? "")
    .trim()
    .slice(0, MAX_CALCULATOR_USERNAME_LENGTH);
  const pendingInslyPassword = String(isInslyPasswordMaskActive() ? "" : elements.inslyPasswordSetting.value ?? "")
    .slice(0, MAX_CALCULATOR_PASSWORD_LENGTH);
  const pzuUsername = String(elements.pzuUsernameSetting.value ?? "")
    .trim()
    .slice(0, MAX_CALCULATOR_USERNAME_LENGTH);
  const pendingPzuPassword = String(isPzuPasswordMaskActive() ? "" : elements.pzuPasswordSetting.value ?? "")
    .slice(0, MAX_CALCULATOR_PASSWORD_LENGTH);
  if (pendingWartaPassword && !wartaUsername) {
    setSettingsTab("user");
    showToast("Wpisz login do Warty, aby zapisać hasło", "warning");
    elements.wartaUsernameSetting.focus();
    return;
  }
  if (pendingGeneraliPassword && !generaliUsername) {
    setSettingsTab("user");
    showToast("Wpisz login do Generali, aby zapisać hasło", "warning");
    elements.generaliUsernameSetting.focus();
    return;
  }
  if (pendingMtuPassword && !mtuUsername) {
    setSettingsTab("user");
    showToast("Wpisz login / alias MTU, aby zapisać hasło", "warning");
    elements.mtuUsernameSetting.focus();
    return;
  }
  if (pendingHestiaPassword && !hestiaUsername) {
    setSettingsTab("user");
    showToast("Wpisz login / alias Ergo Hestii, aby zapisać hasło", "warning");
    elements.hestiaUsernameSetting.focus();
    return;
  }
  if (pendingTrastiPassword && !trastiUsername) {
    setSettingsTab("user");
    showToast("Wpisz adres e-mail do Trasti, aby zapisać hasło", "warning");
    elements.trastiUsernameSetting.focus();
    return;
  }
  if (pendingCompensaPassword && !compensaUsername) {
    setSettingsTab("user");
    showToast("Wpisz login do Compensy, aby zapisać hasło", "warning");
    elements.compensaUsernameSetting.focus();
    return;
  }
  if (pendingAllianzPassword && !allianzUsername) {
    setSettingsTab("user");
    showToast("Wpisz login do Allianz, aby zapisać hasło", "warning");
    elements.allianzUsernameSetting.focus();
    return;
  }
  if (pendingWienerPassword && !wienerUsername) {
    setSettingsTab("user");
    showToast("Wpisz login do Wiener, aby zapisać hasło", "warning");
    elements.wienerUsernameSetting.focus();
    return;
  }
  if (pendingInslyPassword && !inslyUsername) {
    setSettingsTab("user");
    showToast("Wpisz login do Superpolisy, aby zapisać hasło", "warning");
    elements.inslyUsernameSetting.focus();
    return;
  }
  if (pendingPzuPassword && !pzuUsername) {
    setSettingsTab("user");
    showToast("Wpisz login do PZU, aby zapisać hasło", "warning");
    elements.pzuUsernameSetting.focus();
    return;
  }
  const previousWartaUsername = uiSettings.calculatorAccounts?.warta?.username || "";
  const previousGeneraliUsername = uiSettings.calculatorAccounts?.generali?.username || "";
  const previousMtuUsername = uiSettings.calculatorAccounts?.mtu?.username || "";
  const previousHestiaUsername = uiSettings.calculatorAccounts?.hestia?.username || "";
  const previousTrastiUsername = uiSettings.calculatorAccounts?.trasti?.username || "";
  const previousWienerUsername = uiSettings.calculatorAccounts?.wiener?.username || "";
  const previousCompensaUsername = uiSettings.calculatorAccounts?.compensa?.username || "";
  const previousAllianzUsername = uiSettings.calculatorAccounts?.allianz?.username || "";
  const previousInslyUsername = uiSettings.calculatorAccounts?.insly?.username || "";
  const previousPzuUsername = uiSettings.calculatorAccounts?.pzu?.username || "";
  if (wartaUsername && wartaUsername !== previousWartaUsername && !pendingWartaPassword) {
    setSettingsTab("user");
    showToast("Przy ustawianiu lub zmianie loginu wpisz również hasło do Warty", "warning");
    elements.wartaPasswordSetting.focus();
    return;
  }
  if (generaliUsername && generaliUsername !== previousGeneraliUsername && !pendingGeneraliPassword) {
    setSettingsTab("user");
    showToast("Przy ustawianiu lub zmianie loginu wpisz również hasło do Generali", "warning");
    elements.generaliPasswordSetting.focus();
    return;
  }
  if (mtuUsername && mtuUsername !== previousMtuUsername && !pendingMtuPassword) {
    setSettingsTab("user");
    showToast("Przy ustawianiu lub zmianie loginu wpisz również hasło do MTU", "warning");
    elements.mtuPasswordSetting.focus();
    return;
  }
  if (hestiaUsername && hestiaUsername !== previousHestiaUsername && !pendingHestiaPassword) {
    setSettingsTab("user");
    showToast("Przy ustawianiu lub zmianie loginu wpisz również hasło do Ergo Hestii", "warning");
    elements.hestiaPasswordSetting.focus();
    return;
  }
  if (trastiUsername && trastiUsername !== previousTrastiUsername && !pendingTrastiPassword) {
    setSettingsTab("user");
    showToast("Przy ustawianiu lub zmianie adresu e-mail wpisz również hasło do Trasti", "warning");
    elements.trastiPasswordSetting.focus();
    return;
  }
  if (compensaUsername && compensaUsername !== previousCompensaUsername && !pendingCompensaPassword) {
    setSettingsTab("user");
    showToast("Przy ustawianiu lub zmianie loginu wpisz również hasło do Compensy", "warning");
    elements.compensaPasswordSetting.focus();
    return;
  }
  if (allianzUsername && allianzUsername !== previousAllianzUsername && !pendingAllianzPassword) {
    setSettingsTab("user");
    showToast("Przy ustawianiu lub zmianie loginu wpisz również hasło do Allianz", "warning");
    elements.allianzPasswordSetting.focus();
    return;
  }
  if (wienerUsername && wienerUsername !== previousWienerUsername && !pendingWienerPassword) {
    setSettingsTab("user");
    showToast("Przy ustawianiu lub zmianie loginu wpisz również hasło do Wiener", "warning");
    elements.wienerPasswordSetting.focus();
    return;
  }
  if (inslyUsername && inslyUsername !== previousInslyUsername && !pendingInslyPassword) {
    setSettingsTab("user");
    showToast("Przy ustawianiu lub zmianie loginu wpisz również hasło do Superpolisy", "warning");
    elements.inslyPasswordSetting.focus();
    return;
  }
  if (pzuUsername && pzuUsername !== previousPzuUsername && !pendingPzuPassword) {
    setSettingsTab("user");
    showToast("Przy ustawianiu lub zmianie loginu wpisz również hasło do PZU", "warning");
    elements.pzuPasswordSetting.focus();
    return;
  }
  let insurers;
  try {
    insurers = validatePendingInsurerSettings();
  } catch (error) {
    focusInvalidInsurerSetting(error);
    return;
  }
  const radio = globalThis.SekagentRadio?.readSettingsForm() || uiSettings.radio;
  const nextUiSettings = normalizeUiSettings({
    theme: pendingSettingsTheme,
    fontSize: pendingSettingsFontSize,
    showAppearanceDock: pendingShowAppearanceDock,
    showStartDateInput: pendingShowStartDateInput,
    showUsageGuide: pendingShowUsageGuide,
    recordsPerPage: uiSettings.recordsPerPage,
    databaseName: pendingDatabaseName,
    logoDataUrl: pendingLogoDataUrl,
    agencyPrintDetails,
    insurers,
    calculatorAccounts: {
      warta: { username: wartaUsername },
      generali: { username: generaliUsername },
      mtu: { username: mtuUsername },
      hestia: { username: hestiaUsername },
      trasti: { username: trastiUsername },
      wiener: { username: wienerUsername },
      compensa: { username: compensaUsername },
      allianz: { username: allianzUsername },
      insly: { username: inslyUsername },
      pzu: { username: pzuUsername },
    },
    radio,
    idleRpg: uiSettings.idleRpg,
  });
  if (!isEmployeeAccount() && !(await persistAgencyInsurerSelection({ showSuccess: false }))) {
    setSettingsTab("agency");
    return;
  }
  let passwordWasSaved = false;
  let generaliPasswordWasSaved = false;
  let mtuPasswordWasSaved = false;
  let hestiaPasswordWasSaved = false;
  let trastiPasswordWasSaved = false;
  let wienerPasswordWasSaved = false;
  let compensaPasswordWasSaved = false;
  let allianzPasswordWasSaved = false;
  let inslyPasswordWasSaved = false;
  let pzuPasswordWasSaved = false;
  try {
    if (pendingWartaPassword) {
      await saveWartaPasswordToVault(pendingWartaPassword);
      wartaPasswordSaved = true;
      passwordWasSaved = true;
    } else if (!wartaUsername && (previousWartaUsername || wartaPasswordSaved)) {
      await deleteWartaPasswordFromVault();
      wartaPasswordSaved = false;
    }
    if (pendingGeneraliPassword) {
      await saveGeneraliPasswordToVault(pendingGeneraliPassword);
      generaliPasswordSaved = true;
      generaliPasswordWasSaved = true;
    } else if (!generaliUsername && (previousGeneraliUsername || generaliPasswordSaved)) {
      await deleteGeneraliPasswordFromVault();
      generaliPasswordSaved = false;
    }
    if (pendingMtuPassword) {
      await saveMtuPasswordToVault(pendingMtuPassword, mtuUsername);
      mtuPasswordSaved = true;
      mtuPasswordWasSaved = true;
    } else if (!mtuUsername && (previousMtuUsername || mtuPasswordSaved)) {
      await deleteMtuPasswordFromVault();
      mtuPasswordSaved = false;
    }
    if (pendingHestiaPassword) {
      await saveHestiaPasswordToVault(pendingHestiaPassword, hestiaUsername);
      hestiaPasswordSaved = true;
      hestiaPasswordWasSaved = true;
    } else if (!hestiaUsername && (previousHestiaUsername || hestiaPasswordSaved)) {
      await deleteHestiaPasswordFromVault();
      hestiaPasswordSaved = false;
    }
    if (pendingTrastiPassword) {
      await saveTrastiPasswordToVault(pendingTrastiPassword);
      trastiPasswordSaved = true;
      trastiPasswordWasSaved = true;
    } else if (!trastiUsername && (previousTrastiUsername || trastiPasswordSaved)) {
      await deleteTrastiPasswordFromVault();
      trastiPasswordSaved = false;
    }
    if (pendingWienerPassword) {
      await saveWienerPasswordToVault(pendingWienerPassword);
      wienerPasswordSaved = true;
      wienerPasswordWasSaved = true;
    } else if (!wienerUsername && (previousWienerUsername || wienerPasswordSaved)) {
      await deleteWienerPasswordFromVault();
      wienerPasswordSaved = false;
    }
    if (pendingCompensaPassword) {
      await saveCompensaPasswordToVault(pendingCompensaPassword);
      compensaPasswordSaved = true;
      compensaPasswordWasSaved = true;
    } else if (!compensaUsername && (previousCompensaUsername || compensaPasswordSaved)) {
      await deleteCompensaPasswordFromVault();
      compensaPasswordSaved = false;
    }
    if (pendingAllianzPassword) {
      await saveAllianzPasswordToVault(pendingAllianzPassword);
      allianzPasswordSaved = true;
      allianzPasswordWasSaved = true;
    } else if (!allianzUsername && (previousAllianzUsername || allianzPasswordSaved)) {
      await deleteAllianzPasswordFromVault();
      allianzPasswordSaved = false;
    }
    if (pendingInslyPassword) {
      await saveInslyPasswordToVault(pendingInslyPassword);
      inslyPasswordSaved = true;
      inslyPasswordWasSaved = true;
    } else if (!inslyUsername && (previousInslyUsername || inslyPasswordSaved)) {
      await deleteInslyPasswordFromVault();
      inslyPasswordSaved = false;
    }
    if (pendingPzuPassword) {
      await savePzuPasswordToVault(pendingPzuPassword);
      pzuPasswordSaved = true;
      pzuPasswordWasSaved = true;
    } else if (!pzuUsername && (previousPzuUsername || pzuPasswordSaved)) {
      await deletePzuPasswordFromVault();
      pzuPasswordSaved = false;
    }
  } catch (error) {
    setSettingsTab("user");
    showToast(error?.message || "Nie udało się zapisać hasła", "warning");
    (pendingWienerPassword
      ? elements.wienerPasswordSetting
      : pendingTrastiPassword
        ? elements.trastiPasswordSetting
        : pendingHestiaPassword
          ? elements.hestiaPasswordSetting
          : pendingMtuPassword
            ? elements.mtuPasswordSetting
            : pendingGeneraliPassword ? elements.generaliPasswordSetting : elements.wartaPasswordSetting).focus();
    return;
  }
  if (!(await persistUiSettings(nextUiSettings))) {
    if (passwordWasSaved && wartaUsername !== previousWartaUsername) {
      await deleteWartaPasswordFromVault().catch(() => {});
      wartaPasswordSaved = false;
    }
    if (generaliPasswordWasSaved && generaliUsername !== previousGeneraliUsername) {
      await deleteGeneraliPasswordFromVault().catch(() => {});
      generaliPasswordSaved = false;
    }
    if (mtuPasswordWasSaved && mtuUsername !== previousMtuUsername) {
      await deleteMtuPasswordFromVault().catch(() => {});
      mtuPasswordSaved = false;
    }
    if (hestiaPasswordWasSaved && hestiaUsername !== previousHestiaUsername) {
      await deleteHestiaPasswordFromVault().catch(() => {});
      hestiaPasswordSaved = false;
    }
    if (trastiPasswordWasSaved && trastiUsername !== previousTrastiUsername) {
      await deleteTrastiPasswordFromVault().catch(() => {});
      trastiPasswordSaved = false;
    }
    if (wienerPasswordWasSaved && wienerUsername !== previousWienerUsername) {
      await deleteWienerPasswordFromVault().catch(() => {});
      wienerPasswordSaved = false;
    }
    if (compensaPasswordWasSaved && compensaUsername !== previousCompensaUsername) {
      await deleteCompensaPasswordFromVault().catch(() => {});
      compensaPasswordSaved = false;
    }
    if (allianzPasswordWasSaved && allianzUsername !== previousAllianzUsername) {
      await deleteAllianzPasswordFromVault().catch(() => {});
      allianzPasswordSaved = false;
    }
    if (inslyPasswordWasSaved && inslyUsername !== previousInslyUsername) {
      await deleteInslyPasswordFromVault().catch(() => {});
      inslyPasswordSaved = false;
    }
    if (pzuPasswordWasSaved && pzuUsername !== previousPzuUsername) {
      await deletePzuPasswordFromVault().catch(() => {});
      pzuPasswordSaved = false;
    }
    applyTheme(settingsOpeningTheme);
    applyFontSize(settingsOpeningFontSize);
    applyAppearanceDockSetting(settingsOpeningShowAppearanceDock);
    applyStartDateInputSetting(settingsOpeningShowStartDateInput);
    applyUsageGuideSetting(settingsOpeningShowUsageGuide);
    return;
  }

  uiSettings = nextUiSettings;
  applyUiSettings();
  hideAlwaysVisibleSuggestions();
  render();
  settingsOpeningTheme = uiSettings.theme;
  settingsOpeningFontSize = uiSettings.fontSize;
  settingsOpeningShowAppearanceDock = uiSettings.showAppearanceDock;
  settingsOpeningShowStartDateInput = uiSettings.showStartDateInput;
  settingsOpeningShowUsageGuide = uiSettings.showUsageGuide;
  hideInsurerSettingsPopup();
  resetWartaPasswordEditor();
  resetGeneraliPasswordEditor();
  resetMtuPasswordEditor();
  resetHestiaPasswordEditor();
  resetTrastiPasswordEditor();
  resetWienerPasswordEditor();
  resetCompensaPasswordEditor();
  resetAllianzPasswordEditor();
  resetInslyPasswordEditor();
  resetPzuPasswordEditor();
  elements.settingsDialog.close();
  showToast("Ustawienia zostały zapisane");
}

function getSettingsFingerprint(settings = uiSettings) {
  const { idleRpg, ...meaningfulSettings } = normalizeUiSettings(settings);
  return JSON.stringify(meaningfulSettings);
}

function createSettingsFileContents(settings = uiSettings, updatedAt = new Date().toISOString()) {
  return JSON.stringify({
    version: SETTINGS_FILE_VERSION,
    updatedAt,
    theme: settings.theme,
    fontSize: settings.fontSize,
    showAppearanceDock: settings.showAppearanceDock,
    showStartDateInput: settings.showStartDateInput,
    showUsageGuide: settings.showUsageGuide,
    recordsPerPage: settings.recordsPerPage,
    databaseName: normalizeDatabaseName(settings.databaseName),
    logoDataUrl: settings.logoDataUrl,
    agencyPrintDetails: normalizeAgencyPrintDetails(settings.agencyPrintDetails),
    insurers: normalizeInsurerSettings(settings.insurers),
    calculatorAccounts: normalizeCalculatorAccounts(settings.calculatorAccounts),
    radio: globalThis.SekagentRadio?.normalizeSettings(settings.radio) || {
      visible: true,
      shuffle: true,
      volume: 0.35,
      items: [],
    },
    idleRpg: settings.idleRpg || null,
  }, null, 2);
}

function normalizeEmployeePackageImportReceipts(receipts) {
  if (!Array.isArray(receipts)) return [];
  const normalizedReceipts = [];
  const seenTransactionKeys = new Set();
  for (const receipt of receipts) {
    const txId = String(receipt?.txId || "").trim();
    const packageDigest = String(receipt?.packageDigest || "").trim().toLowerCase();
    const planDigest = String(receipt?.planDigest || "").trim().toLowerCase();
    const sourceAccountId = normalizePolicyOwnerId(receipt?.sourceAccountId);
    const kind = receipt?.kind === undefined
      ? EMPLOYEE_TO_CENTRAL_PACKAGE_KIND
      : String(receipt.kind || "");
    const targetAccountId = normalizePolicyOwnerId(
      receipt?.targetAccountId
      || (kind === EMPLOYEE_TO_CENTRAL_PACKAGE_KIND ? currentAccount?.id : ""),
    );
    const transactionKey = `${kind}:${txId}`;
    if (
      !EMPLOYEE_PACKAGE_TRANSACTION_ID_PATTERN.test(txId)
      || !EMPLOYEE_PACKAGE_DIGEST_PATTERN.test(packageDigest)
      || !EMPLOYEE_PACKAGE_DIGEST_PATTERN.test(planDigest)
      || !sourceAccountId
      || !EMPLOYEE_PACKAGE_RECEIPT_KINDS.has(kind)
      || !targetAccountId
      || seenTransactionKeys.has(transactionKey)
    ) {
      continue;
    }
    seenTransactionKeys.add(transactionKey);
    normalizedReceipts.push({
      txId,
      kind,
      packageDigest,
      planDigest,
      sourceAccountId,
      targetAccountId,
    });
  }
  return normalizedReceipts.slice(-MAX_EMPLOYEE_PACKAGE_IMPORT_RECEIPTS);
}




const MAX_CLIENT_ACCOUNT_LINKS = 1000;

function normalizeClientAccountLinkKeyList(values, allowedTypes) {
  if (!Array.isArray(values)) return [];
  const keys = new Set();
  for (const value of values) {
    const digits = String(value ?? "").replace(/\D/g, "");
    if (digits && allowedTypes.includes(getIdentityNumberType(digits))) keys.add(digits);
  }
  return [...keys].sort();
}

function getClientAccountLinkPairKey(link) {
  return `${link.personKeys.join(",")}|${link.companyKeys.join(",")}`;
}

function normalizeClientAccountLinks(links) {
  if (!Array.isArray(links)) return [];
  const normalizedLinks = [];
  const seenPairKeys = new Set();
  for (const link of links) {
    const personKeys = normalizeClientAccountLinkKeyList(link?.personKeys, ["PESEL"]);
    const companyKeys = normalizeClientAccountLinkKeyList(link?.companyKeys, ["NIP", "REGON"]);
    if (personKeys.length === 0 || companyKeys.length === 0) continue;
    const entry = {
      personKeys,
      companyKeys,
      personName: String(link?.personName ?? "").trim().slice(0, 200),
      companyName: String(link?.companyName ?? "").trim().slice(0, 200),
      createdAt: typeof link?.createdAt === "string" ? link.createdAt : "",
      source: link?.source === "porzadkowanie" ? "porzadkowanie" : "reczne",
    };
    const pairKey = getClientAccountLinkPairKey(entry);
    if (seenPairKeys.has(pairKey)) continue;
    seenPairKeys.add(pairKey);
    normalizedLinks.push(entry);
  }
  return normalizedLinks.slice(-MAX_CLIENT_ACCOUNT_LINKS);
}

function getPoliciesFingerprint(
  policyRecords = policies,
  deletedRecords = deletedPolicies,
  taskRecords = calendarTasks,
  importReceipts = employeePackageImportReceipts,
  accountLinks = clientAccountLinks,
) {
  return JSON.stringify({
    policies: Array.isArray(policyRecords) ? policyRecords : [],
    deletedPolicies: Array.isArray(deletedRecords) ? deletedRecords : [],
    calendarTasks: Array.isArray(taskRecords) ? taskRecords : [],
    employeePackageImports: normalizeEmployeePackageImportReceipts(importReceipts),
    clientAccountLinks: normalizeClientAccountLinks(accountLinks),
  });
}

function createDataFileContents(
  policyRecords = policies,
  updatedAt = new Date().toISOString(),
  deletedRecords = deletedPolicies,
  taskRecords = calendarTasks,
  importReceipts = employeePackageImportReceipts,
  accountLinks = clientAccountLinks,
) {
  return JSON.stringify({
    version: DATA_FILE_VERSION,
    updatedAt,
    
    
    accountId: currentAccount?.id || "",
    accountName: currentAccount?.name || "",
    policies: policyRecords,
    deletedPolicies: deletedRecords,
    calendarTasks: taskRecords,
    employeePackageImports: normalizeEmployeePackageImportReceipts(importReceipts),
    clientAccountLinks: normalizeClientAccountLinks(accountLinks),
  }, null, 2);
}

function createCanonicalDataFileWriteSnapshot(
  policyRecords = policies,
  updatedAt = new Date().toISOString(),
  deletedRecords = deletedPolicies,
  taskRecords = calendarTasks,
  importReceipts = employeePackageImportReceipts,
  accountLinks = clientAccountLinks,
) {
  
  
  
  const documentData = parsePoliciesFileDocument(createDataFileContents(
    policyRecords,
    updatedAt,
    deletedRecords,
    taskRecords,
    importReceipts,
    accountLinks,
  ));
  const contents = createDataFileContents(
    documentData.policies,
    updatedAt,
    documentData.deletedPolicies,
    documentData.calendarTasks,
    documentData.employeePackageImports,
    documentData.clientAccountLinks,
  );
  return {
    contents,
    documentData,
    contentFingerprint: getPoliciesFingerprint(
      documentData.policies,
      documentData.deletedPolicies,
      documentData.calendarTasks,
      documentData.employeePackageImports,
      documentData.clientAccountLinks,
    ),
  };
}

function openFileSettingsDatabase() {
  return new Promise((resolve, reject) => {
    if (!globalThis.indexedDB) {
      resolve(null);
      return;
    }

    const request = globalThis.indexedDB.open(FILE_SETTINGS_DB, 1);
    request.onupgradeneeded = () => {
      const database = request.result;
      if (!database.objectStoreNames.contains(FILE_SETTINGS_STORE)) {
        database.createObjectStore(FILE_SETTINGS_STORE);
      }
    };
    request.onsuccess = () => resolve(request.result);
    request.onerror = () => reject(request.error);
  });
}

async function rememberDataFileHandle(handle) {
  let database = null;
  try {
    database = await openFileSettingsDatabase();
    if (!database) return false;
    await new Promise((resolve, reject) => {
      const transaction = database.transaction(FILE_SETTINGS_STORE, "readwrite");
      transaction.objectStore(FILE_SETTINGS_STORE).put(handle, FILE_HANDLE_KEY);
      if (LEGACY_FILE_HANDLE_KEY !== FILE_HANDLE_KEY) {
        transaction.objectStore(FILE_SETTINGS_STORE).delete(LEGACY_FILE_HANDLE_KEY);
      }
      transaction.oncomplete = () => resolve();
      transaction.onerror = () => reject(transaction.error);
      transaction.onabort = () => reject(transaction.error);
    });
    rememberedDataFileHandle = handle;
    return true;
  } catch {
    return false;
  } finally {
    database?.close();
  }
}

async function getRememberedDataFileHandle() {
  let database = null;
  try {
    database = await openFileSettingsDatabase();
    if (!database) return null;
    const readHandle = (key) => new Promise((resolve, reject) => {
      const request = database.transaction(FILE_SETTINGS_STORE, "readonly")
        .objectStore(FILE_SETTINGS_STORE)
        .get(key);
      request.onsuccess = () => resolve(request.result ?? null);
      request.onerror = () => reject(request.error);
    });
    const handle = await readHandle(FILE_HANDLE_KEY) || await readHandle(LEGACY_FILE_HANDLE_KEY);
    rememberedDataFileHandle = handle;
    return handle;
  } catch {
    return null;
  } finally {
    database?.close();
  }
}

async function forgetRememberedDataFileHandle() {
  let database = null;
  try {
    database = await openFileSettingsDatabase();
    if (!database) return;
    await new Promise((resolve, reject) => {
      const transaction = database.transaction(FILE_SETTINGS_STORE, "readwrite");
      transaction.objectStore(FILE_SETTINGS_STORE).delete(FILE_HANDLE_KEY);
      transaction.objectStore(FILE_SETTINGS_STORE).delete(LEGACY_FILE_HANDLE_KEY);
      transaction.oncomplete = () => resolve();
      transaction.onerror = () => reject(transaction.error);
      transaction.onabort = () => reject(transaction.error);
    });
  } catch {
  } finally {
    database?.close();
    rememberedDataFileHandle = null;
  }
}

async function rememberAttachmentsDirectoryHandle(handle) {
  let database = null;
  try {
    database = await openFileSettingsDatabase();
    if (!database) return false;
    await new Promise((resolve, reject) => {
      const transaction = database.transaction(FILE_SETTINGS_STORE, "readwrite");
      transaction.objectStore(FILE_SETTINGS_STORE).put(handle, ATTACHMENTS_DIRECTORY_HANDLE_KEY);
      transaction.oncomplete = () => resolve();
      transaction.onerror = () => reject(transaction.error);
      transaction.onabort = () => reject(transaction.error);
    });
    attachmentsBaseDirectoryHandle = handle;
    rememberedAttachmentsBaseDirectoryHandle = handle;
    return true;
  } catch {
    return false;
  } finally {
    database?.close();
  }
}

async function getRememberedAttachmentsDirectoryHandle() {
  let database = null;
  try {
    database = await openFileSettingsDatabase();
    if (!database) return null;
    const handle = await new Promise((resolve, reject) => {
      const request = database.transaction(FILE_SETTINGS_STORE, "readonly")
        .objectStore(FILE_SETTINGS_STORE)
        .get(ATTACHMENTS_DIRECTORY_HANDLE_KEY);
      request.onsuccess = () => resolve(request.result ?? null);
      request.onerror = () => reject(request.error);
    });
    rememberedAttachmentsBaseDirectoryHandle = handle;
    return handle;
  } catch {
    return null;
  } finally {
    database?.close();
  }
}

async function forgetRememberedAttachmentsDirectoryHandle() {
  let database = null;
  try {
    database = await openFileSettingsDatabase();
    if (!database) return;
    await new Promise((resolve, reject) => {
      const transaction = database.transaction(FILE_SETTINGS_STORE, "readwrite");
      transaction.objectStore(FILE_SETTINGS_STORE).delete(ATTACHMENTS_DIRECTORY_HANDLE_KEY);
      transaction.oncomplete = () => resolve();
      transaction.onerror = () => reject(transaction.error);
      transaction.onabort = () => reject(transaction.error);
    });
  } catch {
  } finally {
    database?.close();
    attachmentsBaseDirectoryHandle = null;
    rememberedAttachmentsBaseDirectoryHandle = null;
  }
}

async function rememberAppDirectoryHandle(handle) {
  let database = null;
  try {
    database = await openFileSettingsDatabase();
    if (!database) return false;
    await new Promise((resolve, reject) => {
      const transaction = database.transaction(FILE_SETTINGS_STORE, "readwrite");
      transaction.objectStore(FILE_SETTINGS_STORE).put(handle, APP_DIRECTORY_HANDLE_KEY);
      transaction.oncomplete = () => resolve();
      transaction.onerror = () => reject(transaction.error);
      transaction.onabort = () => reject(transaction.error);
    });
    appDirectoryHandle = handle;
    rememberedAppDirectoryHandle = handle;
    return true;
  } catch {
    return false;
  } finally {
    database?.close();
  }
}

async function getRememberedAppDirectoryHandle() {
  let database = null;
  try {
    database = await openFileSettingsDatabase();
    if (!database) return null;
    const handle = await new Promise((resolve, reject) => {
      const request = database.transaction(FILE_SETTINGS_STORE, "readonly")
        .objectStore(FILE_SETTINGS_STORE)
        .get(APP_DIRECTORY_HANDLE_KEY);
      request.onsuccess = () => resolve(request.result ?? null);
      request.onerror = () => reject(request.error);
    });
    rememberedAppDirectoryHandle = handle;
    return handle;
  } catch {
    return null;
  } finally {
    database?.close();
  }
}

async function forgetAppDirectoryHandle() {
  let database = null;
  try {
    database = await openFileSettingsDatabase();
    if (!database) return;
    await new Promise((resolve, reject) => {
      const transaction = database.transaction(FILE_SETTINGS_STORE, "readwrite");
      transaction.objectStore(FILE_SETTINGS_STORE).delete(APP_DIRECTORY_HANDLE_KEY);
      transaction.oncomplete = () => resolve();
      transaction.onerror = () => reject(transaction.error);
      transaction.onabort = () => reject(transaction.error);
    });
  } catch {
  } finally {
    database?.close();
    appDirectoryHandle = null;
    rememberedAppDirectoryHandle = null;
  }
}

async function rememberSettingsFileHandle(handle) {
  let database = null;
  try {
    database = await openFileSettingsDatabase();
    if (!database) return false;
    await new Promise((resolve, reject) => {
      const transaction = database.transaction(FILE_SETTINGS_STORE, "readwrite");
      transaction.objectStore(FILE_SETTINGS_STORE).put(handle, SETTINGS_FILE_HANDLE_KEY);
      transaction.oncomplete = () => resolve();
      transaction.onerror = () => reject(transaction.error);
      transaction.onabort = () => reject(transaction.error);
    });
    rememberedSettingsFileHandle = handle;
    return true;
  } catch {
    return false;
  } finally {
    database?.close();
  }
}

async function getRememberedSettingsFileHandle() {
  let database = null;
  try {
    database = await openFileSettingsDatabase();
    if (!database) return null;
    const handle = await new Promise((resolve, reject) => {
      const request = database.transaction(FILE_SETTINGS_STORE, "readonly")
        .objectStore(FILE_SETTINGS_STORE)
        .get(SETTINGS_FILE_HANDLE_KEY);
      request.onsuccess = () => resolve(request.result ?? null);
      request.onerror = () => reject(request.error);
    });
    rememberedSettingsFileHandle = handle;
    return handle;
  } catch {
    return null;
  } finally {
    database?.close();
  }
}

async function forgetRememberedSettingsFileHandle() {
  let database = null;
  try {
    database = await openFileSettingsDatabase();
    if (!database) return;
    await new Promise((resolve, reject) => {
      const transaction = database.transaction(FILE_SETTINGS_STORE, "readwrite");
      transaction.objectStore(FILE_SETTINGS_STORE).delete(SETTINGS_FILE_HANDLE_KEY);
      transaction.oncomplete = () => resolve();
      transaction.onerror = () => reject(transaction.error);
      transaction.onabort = () => reject(transaction.error);
    });
  } catch {
  } finally {
    database?.close();
    rememberedSettingsFileHandle = null;
  }
}

async function rememberFileSnapshot(key, snapshot) {
  let database = null;
  try {
    database = await openFileSettingsDatabase();
    if (!database) return false;
    await new Promise((resolve, reject) => {
      const transaction = database.transaction(FILE_SETTINGS_STORE, "readwrite");
      transaction.objectStore(FILE_SETTINGS_STORE).put(snapshot, key);
      if (key === DATA_FILE_SNAPSHOT_KEY && LEGACY_DATA_FILE_SNAPSHOT_KEY !== DATA_FILE_SNAPSHOT_KEY) {
        transaction.objectStore(FILE_SETTINGS_STORE).delete(LEGACY_DATA_FILE_SNAPSHOT_KEY);
      }
      transaction.oncomplete = () => resolve();
      transaction.onerror = () => reject(transaction.error);
      transaction.onabort = () => reject(transaction.error);
    });
    return true;
  } catch {
    return false;
  } finally {
    database?.close();
  }
}

async function getRememberedFileSnapshot(key) {
  let database = null;
  try {
    database = await openFileSettingsDatabase();
    if (!database) return null;
    const readSnapshot = (snapshotKey) => new Promise((resolve, reject) => {
      const request = database.transaction(FILE_SETTINGS_STORE, "readonly")
        .objectStore(FILE_SETTINGS_STORE)
        .get(snapshotKey);
      request.onsuccess = () => resolve(request.result ?? null);
      request.onerror = () => reject(request.error);
    });
    let snapshot = await readSnapshot(key);
    if (!snapshot && key === DATA_FILE_SNAPSHOT_KEY) {
      snapshot = await readSnapshot(LEGACY_DATA_FILE_SNAPSHOT_KEY);
    }
    if (key !== DATA_FILE_SNAPSHOT_KEY || !snapshot) return snapshot;
    if (snapshot.encryptedContents) {
      return decodeRememberedDataFileSnapshot(snapshot);
    }
    
    
    if (Array.isArray(snapshot.policies)) {
      await rememberDataFileSnapshot(
        snapshot.policies,
        {
          fileName: snapshot.fileName,
          updatedAt: snapshot.updatedAt,
          lastModified: snapshot.sourceLastModified,
          size: snapshot.sourceSize,
        },
        snapshot.deletedPolicies,
        snapshot.calendarTasks,
        snapshot.employeePackageImports,
        snapshot.clientAccountLinks,
      );
    }
    return snapshot;
  } catch {
    return null;
  } finally {
    database?.close();
  }
}

async function rememberDataFileSnapshot(
  policyRecords = policies,
  revision = dataFileRevision,
  deletedRecords = deletedPolicies,
  taskRecords = calendarTasks,
  importReceipts = employeePackageImportReceipts,
  accountLinks = clientAccountLinks,
) {
  try {
    const updatedAt = revision?.updatedAt || new Date().toISOString();
    const writeSnapshot = createCanonicalDataFileWriteSnapshot(
      policyRecords,
      updatedAt,
      deletedRecords,
      taskRecords,
      importReceipts,
      accountLinks,
    );
    const encryptedContents = await encodeProtectedPoliciesFileContents(writeSnapshot.contents);
    return rememberFileSnapshot(DATA_FILE_SNAPSHOT_KEY, {
      version: DATA_FILE_VERSION,
      encrypted: true,
      updatedAt,
      fileName: revision?.fileName
        || dataFileName
        || dataFileHandle?.name
        || rememberedDataFileHandle?.name
        || "polisy-dane.json",
      sourceLastModified: Number(revision?.lastModified) || 0,
      sourceSize: Number(revision?.size) || 0,
      encryptedContents,
    });
  } catch {
    return false;
  }
}

function rememberSettingsFileSnapshot(settings = uiSettings) {
  return rememberFileSnapshot(SETTINGS_FILE_SNAPSHOT_KEY, {
    version: SETTINGS_FILE_VERSION,
    updatedAt: settingsFileRevision?.updatedAt || new Date().toISOString(),
    fileName: settingsFileName || settingsFileHandle?.name || rememberedSettingsFileHandle?.name || DEFAULT_SETTINGS_FILE_NAME,
    sourceLastModified: Number(settingsFileRevision?.lastModified) || 0,
    sourceSize: Number(settingsFileRevision?.size) || 0,
    contentFingerprint: getSettingsFingerprint(settings),
    settings: normalizeUiSettings(settings),
  });
}

function updateSettingsFileStatus() {
  const isConnected = Boolean(settingsFileHandle);
  elements.settingsFileBar.classList.toggle("data-file-bar--connected", isConnected || initialSettingsFileReady);

  if (isConnected) {
    elements.settingsFileName.textContent = settingsFileName || DEFAULT_SETTINGS_FILE_NAME;
    elements.settingsFileHint.textContent = "Wygląd, nazwa agencji, logo i lista towarzystw zapisują się automatycznie do tego pliku.";
  } else if (rememberedSettingsFileHandle) {
    elements.settingsFileName.textContent = rememberedSettingsFileHandle.name || settingsFileName || DEFAULT_SETTINGS_FILE_NAME;
    elements.settingsFileHint.textContent = initialSettingsFileReady
      ? "Ustawienia zostały automatycznie wczytane z pamięci aplikacji. Tutaj możesz wskazać inny plik."
      : "Plik jest zapamiętany. Kliknij „Otwórz plik”, jeśli przeglądarka poprosi o zgodę.";
  } else if (settingsFileName) {
    elements.settingsFileName.textContent = settingsFileName;
    elements.settingsFileHint.textContent = initialSettingsFileReady
      ? "Ustawienia zostały automatycznie wczytane z pamięci aplikacji. Tutaj możesz wskazać inny plik."
      : "Plik wczytany. Użyj „Zapisz jako”, aby włączyć automatyczny zapis.";
  } else if (hasLegacyUiSettings) {
    elements.settingsFileName.textContent = "Ustawienia gotowe do przeniesienia";
    elements.settingsFileHint.textContent = "Kliknij „Zapisz jako”, aby przenieść ustawienia z przeglądarki do osobnego pliku.";
  } else {
    elements.settingsFileName.textContent = "Nie wybrano pliku ustawień";
    elements.settingsFileHint.textContent = `Otwórz istniejący plik albo utwórz ${DEFAULT_SETTINGS_FILE_NAME}.`;
  }
  updateInitialSetupState();
}

function migrateSettingsFileV1ToV2(documentData) {
  const settings = documentData.settings;
  return {
    ...documentData,
    version: 2,
    settings: {
      ...settings,
      showUsageGuide: settings.showUsageGuide !== false,
      idleRpg: settings.idleRpg && typeof settings.idleRpg === "object" && !Array.isArray(settings.idleRpg)
        ? settings.idleRpg
        : null,
    },
  };
}

function migrateSettingsFileV2ToV3(documentData) {
  return {
    ...documentData,
    version: 3,
    settings: {
      ...documentData.settings,
      calculatorAccounts: normalizeCalculatorAccounts(documentData.settings?.calculatorAccounts),
    },
  };
}

function migrateSettingsFileV3ToV4(documentData) {
  return {
    ...documentData,
    version: 4,
    settings: {
      ...documentData.settings,
      databaseName: normalizeDatabaseName(
        documentData.settings?.databaseName ?? documentData.settings?.agencyName,
      ),
    },
  };
}

function migrateSettingsFileDocument(parsed) {
  if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
    throw new Error("Wybrany plik nie zawiera prawidłowych ustawień aplikacji.");
  }

  if ("settings" in parsed && (!parsed.settings || typeof parsed.settings !== "object" || Array.isArray(parsed.settings))) {
    throw new Error("Pole settings w pliku ustawień ma nieprawidłowy format.");
  }

  const settings = parsed.settings && typeof parsed.settings === "object" ? parsed.settings : parsed;
  const versionValue = parsed.version ?? (parsed.settings ? settings.version : undefined);
  const declaredVersion = versionValue === undefined ? 1 : Number(versionValue);
  if (!Number.isInteger(declaredVersion) || declaredVersion < 1) {
    throw new Error("Plik ustawień ma nieprawidłowy numer wersji.");
  }
  if (declaredVersion > SETTINGS_FILE_VERSION) {
    throw new Error(`Ten plik ustawień ma nowszy format v${declaredVersion}. Zaktualizuj aplikację przed jego otwarciem.`);
  }

  let migratedDocument = {
    version: declaredVersion,
    updatedAt: typeof parsed.updatedAt === "string" ? parsed.updatedAt : "",
    settings: { ...settings },
  };
  while (migratedDocument.version < SETTINGS_FILE_VERSION) {
    switch (migratedDocument.version) {
      case 1:
        migratedDocument = migrateSettingsFileV1ToV2(migratedDocument);
        break;
      case 2:
        migratedDocument = migrateSettingsFileV2ToV3(migratedDocument);
        break;
      case 3:
        migratedDocument = migrateSettingsFileV3ToV4(migratedDocument);
        break;
      default:
        throw new Error(`Brakuje migracji ustawień z formatu v${migratedDocument.version}.`);
    }
  }

  return {
    version: migratedDocument.version,
    sourceVersion: declaredVersion,
    wasMigrated: declaredVersion < SETTINGS_FILE_VERSION,
    settings: normalizeUiSettings(migratedDocument.settings),
    updatedAt: migratedDocument.updatedAt,
  };
}

function parseSettingsFileDocument(contents) {
  let parsed = null;
  try {
    parsed = JSON.parse(contents);
  } catch {
    throw new Error("Plik ustawień nie jest prawidłowym plikiem JSON.");
  }
  return migrateSettingsFileDocument(parsed);
}

function createSettingsFileRevision(file, documentData) {
  return {
    fileName: file?.name || settingsFileName || DEFAULT_SETTINGS_FILE_NAME,
    lastModified: Number(file?.lastModified) || 0,
    size: Number(file?.size) || 0,
    updatedAt: documentData.updatedAt || "",
    contentFingerprint: getSettingsFingerprint(documentData.settings),
  };
}

async function inspectSettingsFile(file) {
  if (Number(file?.size) > MAX_SETTINGS_FILE_SIZE) {
    throw new Error("Plik ustawień jest zbyt duży, aby można go było bezpiecznie otworzyć.");
  }
  const documentData = parseSettingsFileDocument(await file.text());
  return {
    file,
    documentData,
    revision: createSettingsFileRevision(file, documentData),
  };
}

async function verifySettingsFileFreshness(handle) {
  const inspection = await inspectSettingsFile(await handle.getFile());
  if (!settingsFileRevision || inspection.revision.contentFingerprint === settingsFileRevision.contentFingerprint) {
    settingsFileRevision = inspection.revision;
    return "fresh";
  }

  const loadDiskVersion = typeof globalThis.confirm === "function" && globalThis.confirm(
    "Plik ustawień został zmieniony poza tą kartą.\n\nKliknij OK, aby wczytać aktualne ustawienia z dysku. Kliknij Anuluj, aby zatrzymać zapis bez nadpisywania pliku.",
  );
  if (loadDiskVersion) {
    await loadSettingsFromFile(inspection.file, handle, {
      inspection,
      permissionGranted: true,
      showToast: false,
    });
    showToast("Wczytano nowsze ustawienia z dysku", "warning");
    return "reloaded";
  }
  showToast("Zapis ustawień zatrzymano - plik został zmieniony", "error");
  return "blocked";
}

async function withSettingsFileWriteLock(callback) {
  if (globalThis.navigator?.locks?.request) {
    return globalThis.navigator.locks.request("baza-polis-settings-file-write", { mode: "exclusive" }, callback);
  }
  return callback();
}

async function writeSettingsToHandle(handle, settings = uiSettings, options = {}) {
  if (!(await requestWritePermission(handle))) {
    throw new Error("Brak zgody na zapis do pliku ustawień.");
  }
  return withSettingsFileWriteLock(async () => {
    if (!options.skipFreshnessCheck && (settingsFileHandle === handle || rememberedSettingsFileHandle === handle)) {
      const freshness = await verifySettingsFileFreshness(handle);
      if (freshness !== "fresh") {
        throw createHandledWriteError("Zapis ustawień zatrzymano z powodu konfliktu wersji pliku.");
      }
    }
    const updatedAt = new Date().toISOString();
    const contents = createSettingsFileContents(settings, updatedAt);
    const writable = await handle.createWritable();
    await writable.write(contents);
    await writable.close();
    let writtenFile = null;
    try {
      writtenFile = await handle.getFile();
    } catch {
    }
    settingsFileHandle = handle;
    rememberedSettingsFileHandle = handle;
    settingsFileName = handle.name || settingsFileName || DEFAULT_SETTINGS_FILE_NAME;
    settingsFileRevision = {
      fileName: settingsFileName,
      lastModified: Number(writtenFile?.lastModified) || Date.now(),
      size: Number(writtenFile?.size) || new Blob([contents]).size,
      updatedAt,
      contentFingerprint: getSettingsFingerprint(settings),
    };
    initialSettingsFileReady = true;
    await rememberSettingsFileHandle(handle);
    await rememberSettingsFileSnapshot(settings);
    clearLegacyUiSettings();
    updateSettingsFileStatus();
  });
}

async function downloadSettingsFile(settings = uiSettings) {
  const blob = new Blob([createSettingsFileContents(settings)], { type: "application/json;charset=utf-8" });
  const url = URL.createObjectURL(blob);
  const link = document.createElement("a");
  link.href = url;
  link.download = settingsFileName || DEFAULT_SETTINGS_FILE_NAME;
  link.click();
  URL.revokeObjectURL(url);
  settingsFileName = link.download;
  settingsFileRevision = null;
  initialSettingsFileReady = true;
  await rememberSettingsFileSnapshot(settings);
  clearLegacyUiSettings();
  updateSettingsFileStatus();
}

async function saveSettingsFileAs(settings = uiSettings) {
  try {
    if (typeof globalThis.showSaveFilePicker !== "function") {
      await downloadSettingsFile(settings);
      showToast("Plik ustawień został pobrany");
      return true;
    }

    const handle = await showSystemPicker("showSaveFilePicker", {
      id: "baza-polis-ustawienia",
      startIn: getPickerStartLocation(settingsFileHandle, rememberedSettingsFileHandle),
      suggestedName: settingsFileName || DEFAULT_SETTINGS_FILE_NAME,
      types: [{
        description: "Plik ustawień aplikacji",
        accept: { "application/json": [".json"] },
      }],
    });
    await writeSettingsToHandle(handle, settings, { skipFreshnessCheck: true });
    showToast("Plik ustawień został zapisany");
    return true;
  } catch (error) {
    if (error?.name !== "AbortError") showToast(error?.message || "Nie udało się zapisać pliku ustawień");
    return false;
  }
}

async function persistUiSettings(settings) {
  if (settingsFileHandle) {
    try {
      await writeSettingsToHandle(settingsFileHandle, settings);
      return true;
    } catch (error) {
      if (!error?.handled) showToast(error?.message || "Nie udało się zapisać pliku ustawień", "error");
      updateSettingsFileStatus();
      return false;
    }
  }

  if (rememberedSettingsFileHandle) {
    try {
      await writeSettingsToHandle(rememberedSettingsFileHandle, settings);
      return true;
    } catch (error) {
      if (!error?.handled) showToast(error?.message || "Nie udało się zapisać pliku ustawień", "error");
      updateSettingsFileStatus();
      return false;
    }
  }

  return saveSettingsFileAs(settings);
}

async function loadSettingsFromFile(file, handle = null, options = {}) {
  const inspection = options.inspection || await inspectSettingsFile(file);
  const loadedSettings = inspection.documentData.settings;
  const writableHandle = handle && (options.permissionGranted || await requestWritePermission(handle)) ? handle : null;
  if (handle && !writableHandle) throw new Error("Brak zgody na zapis do pliku ustawień.");
  settingsFileName = file.name || DEFAULT_SETTINGS_FILE_NAME;
  settingsFileHandle = writableHandle;
  settingsFileRevision = inspection.revision;
  initialSettingsFileReady = true;
  if (!handle && rememberedSettingsFileHandle) {
    await forgetRememberedSettingsFileHandle();
  }
  if (settingsFileHandle) {
    rememberedSettingsFileHandle = settingsFileHandle;
    await rememberSettingsFileHandle(settingsFileHandle);
  }
  clearLegacyUiSettings();
  uiSettings = loadedSettings;
  let migrationSaveError = null;
  if (inspection.documentData.wasMigrated && settingsFileHandle) {
    try {
      await writeSettingsToHandle(settingsFileHandle, uiSettings, { skipFreshnessCheck: true });
    } catch (error) {
      migrationSaveError = error;
    }
  }
  await rememberSettingsFileSnapshot(uiSettings);
  currentPage = 1;
  pageJumpOpen = false;
  applyUiSettings();
  render();
  if (elements.settingsDialog.open) {
    settingsOpeningTheme = uiSettings.theme;
    settingsOpeningFontSize = uiSettings.fontSize;
    settingsOpeningShowAppearanceDock = uiSettings.showAppearanceDock;
    settingsOpeningShowStartDateInput = uiSettings.showStartDateInput;
    settingsOpeningShowUsageGuide = uiSettings.showUsageGuide;
    syncSettingsDialogFromUi();
  }
  updateSettingsFileStatus();
  if (options.showToast !== false) {
    if (migrationSaveError) {
      showToast(
        `Ustawienia v${inspection.documentData.sourceVersion} wczytano, ale nie udało się zapisać aktualizacji do v${SETTINGS_FILE_VERSION}.`,
        "warning",
      );
    } else if (inspection.documentData.wasMigrated && settingsFileHandle) {
      showToast(`Ustawienia zaktualizowano z v${inspection.documentData.sourceVersion} do v${SETTINGS_FILE_VERSION}`);
    } else if (inspection.documentData.wasMigrated) {
      showToast(
        `Ustawienia v${inspection.documentData.sourceVersion} wczytano. Użyj „Zapisz jako”, aby zapisać format v${SETTINGS_FILE_VERSION}.`,
        "warning",
      );
    } else {
      showToast("Ustawienia wczytano z pliku");
    }
  }
}

async function restoreRememberedSettingsFile() {
  const handle = await getRememberedSettingsFileHandle();
  if (handle) {
    rememberedSettingsFileHandle = handle;
    settingsFileName = handle.name || DEFAULT_SETTINGS_FILE_NAME;
    updateSettingsFileStatus();

    try {
      const permission = handle.queryPermission
        ? await handle.queryPermission({ mode: "readwrite" })
        : "granted";
      if (permission === "granted") {
        await loadSettingsFromFile(await handle.getFile(), handle);
        return true;
      }
    } catch {
      settingsFileHandle = null;
      initialSettingsFileReady = false;
    }
  }

  const snapshot = await getRememberedFileSnapshot(SETTINGS_FILE_SNAPSHOT_KEY);
  if (!snapshot?.settings || typeof snapshot.settings !== "object") {
    updateSettingsFileStatus();
    return false;
  }

  let snapshotDocument = null;
  try {
    snapshotDocument = migrateSettingsFileDocument({
      version: snapshot.version,
      updatedAt: snapshot.updatedAt,
      settings: snapshot.settings,
    });
  } catch {
    updateSettingsFileStatus();
    return false;
  }

  settingsFileName = snapshot.fileName || handle?.name || DEFAULT_SETTINGS_FILE_NAME;
  settingsFileRevision = {
    fileName: settingsFileName,
    lastModified: Number(snapshot.sourceLastModified) || 0,
    size: Number(snapshot.sourceSize) || 0,
    updatedAt: typeof snapshot.updatedAt === "string" ? snapshot.updatedAt : "",
    contentFingerprint: snapshot.contentFingerprint || getSettingsFingerprint(snapshotDocument.settings),
  };
  initialSettingsFileReady = true;
  uiSettings = snapshotDocument.settings;
  if (snapshotDocument.wasMigrated) await rememberSettingsFileSnapshot(uiSettings);
  currentPage = 1;
  pageJumpOpen = false;
  applyUiSettings();
  render();
  updateSettingsFileStatus();
  return true;
}

async function openSettingsFileFromPicker() {
  if (typeof globalThis.showOpenFilePicker !== "function") {
    elements.settingsFileInput.click();
    return;
  }

  try {
    const [handle] = await showSystemPicker("showOpenFilePicker", {
      id: "baza-polis-ustawienia",
      startIn: getPickerStartLocation(settingsFileHandle, rememberedSettingsFileHandle),
      multiple: false,
      types: [{
        description: "Plik ustawień aplikacji",
        accept: { "application/json": [".json"] },
      }],
    });
    await loadSettingsFromFile(await handle.getFile(), handle);
  } catch (error) {
    if (error?.name !== "AbortError") showToast(error?.message || "Nie udało się otworzyć pliku ustawień");
  }
}

async function openSettingsFile() {
  if (rememberedSettingsFileHandle) {
    try {
      if (!(await requestWritePermission(rememberedSettingsFileHandle))) {
        showToast("Brak zgody na dostęp do zapamiętanego pliku ustawień");
        return;
      }
      await loadSettingsFromFile(await rememberedSettingsFileHandle.getFile(), rememberedSettingsFileHandle);
      return;
    } catch (error) {
      settingsFileHandle = null;
      initialSettingsFileReady = false;
      updateSettingsFileStatus();
      showToast(error?.message || "Nie udało się otworzyć zapamiętanego pliku ustawień", "error");
    }
  }

  await openSettingsFileFromPicker();
}

function updateDataFileStatus() {
  const isConnected = Boolean(dataFileHandle);
  elements.dataFileBar.classList.toggle("data-file-bar--connected", isConnected || initialDataFileReady);
  elements.backupDataFile.disabled = !(isConnected || rememberedDataFileHandle || dataFileName || hasLegacyPolicies);

  if (isConnected) {
    elements.dataFileName.textContent = dataFileName || "polisy-dane.json";
    elements.dataFileHint.textContent = hasUnsavedPolicyChanges
      ? "W pamięci są zmiany, których nie udało się jeszcze zapisać do pliku."
      : "Po każdej zmianie dane zapisują się automatycznie do tego pliku.";
  } else if (rememberedDataFileHandle) {
    elements.dataFileName.textContent = rememberedDataFileHandle.name || dataFileName || "polisy-dane.json";
    elements.dataFileHint.textContent = dataFileNeedsVerification
      ? "Lokalna kopia wymaga porównania z plikiem przed następnym zapisem."
      : initialDataFileReady
        ? "Baza została automatycznie wczytana z pamięci aplikacji. Kliknij „Otwórz inną bazę”, aby ją zmienić."
      : "Plik jest zapamiętany. Kliknij „Otwórz inną bazę”, aby wskazać inny plik JSON.";
  } else if (dataFileName) {
    elements.dataFileName.textContent = dataFileName;
    elements.dataFileHint.textContent = initialDataFileReady
      ? "Baza została automatycznie wczytana z pamięci aplikacji. Kliknij „Otwórz inną bazę”, aby ją zmienić."
      : "Plik wczytany. Użyj „Zapisz jako”, aby włączyć automatyczny zapis.";
  } else if (hasLegacyPolicies) {
    elements.dataFileName.textContent = "Dane gotowe do przeniesienia";
    elements.dataFileHint.textContent = "Kliknij „Zapisz jako”, aby przenieść dotychczasowe polisy do pliku.";
  } else {
    elements.dataFileName.textContent = "Nie wybrano pliku danych";
    elements.dataFileHint.textContent = "Kliknij „Otwórz inną bazę”, aby wskazać plik JSON, albo utwórz nowy.";
  }
  updateInitialSetupState();
}

function renderDataIntegrityNotice() {
  if (!dataIntegrityNotice) {
    elements.dataIntegrityBanner.hidden = true;
    return;
  }
  elements.dataIntegrityBanner.dataset.type = dataIntegrityNotice.type;
  elements.dataIntegrityTitle.textContent = dataIntegrityNotice.title;
  elements.dataIntegrityMessage.textContent = dataIntegrityNotice.message;
  elements.resolveDataIntegrity.textContent = dataIntegrityNotice.actionLabel || "Rozwiąż problem";
  elements.resolveDataIntegrity.hidden = dataIntegrityNotice.actionLabel === null;
  elements.dismissDataIntegrity.hidden = dataIntegrityNotice.type !== "download";
  elements.dataIntegrityBanner.hidden = false;
}

let saveStatusPopupTimer = null;
let saveStatusPopupSuccessText = null;

function showSaveStatusPopup(state) {
  if (!elements.saveStatusPopup) return;
  if (saveStatusPopupTimer !== null) {
    clearTimeout(saveStatusPopupTimer);
    saveStatusPopupTimer = null;
  }
  const wasHidden = elements.saveStatusPopup.hidden;
  elements.saveStatusPopup.dataset.state = state;
  elements.saveStatusPopupText.textContent = state === "saved"
    ? (saveStatusPopupSuccessText || "Zapisano zmiany")
    : "Zapisywanie zmian…";
  elements.saveStatusPopup.hidden = false;
  
  
  
  if (wasHidden) bringNotificationDockToFront();
  else updateNotificationDockVisibility();
  if (state === "saved") {
    saveStatusPopupSuccessText = null;
    saveStatusPopupTimer = setTimeout(() => {
      saveStatusPopupTimer = null;
      elements.saveStatusPopup.hidden = true;
      updateNotificationDockVisibility();
    }, 1600);
  }
}

function hideSaveStatusPopup() {
  if (saveStatusPopupTimer !== null) {
    clearTimeout(saveStatusPopupTimer);
    saveStatusPopupTimer = null;
  }
  saveStatusPopupSuccessText = null;
  if (elements.saveStatusPopup) elements.saveStatusPopup.hidden = true;
  updateNotificationDockVisibility();
}

function setDataIntegrityNotice(type, title, message, actionLabel = "Rozwiąż problem") {
  hideSaveStatusPopup();
  dataIntegrityNotice = { type, title, message, actionLabel };
  renderDataIntegrityNotice();
  updateDataFileStatus();
}

function clearDataIntegrityNotice() {
  dataIntegrityNotice = null;
  renderDataIntegrityNotice();
  updateDataFileStatus();
}

function markPoliciesDirty(message = null) {
  policyChangeGeneration += 1;
  hasUnsavedPolicyChanges = true;
  if (message) {
    setDataIntegrityNotice("warning", "Niezapisane zmiany", message, "Ponów zapis");
    return;
  }
  showSaveStatusPopup("saving");
  updateDataFileStatus();
}

function markPoliciesSaved() {
  hasUnsavedPolicyChanges = false;
  dataFileNeedsVerification = false;
  dataFileConflictBlocked = false;
  if (elements.saveStatusPopup && !elements.saveStatusPopup.hidden && elements.saveStatusPopup.dataset.state === "saving") {
    showSaveStatusPopup("saved");
  }
  if (dataIntegrityNotice?.type !== "download") clearDataIntegrityNotice();
  else updateDataFileStatus();
}

function markPoliciesRolledBack() {
  hasUnsavedPolicyChanges = false;
  hideSaveStatusPopup();
  void rememberDataFileSnapshot();
  if (dataIntegrityNotice?.actionLabel === "Ponów zapis") clearDataIntegrityNotice();
  else updateDataFileStatus();
}

async function requestWritePermission(handle) {
  if (!handle?.queryPermission || !handle?.requestPermission) return true;
  const currentPermission = await handle.queryPermission({ mode: "readwrite" });
  if (currentPermission === "granted") return true;
  return (await handle.requestPermission({ mode: "readwrite" })) === "granted";
}







const DB_CIPHER_MAGIC = [66, 80, 83, 90, 89, 70, 82, 49]; 
const DB_CIPHER_FLAG_GZIP = 0x01;
const DB_CIPHER_HEADER_LENGTH = 9;
const DB_CIPHER_IV_LENGTH = 12;
let dbCipherPromise = null;
let dbCipherSeenEncrypted = false;
let dbCipherRescueReminderScheduled = false;

function isEncryptedPoliciesBytes(bytes) {
  if (!(bytes instanceof Uint8Array)) return false;
  if (bytes.length < DB_CIPHER_HEADER_LENGTH + DB_CIPHER_IV_LENGTH + 17) return false;
  return DB_CIPHER_MAGIC.every((value, index) => bytes[index] === value);
}

async function fetchDbCipherKeyOnce() {
  const response = await apiFetch("/api/szyfr/klucz-bazy");
  if (!response.ok) throw new Error("Nie udało się pobrać klucza szyfrowania bazy.");
  const payload = await response.json().catch(() => null);
  if (!payload || payload.aktywny !== true) return { active: false, key: null, needsRescue: false };
  if (!payload.klucz) return { active: true, key: null, needsRescue: true };
  const rawKey = Uint8Array.from(globalThis.atob(payload.klucz), (char) => char.charCodeAt(0));
  const key = await globalThis.crypto.subtle.importKey("raw", rawKey, "AES-GCM", false, ["encrypt", "decrypt"]);
  rawKey.fill(0);
  return {
    active: true,
    key,
    needsRescue: false,
    rescueConfirmed: payload.ratunkowyPotwierdzony === true,
    rescueDeposited: payload.depozytUProducenta === true,
  };
}

function getDbCipher() {
  if (!dbCipherPromise) {
    dbCipherPromise = fetchDbCipherKeyOnce()
      .then((cipher) => {
        updateDbCipherSettingsStatus(cipher);
        if (cipher.active && cipher.key && cipher.rescueConfirmed === false) {
          scheduleDbCipherRescueReminder();
        }
        return cipher;
      })
      .catch((error) => {
        dbCipherPromise = null;
        throw error;
      });
  }
  return dbCipherPromise;
}



async function requireDbCipherKey() {
  let cipher = await getDbCipher();
  while (!cipher.key) {
    if (!cipher.active) {
      throw new Error("Plik bazy jest zaszyfrowany, ale klucz nie jest dostępny na tym komputerze. Uruchom aplikację ponownie.");
    }
    await showDbCipherRescueDialog();
    dbCipherPromise = null;
    cipher = await getDbCipher();
  }
  return cipher.key;
}

async function gzipDbCipherBytes(bytes) {
  const stream = new Blob([bytes]).stream().pipeThrough(new CompressionStream("gzip"));
  return new Uint8Array(await new Response(stream).arrayBuffer());
}

async function gunzipDbCipherBytes(bytes) {
  const stream = new Blob([bytes]).stream().pipeThrough(new DecompressionStream("gzip"));
  return new Uint8Array(await new Response(stream).arrayBuffer());
}

async function decodePoliciesFileBytes(bytes, { allowRetry = true } = {}) {
  const key = await requireDbCipherKey();
  const header = bytes.subarray(0, DB_CIPHER_HEADER_LENGTH);
  const iv = bytes.subarray(DB_CIPHER_HEADER_LENGTH, DB_CIPHER_HEADER_LENGTH + DB_CIPHER_IV_LENGTH);
  const body = bytes.subarray(DB_CIPHER_HEADER_LENGTH + DB_CIPHER_IV_LENGTH);
  let plain;
  try {
    plain = new Uint8Array(await globalThis.crypto.subtle.decrypt(
      { name: "AES-GCM", iv, additionalData: header },
      key,
      body,
    ));
  } catch {
    
    
    if (allowRetry) {
      const podanoInny = await showDbCipherRescueDialog({
        powod: "Zapisany klucz nie otwiera tej bazy. Sprawdź klucz ratunkowy i wpisz go jeszcze raz.",
      }).then(() => true, () => false);
      if (podanoInny) {
        dbCipherPromise = null;
        return decodePoliciesFileBytes(bytes, { allowRetry: false });
      }
    }
    throw new Error(
      "Nie udało się odczytać zaszyfrowanego pliku bazy. Jeśli plik pochodzi z innego komputera, "
      + "przenieś dane paczką albo przywróć je kluczem ratunkowym z tamtego komputera.",
    );
  }
  dbCipherSeenEncrypted = true;
  return (header[8] & DB_CIPHER_FLAG_GZIP) ? gunzipDbCipherBytes(plain) : plain;
}



async function readPoliciesFileText(file) {
  const bytes = new Uint8Array(await file.arrayBuffer());
  if (!isEncryptedPoliciesBytes(bytes)) return new TextDecoder().decode(bytes);
  return new TextDecoder().decode(await decodePoliciesFileBytes(bytes));
}




async function hasEncryptedPoliciesOnDisk() {
  const handle = dataFileHandle || rememberedDataFileHandle;
  if (!handle?.getFile) return false;
  try {
    const file = await handle.getFile();
    const naglowek = new Uint8Array(await file.slice(0, DB_CIPHER_HEADER_LENGTH).arrayBuffer());
    return DB_CIPHER_MAGIC.every((wartosc, index) => naglowek[index] === wartosc);
  } catch {
    return false;
  }
}



async function encodePoliciesFileContents(contents) {
  let cipher = null;
  try {
    cipher = await getDbCipher();
  } catch {
    
    
    
    if (dbCipherSeenEncrypted || await hasEncryptedPoliciesOnDisk()) {
      throw new Error("Nie udało się pobrać klucza szyfrowania - zapis wstrzymany. Spróbuj ponownie za chwilę.");
    }
    return contents;
  }
  if (!cipher.active) {
    if (dbCipherSeenEncrypted || await hasEncryptedPoliciesOnDisk()) {
      throw new Error("Baza jest zaszyfrowana, a klucz nie jest teraz dostępny - zapis wstrzymany, żeby nie nadpisać danych.");
    }
    return contents;
  }
  const key = cipher.key || await requireDbCipherKey();
  dbCipherSeenEncrypted = true;
  const data = new TextEncoder().encode(contents);
  const packed = await gzipDbCipherBytes(data);
  const header = new Uint8Array(DB_CIPHER_HEADER_LENGTH);
  header.set(DB_CIPHER_MAGIC);
  header[8] = DB_CIPHER_FLAG_GZIP;
  const iv = globalThis.crypto.getRandomValues(new Uint8Array(DB_CIPHER_IV_LENGTH));
  const encrypted = new Uint8Array(await globalThis.crypto.subtle.encrypt(
    { name: "AES-GCM", iv, additionalData: header },
    key,
    packed,
  ));
  const container = new Uint8Array(header.length + iv.length + encrypted.length);
  container.set(header, 0);
  container.set(iv, header.length);
  container.set(encrypted, header.length + iv.length);
  return container;
}

async function encodeProtectedPoliciesFileContents(contents) {
  const payload = await encodePoliciesFileContents(contents);
  const bytes = typeof payload === "string"
    ? new TextEncoder().encode(payload)
    : payload instanceof Uint8Array
      ? payload
      : new Uint8Array(payload);
  if (!isEncryptedPoliciesBytes(bytes)) {
    throw new Error(
      "Nie udało się zaszyfrować kopii bazy. Zapis został wstrzymany, aby nie utworzyć jawnego pliku z danymi klientów.",
    );
  }
  return bytes;
}

async function decodeRememberedDataFileSnapshot(snapshot) {
  const storedContents = snapshot?.encryptedContents;
  let bytes;
  if (storedContents instanceof Uint8Array) {
    bytes = storedContents;
  } else if (storedContents instanceof ArrayBuffer) {
    bytes = new Uint8Array(storedContents);
  } else if (ArrayBuffer.isView(storedContents)) {
    bytes = new Uint8Array(
      storedContents.buffer,
      storedContents.byteOffset,
      storedContents.byteLength,
    );
  } else {
    bytes = new Uint8Array(storedContents || []);
  }
  if (!isEncryptedPoliciesBytes(bytes)) {
    throw new Error("Lokalna migawka bazy ma nieprawidłowy format szyfru.");
  }
  const documentData = parsePoliciesFileDocument(
    new TextDecoder().decode(await decodePoliciesFileBytes(bytes)),
  );
  return {
    version: documentData.version,
    updatedAt: snapshot.updatedAt || documentData.updatedAt || "",
    fileName: snapshot.fileName || "polisy-dane.json",
    sourceLastModified: Number(snapshot.sourceLastModified) || 0,
    sourceSize: Number(snapshot.sourceSize) || 0,
    contentFingerprint: getPoliciesFingerprint(
      documentData.policies,
      documentData.deletedPolicies,
      documentData.calendarTasks,
      documentData.employeePackageImports,
      documentData.clientAccountLinks,
    ),
    policies: documentData.policies,
    deletedPolicies: documentData.deletedPolicies,
    calendarTasks: documentData.calendarTasks,
    employeePackageImports: documentData.employeePackageImports,
    clientAccountLinks: documentData.clientAccountLinks,
  };
}

function formatDbRescueKeyForDisplay(hex) {
  return String(hex || "").replace(/(.{8})(?=.)/g, "$1 ").trim().toUpperCase();
}

function updateDbCipherSettingsStatus(cipher) {
  const section = document.getElementById("settingsEncryptionSection");
  const status = document.getElementById("settingsEncryptionStatus");
  const button = document.getElementById("showRescueKeyButton");
  if (!section || !status) return;
  section.hidden = false;
  if (cipher?.active && !cipher?.key) {
    
    
    status.textContent = "Baza na dysku jest zaszyfrowana, a ten komputer nie ma do niej klucza. Podaj klucz ratunkowy, aby ją odblokować.";
    if (button) button.hidden = true;
    return;
  }
  if (cipher?.active && cipher?.key) {
    status.textContent = cipher.rescueConfirmed
      ? "Klucz ratunkowy został zapisany."
      : "Zapisz klucz ratunkowy w bezpiecznym miejscu.";
    if (button) button.hidden = false;
  } else {
    status.textContent = "Szyfrowanie bazy nie jest aktywne na tym komputerze.";
    if (button) button.hidden = true;
  }
}

function scheduleDbCipherRescueReminder() {
  if (dbCipherRescueReminderScheduled) return;
  dbCipherRescueReminderScheduled = true;
  globalThis.setTimeout(() => {
    void openDbCipherRescueKeyDialog({ firstRun: true });
  }, 2500);
}



function openDbCipherOverlay(overlay) {
  if (!overlay) return;
  overlay.dataset.hidden = "false";
  if (typeof overlay.showModal === "function") {
    if (!overlay.open) overlay.showModal();
  }
}

function closeDbCipherOverlay(overlay) {
  if (!overlay) return;
  overlay.dataset.hidden = "true";
  if (typeof overlay.close === "function" && overlay.open) overlay.close();
  
  const wartoscKlucza = overlay.querySelector?.("#cipherRescueKeyValue");
  if (wartoscKlucza) wartoscKlucza.textContent = "";
  const wpisanyKlucz = overlay.querySelector?.("#cipherRestoreInput");
  if (wpisanyKlucz) wpisanyKlucz.value = "";
}



async function openDbCipherRescueKeyDialog({ firstRun = false } = {}) {
  const overlay = document.getElementById("cipherRescueKeyOverlay");
  if (!overlay) return;
  
  
  if (firstRun) {
    try {
      const statusResponse = await apiFetch("/api/szyfr/status");
      const status = statusResponse.ok ? await statusResponse.json().catch(() => null) : null;
      if (status?.ratunkowyPotwierdzony === true) {
        dbCipherPromise = null;
        void getDbCipher().catch(() => {});
        return;
      }
    } catch {
    }
  }
  let payload = null;
  try {
    const response = await apiFetch("/api/szyfr/klucz-ratunkowy");
    if (response.ok) payload = await response.json().catch(() => null);
  } catch {
  }
  if (!payload?.klucz) {
    if (!firstRun) showToast("Nie udało się pobrać klucza ratunkowego. Spróbuj ponownie.");
    return;
  }
  const keyHex = payload.klucz;
  const keyDisplay = document.getElementById("cipherRescueKeyValue");
  if (keyDisplay) keyDisplay.textContent = formatDbRescueKeyForDisplay(keyHex);
  const confirmButton = document.getElementById("cipherRescueKeyConfirm");
  if (confirmButton) confirmButton.hidden = payload.ratunkowyPotwierdzony === true;
  openDbCipherOverlay(overlay);

  const copyButton = document.getElementById("cipherRescueKeyCopy");
  if (copyButton) {
    copyButton.onclick = async () => {
      try {
        await globalThis.navigator.clipboard.writeText(formatDbRescueKeyForDisplay(keyHex));
        showToast("Klucz ratunkowy skopiowany. Wklej go w bezpiecznym miejscu poza tym komputerem.");
      } catch {
        showToast("Nie udało się skopiować klucza.");
      }
    };
  }
  const downloadButton = document.getElementById("cipherRescueKeyDownload");
  if (downloadButton) {
    downloadButton.onclick = () => {
      const contents = [
        "Klucz ratunkowy szyfrowania bazy polis",
        `Utworzono: ${new Date().toLocaleString("pl-PL")}`,
        "",
        formatDbRescueKeyForDisplay(keyHex),
        "",
        "Ten klucz pozwala odzyskać dostęp do bazy polis po reinstalacji systemu Windows,",
        "przeniesieniu dysku lub awarii komputera. Przechowuj go POZA tym komputerem:",
        "wydrukuj albo zapisz na pendrive. Nie udostępniaj go nikomu.",
      ].join("\r\n");
      const blob = new Blob([contents], { type: "text/plain;charset=utf-8" });
      const url = URL.createObjectURL(blob);
      const link = document.createElement("a");
      link.href = url;
      link.download = "klucz-ratunkowy-bazy-polis.txt";
      link.click();
      URL.revokeObjectURL(url);
      showToast("Zapisano plik z kluczem. Przenieś go na pendrive albo wydrukuj.");
    };
  }
  if (confirmButton) {
    confirmButton.onclick = async () => {
      try {
        const response = await apiFetch("/api/szyfr/potwierdz-ratunkowy", {
          method: "POST",
          headers: { "Content-Type": "application/json" },
          body: "{}",
        });
        if (!response.ok) throw new Error();
        closeDbCipherOverlay(overlay);
        showToast("Zapisano. Pamiętaj: klucz ratunkowy trzymaj poza tym komputerem.");
        dbCipherPromise = null;
        void getDbCipher().catch(() => {});
      } catch {
        showToast("Nie udało się zapisać potwierdzenia. Spróbuj ponownie.");
      }
    };
  }
  const laterButton = document.getElementById("cipherRescueKeyLater");
  if (laterButton) laterButton.onclick = () => closeDbCipherOverlay(overlay);
}

let dbCipherRescueDialogPromise = null;




function showDbCipherRescueDialog({ powod = "" } = {}) {
  if (dbCipherRescueDialogPromise) return dbCipherRescueDialogPromise;
  const overlay = document.getElementById("cipherRestoreOverlay");
  if (!overlay) {
    return Promise.reject(new Error("Baza jest zaszyfrowana i czeka na klucz ratunkowy."));
  }
  dbCipherRescueDialogPromise = new Promise((resolve, reject) => {
    const input = document.getElementById("cipherRestoreInput");
    const errorLabel = document.getElementById("cipherRestoreError");
    const submitButton = document.getElementById("cipherRestoreSubmit");
    const cancelButton = document.getElementById("cipherRestoreCancel");
    if (errorLabel) {
      errorLabel.textContent = powod || "";
      errorLabel.hidden = !powod;
    }
    if (input) input.value = "";
    openDbCipherOverlay(overlay);
    if (input) input.focus();

    const finish = (ok, error) => {
      overlay.onkeydown = null;
      overlay.oncancel = null;
      closeDbCipherOverlay(overlay);
      dbCipherRescueDialogPromise = null;
      if (ok) resolve();
      else reject(error || new Error("Przywracanie klucza zostało przerwane."));
    };
    
    
    overlay.onkeydown = (event) => {
      if (event.key === "Enter" && !submitButton?.disabled) {
        event.preventDefault();
        submitButton?.click();
      }
    };
    overlay.oncancel = (event) => {
      event.preventDefault();
      finish(false);
    };

    if (submitButton) {
      submitButton.onclick = async () => {
        const value = String(input?.value || "");
        submitButton.disabled = true;
        try {
          const response = await apiFetch("/api/szyfr/przywroc-klucz", {
            method: "POST",
            headers: { "Content-Type": "application/json" },
            body: JSON.stringify({ klucz: value }),
          });
          const payload = await response.json().catch(() => ({}));
          if (!response.ok) {
            if (errorLabel) {
              errorLabel.textContent = payload?.error || "Nie udało się przywrócić klucza.";
              errorLabel.hidden = false;
            }
            return;
          }
          showToast("Klucz przywrócony. Baza jest znowu dostępna na tym komputerze.");
          finish(true);
        } catch {
          if (errorLabel) {
            errorLabel.textContent = "Nie udało się połączyć z aplikacją. Spróbuj ponownie.";
            errorLabel.hidden = false;
          }
        } finally {
          submitButton.disabled = false;
        }
      };
    }
    if (cancelButton) {
      cancelButton.onclick = () => finish(false);
    }
  });
  return dbCipherRescueDialogPromise;
}

function initDbCipherUi() {
  const showButton = document.getElementById("showRescueKeyButton");
  if (showButton) {
    showButton.addEventListener("click", () => {
      void openDbCipherRescueKeyDialog();
    });
  }
}

initDbCipherUi();

function createDataFileRevision(file, documentData) {
  return {
    fileName: file?.name || dataFileName || "polisy-dane.json",
    lastModified: Number(file?.lastModified) || 0,
    size: Number(file?.size) || 0,
    updatedAt: documentData.updatedAt || "",
    contentFingerprint: getPoliciesFingerprint(
      documentData.policies,
      documentData.deletedPolicies,
      documentData.calendarTasks,
      documentData.employeePackageImports,
      documentData.clientAccountLinks,
    ),
  };
}

async function inspectPoliciesFile(file) {
  const documentData = parsePoliciesFileDocument(await readPoliciesFileText(file));
  return {
    file,
    documentData,
    revision: createDataFileRevision(file, documentData),
  };
}

function policiesMatchRevision(
  policyRecords,
  revision,
  deletedRecords = deletedPolicies,
  taskRecords = calendarTasks,
  importReceipts = employeePackageImportReceipts,
  accountLinks = clientAccountLinks,
) {
  return Boolean(revision?.contentFingerprint)
    && getPoliciesFingerprint(
      policyRecords,
      deletedRecords,
      taskRecords,
      importReceipts,
      accountLinks,
    ) === revision.contentFingerprint;
}

async function verifyDataFileFreshness(handle, options = {}) {
  const inspection = await inspectPoliciesFile(await handle.getFile());
  if (!dataFileRevision || inspection.revision.contentFingerprint === dataFileRevision.contentFingerprint) {
    dataFileRevision = inspection.revision;
    return "fresh";
  }

  const loadDiskVersion = typeof globalThis.confirm === "function" && globalThis.confirm(
    options.reapplyAfterReload
      ? "Plik bazy został zmieniony poza tą kartą.\n\nKliknij OK, aby wczytać aktualną wersję z dysku i ponowić na niej bieżącą zmianę. Kliknij Anuluj, aby zatrzymać zapis."
      : "Plik bazy został zmieniony poza tą kartą.\n\nKliknij OK, aby wczytać aktualną wersję z dysku. Po wczytaniu ponów wykonywaną czynność. Kliknij Anuluj, aby zatrzymać zapis.",
  );
  if (loadDiskVersion) {
    await loadPoliciesFromFile(inspection.file, handle, {
      inspection,
      permissionGranted: true,
      skipLegacy: true,
      showToast: false,
      trustedSource: true,
    });
    showToast(options.reapplyAfterReload
      ? "Wczytano nowszą bazę - ponawiam bieżącą zmianę"
      : "Wczytano nowszą wersję bazy z dysku");
    return "reloaded";
  } else {
    dataFileHandle = null;
    dataFileNeedsVerification = true;
    dataFileConflictBlocked = true;
    hasUnsavedPolicyChanges = true;
    setDataIntegrityNotice(
      "error",
      "Zapis zatrzymany - plik został zmieniony",
      "Bieżąca karta nie nadpisała nowszego pliku. Wczytaj plik z dysku albo zapisz tę wersję jako osobną bazę.",
      "Zapisz jako nową bazę",
    );
  }
  return "blocked";
}

async function connectRememberedDataFile() {
  const handle = rememberedDataFileHandle;
  if (!handle) return false;
  if (!(await requestWritePermission(handle))) {
    dataFileNeedsVerification = true;
    setDataIntegrityNotice(
      "error",
      "Brak dostępu do pliku bazy",
      "Przeglądarka nie otrzymała zgody na odczyt i zapis zapamiętanego pliku.",
      "Wskaż plik",
    );
    return false;
  }
  const inspection = await inspectPoliciesFile(await handle.getFile());

  const memoryMatchesDisk = policiesMatchRevision(policies, inspection.revision);
  const diskMatchesKnownBaseline = !dataFileConflictBlocked
    && Boolean(dataFileRevision?.contentFingerprint)
    && dataFileRevision.contentFingerprint === inspection.revision.contentFingerprint;
  if (memoryMatchesDisk || diskMatchesKnownBaseline) {
    dataFileHandle = handle;
    rememberedDataFileHandle = handle;
    dataFileName = handle.name || dataFileName || "polisy-dane.json";
    dataFileRevision = inspection.revision;
    initialDataFileReady = true;
    dataFileNeedsVerification = false;
    dataFileConflictBlocked = false;
    hasUnsavedPolicyChanges = !memoryMatchesDisk;
    await rememberDataFileHandle(handle);
    await rememberDataFileSnapshot();
    if (hasUnsavedPolicyChanges) {
      setDataIntegrityNotice(
        "warning",
        "Niezapisane zmiany",
        "Połączenie z plikiem zostało przywrócone. Ponów zapis zmian.",
        "Ponów zapis",
      );
    } else {
      clearDataIntegrityNotice();
    }
    return true;
  }

  const loadDiskVersion = typeof globalThis.confirm === "function" && globalThis.confirm(
    "Plik na dysku różni się od lokalnej kopii w pamięci aplikacji.\n\nKliknij OK, aby wczytać plik z dysku. Kliknij Anuluj, aby pozostawić lokalną kopię i zapisać ją później jako osobny plik.",
  );
  if (loadDiskVersion) {
    await loadPoliciesFromFile(inspection.file, handle, {
      inspection,
      permissionGranted: true,
      skipLegacy: true,
      showToast: false,
      trustedSource: true,
    });
    showToast("Wczytano bazę z dysku");
  } else {
    dataFileHandle = null;
    dataFileRevision = inspection.revision;
    dataFileNeedsVerification = true;
    dataFileConflictBlocked = true;
    hasUnsavedPolicyChanges = true;
    setDataIntegrityNotice(
      "warning",
      "Lokalna kopia różni się od pliku",
      "Oryginalny plik nie zostanie nadpisany. Zapisz lokalną kopię jako nową bazę albo ponownie otwórz plik z dysku.",
      "Zapisz jako nową bazę",
    );
  }
  return false;
}

function createHandledWriteError(message, details = {}) {
  const error = new Error(message);
  error.handled = true;
  Object.assign(error, details);
  return error;
}

async function withDataFileWriteLock(callback) {
  if (globalThis.navigator?.locks?.request) {
    return globalThis.navigator.locks.request("baza-polis-data-file-write", { mode: "exclusive" }, callback);
  }
  return callback();
}

async function writePoliciesToHandleUnderEmployeePackageLock(handle, options = {}) {
  if (!(await requestWritePermission(handle))) {
    throw new Error("Brak zgody na zapis do wybranego pliku.");
  }
  return withDataFileWriteLock(async () => {
    if (!options.skipFreshnessCheck && dataFileHandle === handle) {
      const freshness = await verifyDataFileFreshness(handle, {
        reapplyAfterReload: options.reapplyAfterReload,
      });
      if (freshness !== "fresh") {
        throw createHandledWriteError("Zapis zatrzymano z powodu konfliktu wersji pliku.", {
          conflictReloaded: freshness === "reloaded",
        });
      }
    }
    const updatedAt = new Date().toISOString();
    const writeGeneration = policyChangeGeneration;
    const writeSnapshot = createCanonicalDataFileWriteSnapshot(policies, updatedAt);
    const payload = await encodePoliciesFileContents(writeSnapshot.contents);
    const writable = await handle.createWritable();
    await writable.write(payload);
    await writable.close();
    let writtenFile = null;
    try {
      writtenFile = await handle.getFile();
    } catch {
    }
    dataFileHandle = handle;
    rememberedDataFileHandle = handle;
    dataFileName = handle.name || dataFileName || "polisy-dane.json";
    dataFileRevision = {
      fileName: dataFileName,
      lastModified: Number(writtenFile?.lastModified) || Date.now(),
      size: Number(writtenFile?.size) || new Blob([payload]).size,
      updatedAt,
      contentFingerprint: writeSnapshot.contentFingerprint,
    };
    initialDataFileReady = true;
    await rememberDataFileHandle(handle);
    await rememberDataFileSnapshot(
      writeSnapshot.documentData.policies,
      dataFileRevision,
      writeSnapshot.documentData.deletedPolicies,
      writeSnapshot.documentData.calendarTasks,
      writeSnapshot.documentData.employeePackageImports,
      writeSnapshot.documentData.clientAccountLinks,
    );
    clearLegacyPolicies();
    if (policyChangeGeneration === writeGeneration) {
      markPoliciesSaved();
    } else {
      
      
      hasUnsavedPolicyChanges = true;
      updateDataFileStatus();
    }
  });
}

function writePoliciesToHandle(handle, options = {}) {
  if (
    options.employeePackageImportLockHeld === true
    || !globalThis.navigator?.locks?.request
  ) {
    return writePoliciesToHandleUnderEmployeePackageLock(handle, options);
  }
  return globalThis.navigator.locks.request(
    EMPLOYEE_PACKAGE_IMPORT_LOCK_NAME,
    { mode: "exclusive" },
    () => writePoliciesToHandleUnderEmployeePackageLock(handle, options),
  );
}

async function downloadPoliciesFile() {
  const updatedAt = new Date().toISOString();
  const writeSnapshot = createCanonicalDataFileWriteSnapshot(policies, updatedAt);
  const payload = await encodeProtectedPoliciesFileContents(writeSnapshot.contents);
  const blob = new Blob([payload], { type: "application/octet-stream" });
  const url = URL.createObjectURL(blob);
  const link = document.createElement("a");
  link.href = url;
  link.download = dataFileName || "polisy-dane.json";
  link.click();
  URL.revokeObjectURL(url);
  dataFileName = link.download;
  dataFileRevision = null;
  dataFileNeedsVerification = false;
  dataFileConflictBlocked = false;
  initialDataFileReady = true;
  hasUnsavedPolicyChanges = false;
  await rememberDataFileSnapshot(
    writeSnapshot.documentData.policies,
    {
      fileName: link.download,
      updatedAt,
      size: blob.size,
    },
    writeSnapshot.documentData.deletedPolicies,
    writeSnapshot.documentData.calendarTasks,
    writeSnapshot.documentData.employeePackageImports,
    writeSnapshot.documentData.clientAccountLinks,
  );
  clearLegacyPolicies();
  setDataIntegrityNotice(
    "download",
    "Pobrano nową kopię bazy",
    "Przeglądarka nie może zapisywać bezpośrednio do pierwotnego pliku. Nowa wersja znajduje się w Pobranych - zastąp nią poprzedni plik.",
    "Zapisz jako",
  );
  updateDataFileStatus();
}

function createBackupFileName(date = new Date()) {
  const sourceName = dataFileHandle?.name
    || rememberedDataFileHandle?.name
    || dataFileName
    || "polisy-dane.json";
  const baseName = String(sourceName)
    .replace(/\.json$/i, "")
    .replace(/[<>:"/\\|?*\u0000-\u001F]/g, "_")
    .replace(/[.\s]+$/g, "")
    .trim()
    .slice(0, 120) || "polisy-dane";
  const pad = (value) => String(value).padStart(2, "0");
  const timestamp = [
    `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())}`,
    `${pad(date.getHours())}-${pad(date.getMinutes())}-${pad(date.getSeconds())}`,
  ].join("_");
  return `kopiazapasowa_${baseName}_${timestamp}.json`;
}

function downloadBackupFile(contents, fileName) {
  const blob = new Blob([contents], { type: "application/octet-stream" });
  const url = URL.createObjectURL(blob);
  const link = document.createElement("a");
  link.href = url;
  link.download = fileName;
  link.click();
  URL.revokeObjectURL(url);
}

async function createDataFileBackup() {
  const backupFileName = createBackupFileName();

  try {
    const writeSnapshot = createCanonicalDataFileWriteSnapshot();
    const payload = await encodeProtectedPoliciesFileContents(writeSnapshot.contents);
    if (typeof globalThis.showSaveFilePicker !== "function") {
      downloadBackupFile(payload, backupFileName);
      showToast(`Utworzono kopię zapasową: ${backupFileName}`);
      return;
    }

    const pickerOptions = {
      suggestedName: backupFileName,
      types: [{
        description: "Kopia zapasowa bazy polis",
        accept: { "application/json": [".json"] },
      }],
    };
    const currentFileHandle = dataFileHandle || rememberedDataFileHandle;
    if (currentFileHandle) pickerOptions.startIn = currentFileHandle;

    const backupHandle = await globalThis.showSaveFilePicker(pickerOptions);
    if (!(await requestWritePermission(backupHandle))) {
      throw new Error("Brak zgody na zapis kopii zapasowej.");
    }
    const writable = await backupHandle.createWritable();
    await writable.write(payload);
    await writable.close();
    showToast(`Utworzono kopię zapasową: ${backupHandle.name || backupFileName}`);
  } catch (error) {
    if (error?.name !== "AbortError") {
      showToast(error?.message || "Nie udało się utworzyć kopii zapasowej");
    }
  }
}

async function saveDataFileAs(options = {}) {
  try {
    if (typeof globalThis.showSaveFilePicker !== "function") {
      await downloadPoliciesFile();
      showToast("Pobrano nową kopię pliku danych");
      return true;
    }

    const handle = await showSystemPicker("showSaveFilePicker", {
      id: "baza-polis-dane",
      startIn: getPickerStartLocation(dataFileHandle, rememberedDataFileHandle),
      suggestedName: dataFileName || "polisy-dane.json",
      types: [{
        description: "Plik danych polis",
        accept: { "application/json": [".json"] },
      }],
    });
    await writePoliciesToHandle(handle, {
      skipFreshnessCheck: true,
      employeePackageImportLockHeld: options.employeePackageImportLockHeld === true,
    });
    showToast("Plik danych został zapisany");
    return true;
  } catch (error) {
    if (error?.name !== "AbortError") showToast(error?.message || "Nie udało się zapisać pliku danych");
    return false;
  }
}

async function ensureWritableDataFile(options = {}) {
  if (dataFileHandle) {
    if (options.deferFreshnessCheck) return true;
    return (await verifyDataFileFreshness(dataFileHandle)) === "fresh";
  }
  if (!dataFileHandle && rememberedDataFileHandle) {
    try {
      const connected = await connectRememberedDataFile();
      return connected || Boolean(dataFileHandle && !dataFileConflictBlocked);
    } catch (error) {
      dataFileNeedsVerification = true;
      setDataIntegrityNotice(
        "error",
        "Nie udało się połączyć z plikiem bazy",
        error?.message || "Wskaż plik ponownie albo zapisz bieżącą bazę jako nowy plik.",
        "Wskaż plik",
      );
      return false;
    }
  }
  if (typeof globalThis.showSaveFilePicker !== "function") return true;
  return saveDataFileAs({
    employeePackageImportLockHeld: options.employeePackageImportLockHeld === true,
  });
}

async function persistPolicies(options = {}) {
  
  
  
  if (licenseGuardState.tylkoOdczyt === true) {
    hasUnsavedPolicyChanges = true;
    updateDataFileStatus();
    showToast(licenseGuardState.komunikat || "Licencja jest nieważna. Program pokazuje dane, ale ich nie zapisuje.", "warning");
    void refreshLicenseGuard();
    return false;
  }
  if (!dataFileHandle && rememberedDataFileHandle) {
    try {
      if (!(await connectRememberedDataFile())) {
        hasUnsavedPolicyChanges = true;
        updateDataFileStatus();
        return false;
      }
    } catch (error) {
      dataFileNeedsVerification = true;
      hasUnsavedPolicyChanges = true;
      setDataIntegrityNotice(
        "error",
        "Nie udało się połączyć z plikiem bazy",
        error?.message || "Zmiany pozostają w pamięci. Wskaż plik ponownie albo zapisz bazę jako nowy plik.",
        "Wskaż plik",
      );
      return false;
    }
  }
  markPoliciesDirty();
  let reapplyAttempts = 0;
  while (true) {
    try {
      if (dataFileHandle) {
        await writePoliciesToHandle(dataFileHandle, {
          reapplyAfterReload: typeof options.reapplyAfterConflict === "function",
          employeePackageImportLockHeld: options.employeePackageImportLockHeld === true,
        });
      } else {
        await downloadPoliciesFile();
      }
      return true;
    } catch (error) {
      if (
        error?.conflictReloaded
        && typeof options.reapplyAfterConflict === "function"
        && reapplyAttempts < 3
      ) {
        reapplyAttempts += 1;
        let reapplied = false;
        try {
          reapplied = await options.reapplyAfterConflict();
        } catch (reapplyError) {
          setDataIntegrityNotice(
            "error",
            "Nie udało się ponowić zmiany",
            reapplyError?.message || "Nowsza wersja bazy została wczytana, ale bieżącej zmiany nie udało się nałożyć ponownie.",
            "Zamknij",
          );
          showToast(reapplyError?.message || "Nie udało się ponowić zmiany na nowszej bazie", "error");
          updateDataFileStatus();
          return false;
        }
        if (reapplied !== false) {
          markPoliciesDirty("Bieżąca zmiana została ponownie nałożona na nowszą bazę i czeka na zapis.");
          continue;
        }
        setDataIntegrityNotice(
          "error",
          "Nie można ponowić zmiany",
          options.reapplyFailureMessage || "Rekordu nie ma już w nowszej wersji bazy. Zmiana nie została zapisana.",
          "Zamknij",
        );
        updateDataFileStatus();
        return false;
      }
      if (error?.conflictReloaded) {
        setDataIntegrityNotice(
          "error",
          "Plik zmienia się zbyt szybko",
          "Nowsza wersja została ponownie wczytana, ale zapis nie może zostać bezpiecznie dokończony. Spróbuj ponownie po zamknięciu drugiej karty.",
          "Zamknij",
        );
      }
      if (!error?.handled) {
        dataFileHandle = null;
        dataFileNeedsVerification = Boolean(rememberedDataFileHandle);
        dataFileConflictBlocked = false;
        setDataIntegrityNotice(
          "error",
          "Nie udało się zapisać zmian",
          error?.message || "Zmiany pozostają w pamięci. Ponów zapis albo zapisz bazę jako nowy plik.",
          "Ponów zapis",
        );
        showToast(error?.message || "Nie udało się zapisać zmian do pliku", "error");
      }
      updateDataFileStatus();
      return false;
    }
  }
}



function getDatabaseOwnershipStatus(fileAccountId) {
  const accountId = normalizePolicyOwnerId(fileAccountId);
  if (!accountId) return { status: "legacy", accountId: "" };
  if (currentAccount && accountId === currentAccount.id) return { status: "own", accountId };
  const member = getAgencyMemberById(accountId);
  if (member) return { status: "member", accountId, member };
  return { status: "unknown", accountId };
}



function assertDatabaseCanBeOpened(documentData) {
  const ownership = getDatabaseOwnershipStatus(documentData?.accountId);
  if (ownership.status === "member") {
    throw new Error(
      `To baza pracownika „${ownership.member.label}”. Nie otwiera się jej jako własnej - `
      + "wczytaj ją przyciskiem „Importuj bazę” przy tym pracowniku (Ustawienia → Agencja), "
      + "a jego polisy trafią do Twojej bazy z właściwym oznaczeniem.",
    );
  }
  if (ownership.status === "unknown") {
    throw new Error(
      `Ta baza należy do konta o identyfikatorze ${ownership.accountId}, którego nie ma w Twojej agencji. `
      + "Jeśli to baza Twojego pracownika, najpierw dodaj jego identyfikator w Ustawieniach, w zakładce Agencja.",
    );
  }
}

function parsePoliciesFileDocument(contents) {
  const parsed = JSON.parse(contents);
  const isLegacyArray = Array.isArray(parsed);
  const records = isLegacyArray ? parsed : parsed?.policies;
  if (!Array.isArray(records)) throw new Error("Wybrany plik nie zawiera prawidłowej listy polis.");
  const declaredVersion = isLegacyArray || parsed?.version === undefined ? 1 : Number(parsed.version);
  if (!Number.isInteger(declaredVersion) || declaredVersion < 1) {
    throw new Error("Plik bazy ma nieprawidłowy numer wersji.");
  }
  if (declaredVersion > DATA_FILE_VERSION) {
    throw new Error(`Ta baza ma nowszy format v${declaredVersion}. Zaktualizuj aplikację przed jej otwarciem.`);
  }
  
  
  
  const accountId = isLegacyArray ? "" : normalizePolicyOwnerId(parsed?.accountId);
  const accountName = isLegacyArray ? "" : String(parsed?.accountName || "").trim().slice(0, 40);
  return {
    version: declaredVersion,
    updatedAt: typeof parsed?.updatedAt === "string" ? parsed.updatedAt : "",
    accountId,
    accountName,
    policies: normalizeLoadedPolicies(records, accountId || currentAccount?.id || ""),
    deletedPolicies: normalizeDeletedPolicies(isLegacyArray ? [] : parsed?.deletedPolicies),
    calendarTasks: normalizeCalendarTasks(isLegacyArray ? [] : parsed?.calendarTasks),
    employeePackageImports: normalizeEmployeePackageImportReceipts(
      isLegacyArray ? [] : parsed?.employeePackageImports,
    ),
    clientAccountLinks: normalizeClientAccountLinks(
      isLegacyArray ? [] : parsed?.clientAccountLinks,
    ),
  };
}

function parsePoliciesFile(contents) {
  return parsePoliciesFileDocument(contents).policies;
}

function updateMergeDatabasesButton() {
  const hasFirstFile = Boolean(elements.mergeFirstDataFile.files?.[0]);
  const hasSecondFile = Boolean(elements.mergeSecondDataFile.files?.[0]);
  elements.mergeDataFiles.disabled = !(hasFirstFile && hasSecondFile);
}

function getPolicyNumberKey(policyOrNumber) {
  const value = policyOrNumber && typeof policyOrNumber === "object"
    ? policyOrNumber.policyNumber
    : policyOrNumber;
  return normalize(value).toLocaleUpperCase("pl").replace(/[^0-9A-Z]/g, "");
}

function getPolicyIdentityKey(policy) {
  const policyNumberKey = getPolicyNumberKey(policy);
  if (!policyNumberKey) return "";
  return `${policyNumberKey}\u0000${normalizeInsurerId(policy?.insurer)}`;
}

function normalizeMergePolicyEndDate(value) {
  const date = parseLocalDate(value);
  return date ? formatDateForInput(date) : normalize(value);
}



function getPolicyIdentityPeriodKey(policy) {
  const identityKey = getPolicyIdentityKey(policy);
  if (!identityKey) return "";
  return [
    identityKey,
    normalizeMergePolicyEndDate(policy?.validFrom),
    normalizeMergePolicyEndDate(policy?.validUntil),
  ].join("\u0000");
}

function getMergePolicyNumberDateKey(policy) {
  const policyNumber = getPolicyNumberKey(policy);
  if (!policyNumber) return "";
  return `${policyNumber}\u0000${normalizeMergePolicyEndDate(policy?.validUntil)}`;
}

function doPoliciesConflictForDatabaseMerge(firstPolicy, secondPolicy) {
  const firstNumberDateKey = getMergePolicyNumberDateKey(firstPolicy);
  if (!firstNumberDateKey || firstNumberDateKey !== getMergePolicyNumberDateKey(secondPolicy)) return false;
  const firstInsurerKey = normalizeInsurerId(firstPolicy?.insurer);
  const secondInsurerKey = normalizeInsurerId(secondPolicy?.insurer);
  return !firstInsurerKey || !secondInsurerKey || firstInsurerKey === secondInsurerKey;
}

function stableStringifyDatabaseMergeValue(value) {
  if (Array.isArray(value)) {
    return `[${value.map((item) => stableStringifyDatabaseMergeValue(item)).join(",")}]`;
  }
  if (value && typeof value === "object") {
    return `{${Object.keys(value)
      .sort()
      .map((key) => `${JSON.stringify(key)}:${stableStringifyDatabaseMergeValue(value[key])}`)
      .join(",")}}`;
  }
  return JSON.stringify(value);
}

function getDatabaseMergePolicyComparableValue(policy) {
  if (!policy || typeof policy !== "object") return stableStringifyDatabaseMergeValue(policy);
  const { updatedAt: _updatedAt, ...comparablePolicy } = policy;
  return stableStringifyDatabaseMergeValue(comparablePolicy);
}

function getDatabaseMergeUpdatedAt(policy) {
  const numericValue = Number(policy?.updatedAt);
  if (Number.isFinite(numericValue)) return numericValue;
  const parsedValue = Date.parse(String(policy?.updatedAt || ""));
  return Number.isFinite(parsedValue) ? parsedValue : 0;
}

function collectDatabaseMergeDeletedCandidates(firstDeletedPolicies, secondDeletedPolicies) {
  const candidatesById = new Map();
  const register = (policy, source) => {
    const policyId = String(policy?.id || "").trim();
    if (!policyId) return;
    const existing = candidatesById.get(policyId);
    if (!existing || Number(policy?.deletedAt) >= Number(existing.policy?.deletedAt)) {
      candidatesById.set(policyId, { policy, source });
    }
  };
  firstDeletedPolicies.forEach((policy) => register(policy, "first"));
  secondDeletedPolicies.forEach((policy) => register(policy, "second"));
  return [...candidatesById.values()];
}

function prepareDatabaseMerge(
  firstPolicies,
  secondPolicies,
  firstDeletedPolicies = [],
  secondDeletedPolicies = [],
) {
  const mergedPolicies = [];
  const indexesByPolicyId = new Map();
  const sourceByMergedIndex = new Map();
  const conflicts = [];
  const registerMergedPolicy = (policy, source) => {
    const newIndex = mergedPolicies.push(policy) - 1;
    const policyId = String(policy?.id || "").trim();
    if (policyId) indexesByPolicyId.set(policyId, newIndex);
    sourceByMergedIndex.set(newIndex, source);
    return newIndex;
  };
  const appendOrRegisterConflict = (policy, source) => {
    const policyId = String(policy?.id || "").trim();
    const sameIdIndex = policyId ? indexesByPolicyId.get(policyId) : undefined;
    if (sameIdIndex !== undefined) {
      const existingPolicy = mergedPolicies[sameIdIndex];
      if (
        getDatabaseMergePolicyComparableValue(existingPolicy)
        === getDatabaseMergePolicyComparableValue(policy)
      ) {
        if (getDatabaseMergeUpdatedAt(policy) > getDatabaseMergeUpdatedAt(existingPolicy)) {
          mergedPolicies[sameIdIndex] = policy;
          sourceByMergedIndex.set(sameIdIndex, source);
        }
        return;
      }
      conflicts.push({
        kind: "same-id",
        allowKeepBoth: false,
        secondPolicy: policy,
        targetIndex: sameIdIndex,
        firstSource: sourceByMergedIndex.get(sameIdIndex) || "first",
        secondSource: source,
      });
      return;
    }
    registerMergedPolicy(policy, source);
  };

  firstPolicies.forEach((policy) => appendOrRegisterConflict(policy, "first"));
  secondPolicies.forEach((policy) => appendOrRegisterConflict(policy, "second"));

  return {
    conflicts,
    mergedPolicies,
    sourceByMergedIndex,
    deletedCandidates: collectDatabaseMergeDeletedCandidates(
      firstDeletedPolicies,
      secondDeletedPolicies,
    ),
  };
}

function getNaturalDatabaseMergeConflictPairKey(firstPolicy, secondPolicy) {
  return [String(firstPolicy?.id || "").trim(), String(secondPolicy?.id || "").trim()]
    .sort()
    .join("\u0000");
}

function findNaturalDatabaseMergeConflicts(
  policyRecords,
  sourceByMergedIndex,
  allowedConflictPairs = new Set(),
) {
  const indexesByNumberDateKey = new Map();
  const conflicts = [];
  policyRecords.forEach((policy, policyIndex) => {
    if (!policy) return;
    const numberDateKey = getMergePolicyNumberDateKey(policy);
    if (!numberDateKey) return;
    const candidateIndexes = indexesByNumberDateKey.get(numberDateKey) || [];
    candidateIndexes.forEach((candidateIndex) => {
      const firstPolicy = policyRecords[candidateIndex];
      if (!firstPolicy || !doPoliciesConflictForDatabaseMerge(firstPolicy, policy)) return;
      const pairKey = getNaturalDatabaseMergeConflictPairKey(firstPolicy, policy);
      if (allowedConflictPairs.has(pairKey)) return;
      conflicts.push({
        kind: "natural-key",
        allowKeepBoth: true,
        firstIndex: candidateIndex,
        secondIndex: policyIndex,
        firstPolicy,
        secondPolicy: policy,
        firstSource: sourceByMergedIndex.get(candidateIndex) || "first",
        secondSource: sourceByMergedIndex.get(policyIndex) || "second",
        pairKey,
      });
    });
    candidateIndexes.push(policyIndex);
    indexesByNumberDateKey.set(numberDateKey, candidateIndexes);
  });
  return conflicts;
}

function formatMergeDeletionTimestamp(value) {
  const timestamp = Number(value);
  if (!Number.isFinite(timestamp) || timestamp <= 0) return "Usunięta (kosz)";
  return `Usunięta ${new Date(timestamp).toLocaleString("pl-PL")}`;
}

function createMergeRecordDetails(policy, { deleted = false } = {}) {
  const fields = [
    ...(deleted ? [["Stan", formatMergeDeletionTimestamp(policy?.deletedAt)]] : []),
    ["Imię i nazwisko / nazwa", policy.clientName],
    ["PESEL / NIP / REGON", policy.identityNumber],
    ["Towarzystwo", policy.insurer],
    ["Numer Polisy", policy.policyNumber],
    ["Od kiedy", formatStartDate(policy)],
    ["Do kiedy", formatDate(policy.validUntil)],
    ["Nr Rej. / Rodzaj Polisy", policy.registration],
    ["Składka", formatPremium(policy.premium)],
    ["Notatki", policy.contact],
  ];

  return fields.map(([label, value]) => `
    <div class="merge-record-field">
      <span>${escapeHtml(label)}</span>
      <strong>${escapeHtml(value || "-")}</strong>
    </div>
  `).join("");
}

function finishMergeConflict(decision) {
  if (!mergeConflictResolver) return;
  const resolver = mergeConflictResolver;
  mergeConflictResolver = null;
  if (elements.mergeConflictDialog.open) elements.mergeConflictDialog.close();
  resolver(decision);
}

function showMergeConflict(conflict, conflictIndex, conflictCount, databaseNames) {
  const firstDatabaseName = databaseNames[conflict.firstSource] || databaseNames.first;
  const secondDatabaseName = databaseNames[conflict.secondSource] || databaseNames.second;
  const isActiveDeletedConflict = conflict.kind === "active-deleted";
  elements.mergeConflictProgress.textContent = `Konflikt ${conflictIndex + 1} z ${conflictCount}`;
  elements.mergeConflictTitle.textContent = isActiveDeletedConflict
    ? "Polisa aktywna w jednej bazie i usunięta w drugiej"
    : conflict.kind === "same-id"
      ? "Ten sam rekord ma różne dane"
      : "Ten sam numer polisy i data końca";
  elements.mergeConflictCopy.textContent = conflict.allowKeepBoth === false
    ? "Wybierz, który stan ma trafić do połączonej bazy. Zachowanie obu wersji uszkodziłoby spójność rekordu."
    : "Porównaj oba rekordy i zdecyduj, czy zachować jeden z nich, czy oba.";
  elements.mergeFirstDatabaseName.textContent = firstDatabaseName;
  elements.mergeFirstDatabaseName.title = firstDatabaseName;
  elements.mergeSecondDatabaseName.textContent = secondDatabaseName;
  elements.mergeSecondDatabaseName.title = secondDatabaseName;
  elements.mergeFirstRecord.innerHTML = createMergeRecordDetails(
    conflict.firstPolicy,
    { deleted: conflict.firstDeleted === true },
  );
  elements.mergeSecondRecord.innerHTML = createMergeRecordDetails(
    conflict.secondPolicy,
    { deleted: conflict.secondDeleted === true },
  );
  elements.mergeKeepBoth.hidden = conflict.allowKeepBoth === false;
  elements.mergeConflictDialog.showModal();

  return new Promise((resolve) => {
    mergeConflictResolver = resolve;
  });
}

function ensureUniqueMergedPolicyIds(policyRecords) {
  const usedIds = new Set();
  return policyRecords.map((policy) => {
    const policyId = String(policy?.id || "").trim();
    if (!policyId || usedIds.has(policyId)) {
      throw new Error("Scalanie zatrzymano: wykryto brakujący albo powtórzony identyfikator polisy.");
    }
    usedIds.add(policyId);
    return policy;
  });
}

function getPreferredDatabaseMergeDecision(conflict, preferredSource) {
  if (!preferredSource) return null;
  if (conflict.firstSource === preferredSource && conflict.secondSource !== preferredSource) {
    return { side: "first", applyToAll: false };
  }
  if (conflict.secondSource === preferredSource && conflict.firstSource !== preferredSource) {
    return { side: "second", applyToAll: false };
  }
  return null;
}

function clearDanglingMergedRenewalReferences(policyRecords, removedPolicies = []) {
  const activeIds = new Set(policyRecords.map((policy) => String(policy?.id || "").trim()));
  const trackingBeforeDeletion = createRenewalManualTrackingContext([
    ...policyRecords,
    ...removedPolicies,
  ]);
  const cleanedPolicies = policyRecords.map((policy) => {
    const previousPolicyId = String(policy?.previousPolicyId || "").trim();
    if (!previousPolicyId || activeIds.has(previousPolicyId)) return policy;
    const cleanedPolicy = { ...policy };
    setPolicyRenewalPredecessor(cleanedPolicy, null, false);
    return cleanedPolicy;
  });
  const remainingSuccessorIds = new Set(
    cleanedPolicies.map((policy) => String(policy?.previousPolicyId || "").trim()).filter(Boolean),
  );
  const predecessorIdsToReview = new Set();
  removedPolicies.forEach((removedPolicy) => {
    const previousPolicyId = String(removedPolicy?.previousPolicyId || "").trim();
    if (
      previousPolicyId
      && !isRenewalPredecessorManuallyEdited(removedPolicy, trackingBeforeDeletion)
    ) {
      predecessorIdsToReview.add(previousPolicyId);
    }
  });
  return cleanedPolicies.map((policy) => {
    const policyId = String(policy?.id || "").trim();
    if (
      !predecessorIdsToReview.has(policyId)
      || remainingSuccessorIds.has(policyId)
      || policy.renewalStatus !== "renewed"
      || isRenewalStatusManuallyEdited(policy, trackingBeforeDeletion)
    ) return policy;
    const cleanedPolicy = { ...policy };
    setPolicyRenewalStatusValue(cleanedPolicy, null, false);
    return cleanedPolicy;
  });
}

async function resolveDatabaseMergeConflicts(mergePlan, databaseNames) {
  const {
    conflicts,
    mergedPolicies,
    sourceByMergedIndex,
    deletedCandidates = [],
  } = mergePlan;
  let preferredSource = "";
  const discardedPolicies = [];

  for (let index = 0; index < conflicts.length; index += 1) {
    const conflict = conflicts[index];
    const currentConflict = {
      ...conflict,
      firstPolicy: mergedPolicies[conflict.targetIndex],
      firstSource: sourceByMergedIndex.get(conflict.targetIndex) || conflict.firstSource,
    };
    const decision = getPreferredDatabaseMergeDecision(currentConflict, preferredSource)
      || await showMergeConflict(currentConflict, index, conflicts.length, databaseNames);
    if (decision?.cancelled) return null;

    if (decision?.keepBoth) {
      if (conflict.allowKeepBoth === false) {
        throw new Error("Nie można zachować obu wersji rekordu o tym samym identyfikatorze.");
      }
      const newIndex = mergedPolicies.push(conflict.secondPolicy) - 1;
      sourceByMergedIndex.set(newIndex, conflict.secondSource);
      continue;
    }

    if (decision?.side === "second") {
      discardedPolicies.push(mergedPolicies[conflict.targetIndex]);
      mergedPolicies[conflict.targetIndex] = conflict.secondPolicy;
      sourceByMergedIndex.set(conflict.targetIndex, conflict.secondSource);
    } else {
      discardedPolicies.push(conflict.secondPolicy);
    }

    if (decision?.applyToAll) {
      preferredSource = decision.side === "second"
        ? currentConflict.secondSource
        : currentConflict.firstSource;
    }
  }

  const uniqueActivePolicies = ensureUniqueMergedPolicyIds(mergedPolicies);
  const allowedNaturalConflictPairs = new Set();
  let resolvedNaturalConflictCount = 0;
  while (true) {
    const naturalConflicts = findNaturalDatabaseMergeConflicts(
      uniqueActivePolicies,
      sourceByMergedIndex,
      allowedNaturalConflictPairs,
    );
    const conflict = naturalConflicts[0];
    if (!conflict) break;
    const decision = getPreferredDatabaseMergeDecision(conflict, preferredSource)
      || await showMergeConflict(
        conflict,
        resolvedNaturalConflictCount,
        resolvedNaturalConflictCount + naturalConflicts.length,
        databaseNames,
      );
    if (decision?.cancelled) return null;
    if (decision?.keepBoth) {
      allowedNaturalConflictPairs.add(conflict.pairKey);
    } else if (decision?.side === "second") {
      discardedPolicies.push(uniqueActivePolicies[conflict.firstIndex]);
      uniqueActivePolicies[conflict.firstIndex] = null;
    } else {
      discardedPolicies.push(uniqueActivePolicies[conflict.secondIndex]);
      uniqueActivePolicies[conflict.secondIndex] = null;
    }
    resolvedNaturalConflictCount += 1;
    if (decision?.applyToAll) {
      preferredSource = decision.side === "second"
        ? conflict.secondSource
        : conflict.firstSource;
    }
  }

  const activeEntries = uniqueActivePolicies
    .map((policy, originalIndex) => (
      policy
        ? { policy, source: sourceByMergedIndex.get(originalIndex) || "first" }
        : null
    ))
    .filter(Boolean);
  const activePoliciesAfterNaturalMerge = activeEntries.map((entry) => entry.policy);
  const activeSourceById = new Map(
    activeEntries.map((entry) => [String(entry.policy.id).trim(), entry.source]),
  );
  const activeIndexById = new Map(
    activePoliciesAfterNaturalMerge.map((policy, index) => [String(policy.id).trim(), index]),
  );
  const mergedDeletedById = new Map();
  const deletionConflicts = [];
  deletedCandidates.forEach(({ policy, source }) => {
    const policyId = String(policy?.id || "").trim();
    const activeIndex = activeIndexById.get(policyId);
    if (activeIndex === undefined) {
      mergedDeletedById.set(policyId, policy);
      return;
    }
    const activeSource = activeSourceById.get(policyId) || (source === "first" ? "second" : "first");
    const activePolicy = activePoliciesAfterNaturalMerge[activeIndex];
    const activeFirst = activeSource === "first";
    deletionConflicts.push({
      kind: "active-deleted",
      allowKeepBoth: false,
      targetIndex: activeIndex,
      firstPolicy: activeFirst ? activePolicy : policy,
      secondPolicy: activeFirst ? policy : activePolicy,
      firstSource: activeFirst ? activeSource : source,
      secondSource: activeFirst ? source : activeSource,
      firstDeleted: !activeFirst,
      secondDeleted: activeFirst,
      deletedPolicy: policy,
    });
  });

  const selectedDeletedPolicies = [];
  for (let index = 0; index < deletionConflicts.length; index += 1) {
    const conflict = deletionConflicts[index];
    const decision = getPreferredDatabaseMergeDecision(conflict, preferredSource)
      || await showMergeConflict(conflict, index, deletionConflicts.length, databaseNames);
    if (decision?.cancelled) return null;
    if (decision?.keepBoth) {
      throw new Error("Nie można jednocześnie zachować aktywnej i usuniętej wersji tej samej polisy.");
    }
    const selectedDeleted = decision?.side === "first"
      ? conflict.firstDeleted
      : conflict.secondDeleted;
    if (selectedDeleted) {
      activePoliciesAfterNaturalMerge[conflict.targetIndex] = null;
      mergedDeletedById.set(String(conflict.deletedPolicy.id).trim(), conflict.deletedPolicy);
      selectedDeletedPolicies.push(conflict.deletedPolicy);
    }
    if (decision?.applyToAll) {
      preferredSource = decision.side === "second"
        ? conflict.secondSource
        : conflict.firstSource;
    }
  }

  const finalPolicies = clearDanglingMergedRenewalReferences(
    activePoliciesAfterNaturalMerge.filter(Boolean),
    [...discardedPolicies, ...selectedDeletedPolicies],
  );
  return {
    policies: ensureUniqueMergedPolicyIds(finalPolicies),
    deletedPolicies: [...mergedDeletedById.values()].sort(
      (first, second) => Number(second.deletedAt) - Number(first.deletedAt),
    ),
  };
}

function downloadMergedPoliciesFile(contents) {
  const blob = new Blob([contents], { type: "application/octet-stream" });
  const url = URL.createObjectURL(blob);
  const link = document.createElement("a");
  link.href = url;
  link.download = "polisy-polaczone.json";
  link.click();
  URL.revokeObjectURL(url);
}

function assertDatabaseMergeInputIntegrity(database, databaseName) {
  const activeIds = new Set();
  const deletedIds = new Set();
  const registerIds = (records, target, label) => {
    records.forEach((policy) => {
      const policyId = String(policy?.id || "").trim();
      if (!policyId || target.has(policyId)) {
        throw new Error(
          `Nie można połączyć bazy „${databaseName}”: ${label} zawiera brakujący albo powtórzony identyfikator polisy.`,
        );
      }
      target.add(policyId);
    });
  };
  registerIds(database.policies, activeIds, "lista aktywna");
  registerIds(database.deletedPolicies, deletedIds, "kosz");
  const overlappingId = [...activeIds].find((policyId) => deletedIds.has(policyId));
  if (overlappingId) {
    throw new Error(
      `Nie można połączyć bazy „${databaseName}”: ta sama polisa jest jednocześnie aktywna i znajduje się w koszu.`,
    );
  }
}

function mergeCalendarTaskCollections(firstTasks, secondTasks) {
  const mergedById = new Map();
  [...firstTasks, ...secondTasks].forEach((task) => {
    const existing = mergedById.get(task.id);
    if (!existing || Number(task.updatedAt) >= Number(existing.updatedAt)) {
      mergedById.set(task.id, task);
    }
  });
  return [...mergedById.values()].sort((first, second) => (
    first.date.localeCompare(second.date) || Number(first.createdAt) - Number(second.createdAt)
  ));
}

async function mergeSelectedDatabases() {
  const [firstFile] = elements.mergeFirstDataFile.files ?? [];
  const [secondFile] = elements.mergeSecondDataFile.files ?? [];
  if (!firstFile || !secondFile) {
    showToast("Wybierz pierwszą i drugą bazę danych");
    return;
  }

  let outputHandle = null;
  let mergeCompleted = false;
  elements.mergeDataFiles.disabled = true;
  elements.mergeDataFiles.textContent = "Łączenie...";

  try {
    const [firstDatabase, secondDatabase] = await Promise.all([
      readPoliciesFileText(firstFile).then(parsePoliciesFileDocument),
      readPoliciesFileText(secondFile).then(parsePoliciesFileDocument),
    ]);
    
    
    [[firstDatabase, firstFile], [secondDatabase, secondFile]].forEach(([database, file]) => {
      if (getDatabaseOwnershipStatus(database.accountId).status === "unknown") {
        throw new Error(
          `Baza „${file.name}” należy do konta o identyfikatorze ${database.accountId}, którego nie ma w Twojej agencji. `
          + "Dodaj to konto jako pracownika w zakładce Agencja albo wybierz inną bazę.",
        );
      }
      assertDatabaseMergeInputIntegrity(database, file.name || "wybrana baza");
    });
    const mergePlan = prepareDatabaseMerge(
      firstDatabase.policies,
      secondDatabase.policies,
      firstDatabase.deletedPolicies,
      secondDatabase.deletedPolicies,
    );
    const mergeResult = await resolveDatabaseMergeConflicts(mergePlan, {
      first: firstFile.name || "Pierwsza baza",
      second: secondFile.name || "Druga baza",
    });
    if (!mergeResult) {
      showToast("Łączenie baz zostało anulowane");
      return;
    }
    const { policies: mergedPolicies, deletedPolicies: mergedDeletedPolicies } = mergeResult;
    const mergedCalendarTasks = mergeCalendarTaskCollections(
      firstDatabase.calendarTasks,
      secondDatabase.calendarTasks,
    );
    const mergedEmployeePackageImports = normalizeEmployeePackageImportReceipts([
      ...firstDatabase.employeePackageImports,
      ...secondDatabase.employeePackageImports,
    ]);
    const mergedClientAccountLinks = normalizeClientAccountLinks([
      ...firstDatabase.clientAccountLinks,
      ...secondDatabase.clientAccountLinks,
    ]);

    if (typeof globalThis.showSaveFilePicker === "function") {
      outputHandle = await globalThis.showSaveFilePicker({
        suggestedName: "polisy-polaczone.json",
        types: [{
          description: "Połączona baza polis",
          accept: { "application/json": [".json"] },
        }],
      });
    }

    const contents = createDataFileContents(
      mergedPolicies,
      new Date().toISOString(),
      mergedDeletedPolicies,
      mergedCalendarTasks,
      mergedEmployeePackageImports,
      mergedClientAccountLinks,
    );
    const payload = await encodeProtectedPoliciesFileContents(contents);

    if (outputHandle) {
      const writable = await outputHandle.createWritable();
      await writable.write(payload);
      await writable.close();
    } else {
      downloadMergedPoliciesFile(payload);
    }

    elements.mergeFirstDataFile.value = "";
    elements.mergeSecondDataFile.value = "";
    mergeCompleted = true;
    showToast(`${pluralizePolicies(mergedPolicies.length)} zapisano w połączonej bazie`);
  } catch (error) {
    if (error?.name !== "AbortError") {
      showToast(error?.message || "Nie udało się połączyć baz danych");
    }
  } finally {
    elements.mergeDataFiles.textContent = "Połącz i zapisz JSON";
    if (mergeCompleted) {
      elements.mergeDataFiles.disabled = true;
    } else {
      updateMergeDatabasesButton();
    }
  }
}

function resetPolicyViewState() {
  editingPolicyId = null;
  editingPolicyDraft = null;
  expandedPolicyId = null;
  renewalsOnly = false;
  sortMode = null;
  sortDirection = "asc";
  insurerSortSelection = null;
  policyTypeSortIndex = -1;
  currentPage = 1;
  pageJumpOpen = false;
}

function loadPoliciesFromSnapshot(snapshot, needsVerification = false, options = {}) {
  policies = normalizeLoadedPolicies(snapshot.policies);
  deletedPolicies = normalizeDeletedPolicies(snapshot.deletedPolicies);
  calendarTasks = normalizeCalendarTasks(snapshot.calendarTasks);
  employeePackageImportReceipts = normalizeEmployeePackageImportReceipts(
    snapshot.employeePackageImports,
  );
  clientAccountLinks = normalizeClientAccountLinks(snapshot.clientAccountLinks);
  dataFileName = snapshot.fileName || rememberedDataFileHandle?.name || "polisy-dane.json";
  dataFileHandle = null;
  dataFileRevision = {
    fileName: dataFileName,
    lastModified: Number(snapshot.sourceLastModified) || 0,
    size: Number(snapshot.sourceSize) || 0,
    updatedAt: typeof snapshot.updatedAt === "string" ? snapshot.updatedAt : "",
    contentFingerprint: Number(snapshot.version) >= 4 && snapshot.contentFingerprint
      ? snapshot.contentFingerprint
      : getPoliciesFingerprint(
        policies,
        deletedPolicies,
        calendarTasks,
        employeePackageImportReceipts,
        clientAccountLinks,
      ),
  };
  initialDataFileReady = true;
  hasLegacyPolicies = false;
  dataFileNeedsVerification = needsVerification;
  dataFileConflictBlocked = false;
  hasUnsavedPolicyChanges = false;
  resetPolicyViewState();
  render();
  updateDeletedRecordsSettingsSummary();
  if (needsVerification && !options.quietVerification) {
    setDataIntegrityNotice(
      "warning",
      "Baza wczytana z lokalnej kopii",
      "Przed pierwszym zapisem porównaj ją z zapamiętanym plikiem na dysku.",
      "Sprawdź plik",
    );
  } else {
    clearDataIntegrityNotice();
  }
  updateDataFileStatus();
}

async function loadPoliciesFromFile(file, handle = null, options = {}) {
  const inspection = options.inspection || await inspectPoliciesFile(file);
  
  
  if (!options.trustedSource) assertDatabaseCanBeOpened(inspection.documentData);
  const loadedPolicies = inspection.documentData.policies;
  const loadedDeletedPolicies = inspection.documentData.deletedPolicies;
  const loadedCalendarTasks = inspection.documentData.calendarTasks;
  const loadedEmployeePackageImports = inspection.documentData.employeePackageImports;
  const loadedClientAccountLinks = inspection.documentData.clientAccountLinks;
  const writableHandle = handle && (options.permissionGranted || await requestWritePermission(handle)) ? handle : null;
  if (handle && !writableHandle) throw new Error("Brak zgody na zapis do wybranego pliku.");

  let nextPolicies = loadedPolicies;
  let migratedLegacyRecords = false;
  if (hasLegacyPolicies && !options.skipLegacy) {
    const fileIds = new Set(loadedPolicies.map((policy) => policy.id));
    const legacyOnlyPolicies = policies.filter((policy) => !fileIds.has(policy.id));
    if (legacyOnlyPolicies.length > 0) {
      const includeLegacy = typeof globalThis.confirm === "function" && globalThis.confirm(
        `Znaleziono ${pluralizePolicies(legacyOnlyPolicies.length)} ze starej pamięci przeglądarki, których nie ma w otwieranym pliku.\n\nKliknij OK, aby dodać tylko te brakujące rekordy. Kliknij Anuluj, aby użyć wyłącznie zawartości pliku. Rekordy o tych samych identyfikatorach zawsze pozostaną w wersji z pliku.`,
      );
      if (includeLegacy) {
        nextPolicies = [...loadedPolicies, ...legacyOnlyPolicies];
        migratedLegacyRecords = true;
      }
    }
  }

  policies = nextPolicies;
  deletedPolicies = loadedDeletedPolicies;
  calendarTasks = loadedCalendarTasks;
  employeePackageImportReceipts = loadedEmployeePackageImports;
  clientAccountLinks = loadedClientAccountLinks;
  dataFileName = inspection.file.name || "polisy-dane.json";
  initialDataFileReady = true;
  if (!handle && rememberedDataFileHandle) {
    await forgetRememberedDataFileHandle();
  }
  dataFileHandle = writableHandle;
  dataFileRevision = inspection.revision;
  dataFileNeedsVerification = false;
  dataFileConflictBlocked = false;
  hasUnsavedPolicyChanges = migratedLegacyRecords;
  resetPolicyViewState();
  if (dataFileHandle) {
    rememberedDataFileHandle = dataFileHandle;
    await rememberDataFileHandle(dataFileHandle);
  }
  clearLegacyPolicies();
  if (migratedLegacyRecords && dataFileHandle) {
    await writePoliciesToHandle(dataFileHandle, { skipFreshnessCheck: true });
  } else {
    await rememberDataFileSnapshot();
    if (migratedLegacyRecords) {
      markPoliciesDirty("Brakujące rekordy ze starej pamięci zostały dodane, ale wymagają zapisania do nowego pliku.");
    } else {
      markPoliciesSaved();
    }
  }
  hasLegacyPolicies = false;
  render();
  updateDeletedRecordsSettingsSummary();
  updateDataFileStatus();
  if (options.showToast !== false) showToast(`${pluralizePolicies(policies.length)} wczytano z pliku`);
}

async function restoreRememberedDataFile() {
  const handle = await getRememberedDataFileHandle();
  const snapshot = await getRememberedFileSnapshot(DATA_FILE_SNAPSHOT_KEY);
  if (handle) {
    rememberedDataFileHandle = handle;
    dataFileName = handle.name || "polisy-dane.json";
    updateDataFileStatus();

    try {
      const permission = handle.queryPermission
        ? await handle.queryPermission({ mode: "readwrite" })
        : "granted";
      if (permission === "granted") {
        const inspection = await inspectPoliciesFile(await handle.getFile());
        const snapshotPolicies = Array.isArray(snapshot?.policies)
          ? normalizeLoadedPolicies(snapshot.policies)
          : null;
        const snapshotDeletedPolicies = normalizeDeletedPolicies(snapshot?.deletedPolicies);
        const snapshotCalendarTasks = normalizeCalendarTasks(snapshot?.calendarTasks);
        if (snapshotPolicies && !policiesMatchRevision(
          snapshotPolicies,
          inspection.revision,
          snapshotDeletedPolicies,
          snapshotCalendarTasks,
        )) {
          const useDiskVersion = typeof globalThis.confirm === "function" && globalThis.confirm(
            "Zapamiętany plik różni się od lokalnej kopii z poprzedniej sesji.\n\nKliknij OK, aby wczytać plik z dysku. Kliknij Anuluj, aby zachować lokalną kopię i zapisać ją później jako osobny plik.",
          );
          if (!useDiskVersion) {
            loadPoliciesFromSnapshot(snapshot, true);
            dataFileRevision = inspection.revision;
            dataFileConflictBlocked = true;
            hasUnsavedPolicyChanges = true;
            setDataIntegrityNotice(
              "warning",
              "Zachowano lokalną kopię bazy",
              "Plik na dysku ma inną zawartość i nie zostanie nadpisany. Zapisz tę kopię jako nową bazę.",
              "Zapisz jako nową bazę",
            );
            return true;
          }
        }
        await loadPoliciesFromFile(inspection.file, handle, {
          inspection,
          permissionGranted: true,
          showToast: false,
          trustedSource: true,
        });
        return true;
      }
    } catch (error) {
      dataFileHandle = null;
      dataFileNeedsVerification = true;
      if (!Array.isArray(snapshot?.policies)) {
        setDataIntegrityNotice(
          "error",
          "Nie udało się odczytać zapamiętanego pliku",
          error?.message || "Otwórz plik ponownie.",
          "Wskaż plik",
        );
      }
    }
  }

  if (!Array.isArray(snapshot?.policies)) {
    updateDataFileStatus();
    return false;
  }
  loadPoliciesFromSnapshot(snapshot, Boolean(handle), { quietVerification: Boolean(handle) });
  return true;
}

async function openDataFile() {
  if (hasUnsavedPolicyChanges) {
    const confirmed = typeof globalThis.confirm === "function" && globalThis.confirm(
      "W pamięci są niezapisane zmiany. Otwarcie innej bazy je zastąpi.\n\nKliknij OK, aby kontynuować, albo Anuluj i najpierw zapisz bieżącą bazę jako nowy plik.",
    );
    if (!confirmed) return;
  }
  if (typeof globalThis.showOpenFilePicker !== "function") {
    elements.dataFileInput.click();
    return;
  }

  try {
    const [handle] = await showSystemPicker("showOpenFilePicker", {
      id: "baza-polis-dane",
      startIn: getPickerStartLocation(dataFileHandle, rememberedDataFileHandle),
      multiple: false,
      types: [{
        description: "Plik danych polis",
        accept: { "application/json": [".json"] },
      }],
    });
    await loadPoliciesFromFile(await handle.getFile(), handle);
  } catch (error) {
    if (error?.name !== "AbortError") showToast(error?.message || "Nie udało się otworzyć pliku danych");
  }
}

async function showSystemPicker(pickerName, pickerOptions) {
  try {
    return await globalThis[pickerName](pickerOptions);
  } catch (error) {
    if (error?.name !== "TypeError" || !pickerOptions.startIn) throw error;
    const { startIn, ...fallbackOptions } = pickerOptions;
    return globalThis[pickerName](fallbackOptions);
  }
}

function getPickerStartLocation(...preferredHandles) {
  for (const handle of preferredHandles) {
    if (handle) return handle;
  }
  return appDirectoryHandle || rememberedAppDirectoryHandle || "desktop";
}

function isPoliciesFileDocument(parsed) {
  return Array.isArray(parsed) || Array.isArray(parsed?.policies);
}

function isSettingsFileDocument(parsed, fileName = "") {
  if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return false;
  if (isPoliciesFileDocument(parsed)) return false;
  if (String(fileName).toLocaleLowerCase("pl") === DEFAULT_SETTINGS_FILE_NAME.toLocaleLowerCase("pl")) return true;
  if (parsed.settings && typeof parsed.settings === "object" && !Array.isArray(parsed.settings)) return true;
  const settings = parsed.settings && typeof parsed.settings === "object" ? parsed.settings : parsed;
  return [
    "theme",
    "fontSize",
    "showAppearanceDock",
    "recordsPerPage",
    "showStartDateInput",
    "showUsageGuide",
    "databaseName",
    "agencyName",
    "logoDataUrl",
    "insurers",
    "radio",
    "idleRpg",
  ]
    .some((key) => key in settings);
}

async function findSetupFilesInDirectory(directoryHandle) {
  const dataCandidates = [];
  const settingsCandidates = [];
  const unreadableJsonNames = [];
  for await (const entry of directoryHandle.values()) {
    if (entry.kind !== "file" || !/\.json$/i.test(entry.name)) continue;
    try {
      const file = await entry.getFile();
      if (file.size > 50 * 1024 * 1024) {
        unreadableJsonNames.push(entry.name);
        continue;
      }
      const parsed = JSON.parse(await readPoliciesFileText(file));
      if (isPoliciesFileDocument(parsed)) dataCandidates.push({ handle: entry, file });
      else if (isSettingsFileDocument(parsed, entry.name)) settingsCandidates.push({ handle: entry, file });
    } catch {
      unreadableJsonNames.push(entry.name);
    }
  }

  const pickCandidate = (candidates, preferredNames, deprioritizePattern = null) => {
    for (const preferredName of preferredNames) {
      if (!preferredName) continue;
      const match = candidates.find((candidate) => candidate.file.name === preferredName);
      if (match) return { pick: match, byName: true };
    }
    if (!candidates.length) return { pick: null, byName: false };
    const sorted = [...candidates].sort((a, b) => b.file.lastModified - a.file.lastModified);
    if (deprioritizePattern) {
      const primary = sorted.find((candidate) => !deprioritizePattern.test(candidate.file.name));
      if (primary) return { pick: primary, byName: false };
    }
    return { pick: sorted[0], byName: false };
  };

  const dataPick = pickCandidate(
    dataCandidates,
    [rememberedDataFileHandle?.name, dataFileName],
    /^(kopiazapasowa_|polisy-polaczone)/i,
  );
  const settingsPick = pickCandidate(
    settingsCandidates,
    [rememberedSettingsFileHandle?.name, settingsFileName, DEFAULT_SETTINGS_FILE_NAME],
  );

  return {
    dataFile: dataPick.pick,
    dataFileMatchedByName: dataPick.byName,
    settingsFile: settingsPick.pick,
    dataCandidateCount: dataCandidates.length,
    unreadableJsonNames,
  };
}

async function createFileInDirectory(directoryHandle, fileName, contents) {
  let alreadyExists = false;
  let probeError = null;
  try {
    await directoryHandle.getFileHandle(fileName);
    alreadyExists = true;
  } catch (error) {
    if (error?.name !== "NotFoundError") probeError = error;
  }
  if (alreadyExists) {
    throw new Error(`Plik „${fileName}” już istnieje w tym folderze i nie został nadpisany. Wskaż go przyciskiem „Wybierz plik”.`);
  }
  if (probeError) {
    throw new Error(`Nie udało się sprawdzić folderu przed utworzeniem pliku „${fileName}” (${probeError?.message || probeError?.name || "nieznany błąd"}). Nic nie zostało zapisane.`);
  }
  const handle = await directoryHandle.getFileHandle(fileName, { create: true });
  const writable = await handle.createWritable();
  await writable.write(contents);
  await writable.close();
  return { handle, file: await handle.getFile() };
}

function scheduleAppDirectoryAttachmentReconcile(options = {}) {
  if (options.deferAttachmentReconcile === true) return false;
  void reconcileAttachmentsFromFolder({ force: true });
  return true;
}

async function connectAppDirectory(directoryHandle, options = {}) {
  if (!(await requestWritePermission(directoryHandle))) {
    if (!options.silent) showToast("Brak zgody na dostęp do wybranego folderu", "error");
    return false;
  }

  const found = await findSetupFilesInDirectory(directoryHandle);
  const snapshot = await getRememberedFileSnapshot(DATA_FILE_SNAPSHOT_KEY);
  const snapshotPolicies = Array.isArray(snapshot?.policies)
    ? normalizeLoadedPolicies(snapshot.policies)
    : null;
  const snapshotDeletedPolicies = normalizeDeletedPolicies(snapshot?.deletedPolicies);
  const snapshotCalendarTasks = normalizeCalendarTasks(snapshot?.calendarTasks);
  const snapshotEmployeePackageImports = normalizeEmployeePackageImportReceipts(
    snapshot?.employeePackageImports,
  );
  const snapshotClientAccountLinks = normalizeClientAccountLinks(snapshot?.clientAccountLinks);

  let dataPick = found.dataFile;
  if (options.silent && dataPick) {
    const expectedSilentName = rememberedDataFileHandle?.name || dataFileName || "";
    const silentNameOk = expectedSilentName
      ? dataPick.file.name === expectedSilentName
      : found.dataFileMatchedByName;
    if (!silentNameOk) return false;
  }
  let createdDataFile = false;
  if (!dataPick) {
    if (options.silent) return false;
    if (found.unreadableJsonNames.length) {
      throw new Error(`Nie udało się odczytać pliku „${found.unreadableJsonNames[0]}” w tym folderze. Nie utworzono nowej bazy, aby niczego nie nadpisać. Jeśli to baza polis - napraw go albo wskaż bazę przyciskiem „Wybierz plik”; jeśli to zbędny plik - usuń go z folderu i spróbuj ponownie.`);
    }
    const seedPolicies = !policies.length && snapshotPolicies?.length ? snapshotPolicies : policies;
    const seedDeletedPolicies = seedPolicies === snapshotPolicies ? snapshotDeletedPolicies : deletedPolicies;
    const seedCalendarTasks = seedPolicies === snapshotPolicies ? snapshotCalendarTasks : calendarTasks;
    const seedEmployeePackageImports = seedPolicies === snapshotPolicies
      ? snapshotEmployeePackageImports
      : employeePackageImportReceipts;
    const seedClientAccountLinks = seedPolicies === snapshotPolicies
      ? snapshotClientAccountLinks
      : clientAccountLinks;
    dataPick = await createFileInDirectory(
      directoryHandle,
      "polisy-dane.json",
      await encodePoliciesFileContents(createDataFileContents(
        seedPolicies,
        new Date().toISOString(),
        seedDeletedPolicies,
        seedCalendarTasks,
        seedEmployeePackageImports,
        seedClientAccountLinks,
      )),
    );
    createdDataFile = true;
  }
  let settingsPick = found.settingsFile;
  let createdSettingsFile = false;
  if (!settingsPick) {
    if (options.silent) return false;
    if (found.unreadableJsonNames.some((name) => name.toLocaleLowerCase("pl") === DEFAULT_SETTINGS_FILE_NAME)) {
      throw new Error(`Nie udało się odczytać pliku „${DEFAULT_SETTINGS_FILE_NAME}” w tym folderze. Wskaż plik ustawień przyciskiem „Wybierz plik”.`);
    }
    settingsPick = await createFileInDirectory(directoryHandle, DEFAULT_SETTINGS_FILE_NAME, createSettingsFileContents(uiSettings));
    createdSettingsFile = true;
  }

  const inspection = await inspectPoliciesFile(dataPick.file);
  let keptLocalCopy = false;
  const snapshotGuardsThisFile = !createdDataFile
    && Boolean(snapshotPolicies)
    && snapshot?.fileName === dataPick.file.name;
  if (snapshotGuardsThisFile && !policiesMatchRevision(
    snapshotPolicies,
    inspection.revision,
    snapshotDeletedPolicies,
    snapshotCalendarTasks,
    snapshotEmployeePackageImports,
    snapshotClientAccountLinks,
  )) {
    const useDiskVersion = typeof globalThis.confirm === "function" && globalThis.confirm(
      "Plik bazy w tym folderze różni się od lokalnej kopii z poprzedniej sesji.\n\nKliknij OK, aby wczytać plik z dysku. Kliknij Anuluj, aby zachować lokalną kopię i zapisać ją później jako osobny plik.",
    );
    if (!useDiskVersion) {
      rememberedDataFileHandle = dataPick.handle;
      await rememberDataFileHandle(dataPick.handle);
      loadPoliciesFromSnapshot(snapshot, true);
      dataFileRevision = inspection.revision;
      dataFileConflictBlocked = true;
      hasUnsavedPolicyChanges = true;
      setDataIntegrityNotice(
        "warning",
        "Zachowano lokalną kopię bazy",
        "Plik na dysku ma inną zawartość i nie zostanie nadpisany. Zapisz tę kopię jako nową bazę.",
        "Zapisz jako nową bazę",
      );
      keptLocalCopy = true;
    }
  }
  if (!keptLocalCopy) {
    await loadPoliciesFromFile(inspection.file, dataPick.handle, {
      inspection,
      permissionGranted: true,
      showToast: false,
    });
  }

  await loadSettingsFromFile(settingsPick.file, settingsPick.handle, {
    permissionGranted: true,
    showToast: false,
  });

  await rememberAppDirectoryHandle(directoryHandle);
  try {
    const existingAttachmentsBase = attachmentsBaseDirectoryHandle
      || rememberedAttachmentsBaseDirectoryHandle
      || await getRememberedAttachmentsDirectoryHandle();
    if (!existingAttachmentsBase) {
      await resolveAttachmentsRootDirectory(directoryHandle, { create: true });
      attachmentsBaseDirectoryHandle = directoryHandle;
      rememberedAttachmentsBaseDirectoryHandle = directoryHandle;
      await rememberAttachmentsDirectoryHandle(directoryHandle);
    }
  } catch {
  }

  updateInitialSetupState();
  if (initialDataFileReady && initialSettingsFileReady && elements.welcomeDialog.open) {
    elements.welcomeDialog.close();
  }
  if (!options.silent) {
    const dataSummary = createdDataFile
      ? "utworzono nową bazę polis"
      : `wczytano bazę „${dataPick.file.name}”`;
    const settingsSummary = createdSettingsFile
      ? "utworzono plik ustawień"
      : "wczytano ustawienia";
    showToast(`Folder połączony: ${dataSummary}, ${settingsSummary}`);
  }
  if (!createdDataFile && found.dataCandidateCount > 1 && !found.dataFileMatchedByName) {
    showToast(`W folderze jest kilka plików bazy - wybrano „${dataPick.file.name}”. Inny wskażesz przyciskiem „Wybierz plik”.`, "warning");
  }
  scheduleAppDirectoryAttachmentReconcile(options);
  return true;
}

async function chooseAppDirectory() {
  if (quickSetupInProgress) return;
  quickSetupInProgress = true;
  welcomeSetupError = "";
  elements.welcomeQuickSetup.disabled = true;
  try {
    if (typeof globalThis.showDirectoryPicker !== "function") {
      setWelcomeSetupError("Ta przeglądarka nie obsługuje szybkiej konfiguracji. Wskaż pliki poniżej.");
      return;
    }

    const remembered = rememberedAppDirectoryHandle || await getRememberedAppDirectoryHandle();
    if (remembered && !appDirectoryHandle) {
      try {
        if (await connectAppDirectory(remembered)) return;
        setWelcomeSetupError("Brak zgody na zapamiętany folder - możesz wskazać inny.");
      } catch (error) {
        setWelcomeSetupError(error?.message || "Nie udało się połączyć z zapamiętanym folderem - wskaż folder ponownie.");
      }
    }

    let handle = null;
    try {
      handle = await showSystemPicker("showDirectoryPicker", {
        id: "baza-polis-folder",
        mode: "readwrite",
        startIn: "desktop",
      });
    } catch (error) {
      if (error?.name !== "AbortError") {
        setWelcomeSetupError(error?.message || "Nie udało się otworzyć wyboru folderu");
      }
      return;
    }

    try {
      await connectAppDirectory(handle);
    } catch (error) {
      setWelcomeSetupError(error?.message || "Nie udało się skonfigurować folderu aplikacji");
    }
  } finally {
    quickSetupInProgress = false;
    elements.welcomeQuickSetup.disabled = false;
  }
}

async function restoreRememberedAppDirectory(options = {}) {
  const handle = await getRememberedAppDirectoryHandle();
  if (!handle) return false;
  try {
    const permission = handle.queryPermission
      ? await handle.queryPermission({ mode: "readwrite" })
      : "granted";
    if (permission !== "granted") return false;
    await getRememberedDataFileHandle();
    await getRememberedSettingsFileHandle();
    return await connectAppDirectory(handle, {
      silent: true,
      deferAttachmentReconcile: options.deferAttachmentReconcile === true,
    });
  } catch {
    return false;
  }
}

async function resolveDataIntegrityIssue() {
  const actionLabel = dataIntegrityNotice?.actionLabel || "";
  if (actionLabel === "Zamknij") {
    clearDataIntegrityNotice();
    return;
  }
  if (dataFileConflictBlocked || actionLabel.includes("Zapisz jako")) {
    await saveDataFileAs();
    return;
  }
  if (actionLabel === "Wskaż plik") {
    await openDataFile();
    return;
  }
  if (!dataFileHandle && rememberedDataFileHandle) {
    const connected = await connectRememberedDataFile();
    if (!connected) return;
  }
  if (hasUnsavedPolicyChanges) {
    await persistPolicies();
    return;
  }
  if (!dataFileHandle) await openDataFile();
  else clearDataIntegrityNotice();
}

let fontSizeAdjustmentApplied = false;

function applyFontSize(fontSize) {
  const normalizedSize = normalizeUiFontSize(fontSize);
  const sizeIncrease = normalizedSize === "large" ? 4 : normalizedSize === "medium" ? 2 : 0;
  document.documentElement.dataset.fontSize = normalizedSize;
  updateAppearanceDockControls(undefined, normalizedSize);
  if (!document.querySelectorAll || !globalThis.getComputedStyle) return;
  
  
  if (sizeIncrease === 0 && !fontSizeAdjustmentApplied) return;

  const textElements = [...document.querySelectorAll("body *")].filter((element) => {
    if (!element?.style) return false;
    if (element.closest?.("#appearanceDock")) return false;
    const tagName = String(element.tagName ?? "").toLocaleLowerCase();
    if (["input", "textarea", "select", "button", "option"].includes(tagName)) return true;
    return [...(element.childNodes ?? [])].some((node) => node.nodeType === 3 && String(node.textContent ?? "").trim());
  });

  const elementsWithoutBase = textElements.filter((element) => !baseFontStyles.has(element));
  const measuredFontSizes = elementsWithoutBase.map((element) => {
    const pixels = Number.parseFloat(globalThis.getComputedStyle(element).fontSize);
    return { element, inline: element.style.fontSize, pixels };
  });
  measuredFontSizes.forEach(({ element, inline, pixels }) => {
    if (Number.isFinite(pixels)) baseFontStyles.set(element, { inline, pixels });
  });

  textElements.forEach((element) => {
    const base = baseFontStyles.get(element);
    if (!base) return;
    element.style.fontSize = sizeIncrease > 0 ? `${base.pixels + sizeIncrease}px` : base.inline;
  });
  fontSizeAdjustmentApplied = sizeIncrease > 0;
}

function applyTheme(theme) {
  const isDark = theme === "dark";
  document.documentElement.dataset.theme = isDark ? "dark" : "light";
  if (!uiSettings.logoDataUrl && elements.brandLogo) {
    elements.brandLogo.src = isDark ? DEFAULT_LOGO_LIGHT_SRC : DEFAULT_LOGO_SRC;
  }
  updateThemeChoices(isDark ? "dark" : "light");
  updateAppearanceDockControls(isDark ? "dark" : "light");
}

function updateAddPolicyButtonState() {
  elements.addPolicyButton.disabled = addPolicySubmitting
    || !elements.clientNameInput.value.trim();
}

function updateAddFormStartDateFromEnd() {
  if (document.documentElement.dataset.startDateInput !== "visible") return;
  if (elements.startDateFormField.dataset.manuallyEdited === "true") return;
  const startDate = isTravelPolicySelected()
    ? calculateTravelStartDate(elements.validUntilInput.value)
    : calculateStartDate(elements.validUntilInput.value);
  elements.validFromInput.value = formatDateForInput(startDate);
}

function isTravelPolicySelected() {
  return normalize(elements.registrationInput.value) === normalize("Podróż");
}

function shouldShowStartDateForPolicyType(value) {
  const policyType = normalize(value);
  return policyType === normalize("Podróż") || policyType === normalize("Życie");
}

function refreshAddFormStartDateVisibility() {
  const isVisible = appliedStartDateInputSetting
    || shouldShowStartDateForPolicyType(elements.registrationInput.value);
  document.documentElement.dataset.startDateInput = isVisible ? "visible" : "automatic";
  elements.startDateFormField.classList.toggle("form-date-field--hidden", !isVisible);
  elements.validFromInput.disabled = !isVisible;

  if (!isVisible) {
    elements.startDateFormField.dataset.manuallyEdited = "false";
    elements.validFromInput.value = "";
    return;
  }

  updateAddFormStartDateFromEnd();
}

function applyStartDateInputSetting(showStartDateInput) {
  appliedStartDateInputSetting = showStartDateInput === true;
  refreshAddFormStartDateVisibility();
}

function applyAppearanceDockSetting(showAppearanceDock) {
  elements.appearanceDock.hidden = showAppearanceDock === false;
  setAppearanceDockCollapsed(appearanceDockCollapsed, { save: false });
  updateAppearanceDockControls();
}

function applyUsageGuideSetting(showUsageGuide) {
  const isVisible = showUsageGuide !== false;
  elements.usageGuideRow.hidden = !isVisible;
  if (!isVisible && usageGuideActive) hideUsageGuide();
}

async function persistRadioSettings(event) {
  const previousSettings = uiSettings;
  const nextSettings = normalizeUiSettings({
    ...uiSettings,
    radio: event?.detail?.radio || uiSettings.radio,
  });
  uiSettings = nextSettings;
  if (await persistUiSettings(nextSettings)) return;
  uiSettings = previousSettings;
  globalThis.SekagentRadio?.configure(previousSettings.radio);
  if (elements.settingsDialog.open) {
    globalThis.SekagentRadio?.syncSettingsForm(previousSettings.radio);
  }
}

function setQuickAppearanceBusy(isBusy) {
  quickAppearanceSaving = isBusy;
  elements.appearanceDock.setAttribute("aria-busy", String(isBusy));
  elements.closeAppearanceDock.disabled = isBusy;
  elements.appearanceThemeToggle.disabled = isBusy;
  elements.appearanceFontSizeChoices.forEach((button) => {
    button.disabled = isBusy;
  });
}

async function updateQuickAppearance(changes) {
  if (quickAppearanceSaving) return;
  const previousSettings = uiSettings;
  const nextSettings = normalizeUiSettings({ ...uiSettings, ...changes });
  uiSettings = nextSettings;
  pendingSettingsTheme = nextSettings.theme;
  pendingSettingsFontSize = nextSettings.fontSize;
  pendingShowAppearanceDock = nextSettings.showAppearanceDock;
  applyTheme(nextSettings.theme);
  applyFontSize(nextSettings.fontSize);
  applyAppearanceDockSetting(nextSettings.showAppearanceDock);
  setQuickAppearanceBusy(true);

  if (!(await persistUiSettings(nextSettings))) {
    uiSettings = previousSettings;
    pendingSettingsTheme = previousSettings.theme;
    pendingSettingsFontSize = previousSettings.fontSize;
    pendingShowAppearanceDock = previousSettings.showAppearanceDock;
    applyTheme(previousSettings.theme);
    applyFontSize(previousSettings.fontSize);
    applyAppearanceDockSetting(previousSettings.showAppearanceDock);
  }

  if (elements.settingsDialog.open) {
    elements.showAppearanceDockSetting.checked = uiSettings.showAppearanceDock !== false;
    updateThemeChoices(uiSettings.theme);
    updateFontSizeChoices(uiSettings.fontSize);
  }
  setQuickAppearanceBusy(false);
}

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





const SEARCH_ENTRY_CACHE_LIMIT = 80000;
const searchEntryCache = new Map();
function getSearchEntry(rawValue) {
  const key = String(rawValue ?? "");
  const cached = searchEntryCache.get(key);
  if (cached) return cached;
  if (searchEntryCache.size >= SEARCH_ENTRY_CACHE_LIMIT) searchEntryCache.clear();
  const value = normalize(key);
  const entry = { value, compactValue: value.replace(/[^a-z0-9]/g, "") };
  searchEntryCache.set(key, entry);
  return entry;
}

function getEntryOrganizerApi() {
  return globalThis.PolicyRecordOrganizer;
}

function getEntryOrganizerCandidates() {
  const organizer = getEntryOrganizerApi();
  return organizer?.findReviewCandidates ? organizer.findReviewCandidates(policies) : [];
}

function getEntryOrganizerMissingRecords() {
  const organizer = getEntryOrganizerApi();
  return organizer?.findMissingIdentityRecords ? organizer.findMissingIdentityRecords(policies) : [];
}

function getEntryOrganizerNameChanges() {
  const organizer = getEntryOrganizerApi();
  return organizer?.findNameUnificationChanges ? organizer.findNameUnificationChanges(policies) : [];
}

function getEntryOrganizerFirstRegistrationDateChanges() {
  const organizer = getEntryOrganizerApi();
  return organizer?.findFirstRegistrationDateChanges
    ? organizer.findFirstRegistrationDateChanges(policies)
    : [];
}

function isWartaTravelPortfolioLabel(value) {
  return /\bWARTA\s+TRAVEL\b/i.test(String(value ?? "").trim());
}

function getKnownWartaTravelFieldValues(existingPolicy, sourcePolicy = existingPolicy) {
  const hasTravelSignal = isWartaTravelPortfolioLabel(existingPolicy?.riskSummary)
    || isWartaTravelPortfolioLabel(sourcePolicy?.riskSummary);
  if (!hasTravelSignal) return {};
  const values = {};
  const registration = normalize(existingPolicy?.registration);
  if (registration !== normalize("Podróż")) values.registration = "Podróż";
  if (isWartaTravelPortfolioLabel(existingPolicy?.riskSummary)) {
    const currentRisk = String(existingPolicy.riskSummary).trim();
    const normalizedRisk = currentRisk.replace(/^eAgent\s+/i, "");
    if (currentRisk !== normalizedRisk) values.riskSummary = normalizedRisk;
  } else if (isImportedPolicyFieldMissing(existingPolicy?.riskSummary)) {
    values.riskSummary = "WARTA TRAVEL";
  }
  return values;
}

function applyKnownWartaTravelFields(existingPolicy, sourcePolicy = existingPolicy) {
  const values = getKnownWartaTravelFieldValues(existingPolicy, sourcePolicy);
  return applyImportedPolicyFieldSync(existingPolicy, values);
}

function getEntryOrganizerKnownClassificationChanges() {
  return policies
    .map((policy) => ({
      targetId: String(policy?.id),
      fields: getKnownWartaTravelFieldValues(policy),
    }))
    .filter((change) => Object.keys(change.fields).length > 0);
}





function getEntryOrganizerErgoInsurerChanges() {
  const changes = [];
  for (const policy of policies) {
    const insurer = String(policy?.insurer ?? "").trim();
    if (insurer !== "Hestia" && insurer !== "MTU") continue;
    const digits = String(policy?.policyNumber ?? "").replace(/\D/g, "");
    const expected = /^911\d{7,}$/.test(digits)
      ? "MTU"
      : (/^(?:909|922)\d{7,}$/.test(digits) ? "Hestia" : "");
    if (expected && expected !== insurer) {
      changes.push({ targetId: String(policy?.id), insurer: expected });
    }
  }
  return changes;
}

function formatEntryOrganizerRecordCount(count) {
  const lastDigit = count % 10;
  const lastTwoDigits = count % 100;
  const label = count === 1
    ? "rekord"
    : lastDigit >= 2 && lastDigit <= 4 && !(lastTwoDigits >= 12 && lastTwoDigits <= 14)
      ? "rekordy"
      : "rekordów";
  return `${count} ${label}`;
}

function hasEntryOrganizerApi() {
  const organizer = getEntryOrganizerApi();
  return Boolean(
    organizer?.findReviewCandidates
    && organizer?.findMissingIdentityRecords
    && organizer?.findNameUnificationChanges
    && organizer?.findFirstRegistrationDateChanges,
  );
}

function resetEntryOrganizerSettingsSummary() {
  if (!hasEntryOrganizerApi()) {
    elements.entryOrganizerSummary.textContent = "Brakuje modułu porządkowania wpisów.";
    elements.startEntryOrganizer.disabled = true;
    return;
  }
  elements.entryOrganizerSummary.textContent = "Kliknij „Porządkuj polisy”, aby sprawdzić bazę i uporządkować wpisy.";
  elements.startEntryOrganizer.disabled = false;
}

function updateEntryOrganizerSettingsSummary() {
  if (!hasEntryOrganizerApi()) {
    elements.entryOrganizerSummary.textContent = "Brakuje modułu porządkowania wpisów.";
    elements.startEntryOrganizer.disabled = true;
    return;
  }
  const missingCount = getEntryOrganizerMissingRecords().length;
  const nameChangeCount = getEntryOrganizerNameChanges().length;
  const classificationChangeCount = getEntryOrganizerKnownClassificationChanges().length;
  const ergoInsurerChangeCount = getEntryOrganizerErgoInsurerChanges().length;
  const firstRegistrationDateChangeCount = getEntryOrganizerFirstRegistrationDateChanges().length;
  const attachmentDataCandidateCount = getEntryOrganizerAttachmentDataCandidates().length;
  const renewalChangeCount = getRenewalVerificationChangeCount();
  const splitProposalCount = getClientAccountSplitProposals().length;
  const linkProposalCount = getClientAccountLinkProposals().length;
  const nipCandidateCount = getEntryOrganizerNipFillCandidates().length;
  const candidates = getEntryOrganizerCandidates();
  const targetCount = new Set(candidates.map((candidate) => candidate.targetId)).size;
  const renewalMessage = renewalChangeCount > 0
    ? ` Wznowienia do aktualizacji: ${formatEntryOrganizerRecordCount(renewalChangeCount)}.`
    : "";
  const splitMessage = splitProposalCount > 0
    ? ` Sklejone konta osoby i firmy do rozdzielenia: ${splitProposalCount}.`
    : "";
  const linkMessage = linkProposalCount > 0
    ? ` Powiązania osoby z firmą do potwierdzenia: ${linkProposalCount}.`
    : "";
  const nipMessage = nipCandidateCount > 0
    ? ` Firmy bez NIP-u do sprawdzenia w rejestrze: ${nipCandidateCount}.`
    : "";
  const firstRegistrationDateMessage = firstRegistrationDateChangeCount > 0
    ? ` Daty pierwszej rejestracji do uzupełnienia: ${formatEntryOrganizerRecordCount(firstRegistrationDateChangeCount)}.`
    : "";
  const classificationMessage = classificationChangeCount > 0
    ? ` Rodzaje polis do poprawienia: ${formatEntryOrganizerRecordCount(classificationChangeCount)}.`
    : "";
  const ergoInsurerMessage = ergoInsurerChangeCount > 0
    ? ` Towarzystwa (MTU/Hestia) do poprawienia: ${formatEntryOrganizerRecordCount(ergoInsurerChangeCount)}.`
    : "";
  const attachmentMessage = attachmentDataCandidateCount > 0
    ? ` Pliki PDF do ponownego odczytania: ${formatEntryOrganizerRecordCount(attachmentDataCandidateCount)}.`
    : "";
  elements.startEntryOrganizer.disabled = missingCount === 0
    && nameChangeCount === 0
    && classificationChangeCount === 0
    && ergoInsurerChangeCount === 0
    && firstRegistrationDateChangeCount === 0
    && attachmentDataCandidateCount === 0
    && renewalChangeCount === 0
    && splitProposalCount === 0
    && linkProposalCount === 0
    && nipCandidateCount === 0;
  if (
    missingCount === 0
    && nameChangeCount === 0
    && classificationChangeCount === 0
    && ergoInsurerChangeCount === 0
    && firstRegistrationDateChangeCount === 0
    && attachmentDataCandidateCount === 0
    && renewalChangeCount === 0
    && splitProposalCount === 0
    && linkProposalCount === 0
    && nipCandidateCount === 0
  ) {
    elements.entryOrganizerSummary.textContent = "Nie znaleziono wpisów wymagających uporządkowania.";
    return;
  }
  if (missingCount === 0 && nameChangeCount === 0) {
    elements.entryOrganizerSummary.textContent = `Znaleziono dane do automatycznej aktualizacji.${classificationMessage}${ergoInsurerMessage}${firstRegistrationDateMessage}${attachmentMessage}${renewalMessage}${splitMessage}${linkMessage}${nipMessage}`;
    return;
  }
  if (missingCount === 0) {
    elements.entryOrganizerSummary.textContent = `Znaleziono ${formatEntryOrganizerRecordCount(nameChangeCount)} z nazwą klienta do ujednolicenia.${classificationMessage}${ergoInsurerMessage}${firstRegistrationDateMessage}${attachmentMessage}${renewalMessage}${splitMessage}${linkMessage}${nipMessage}`;
    return;
  }
  const nameChangeMessage = nameChangeCount > 0
    ? ` Dodatkowo ${formatEntryOrganizerRecordCount(nameChangeCount)} ma nazwę klienta do ujednolicenia.`
    : "";
  if (targetCount === 0) {
    elements.entryOrganizerSummary.textContent = `Znaleziono ${formatEntryOrganizerRecordCount(missingCount)} z pustym PESEL-em do ręcznego uzupełnienia.${nameChangeMessage}${classificationMessage}${ergoInsurerMessage}${firstRegistrationDateMessage}${attachmentMessage}${renewalMessage}${splitMessage}${linkMessage}${nipMessage}`;
    return;
  }
  elements.entryOrganizerSummary.textContent = `Znaleziono ${formatEntryOrganizerRecordCount(missingCount)} z pustym PESEL-em. ${formatEntryOrganizerRecordCount(targetCount)} można najpierw porównać z innymi polisami.${nameChangeMessage}${classificationMessage}${ergoInsurerMessage}${firstRegistrationDateMessage}${attachmentMessage}${renewalMessage}${splitMessage}${linkMessage}${nipMessage}`;
}

function setEntryOrganizerBusy(busy) {
  entryOrganizerBusy = busy;
  elements.closeEntryOrganizer.disabled = busy;
  elements.skipEntryOrganizerManualStage.disabled = busy;
  elements.rejectEntryOrganizerMatch.disabled = busy;
  elements.confirmEntryOrganizerMatch.disabled = busy;
  elements.entryOrganizerManualPesel.disabled = busy;
}

function getCurrentEntryOrganizerReview() {
  const organizer = getEntryOrganizerApi();
  if (!organizer) return null;
  while (entryOrganizerIndex < entryOrganizerQueue.length) {
    const candidate = entryOrganizerQueue[entryOrganizerIndex];
    const target = policies.find((policy) => String(policy.id) === candidate.targetId);
    if (
      !target
      || !organizer.isMissingIdentity(target.identityNumber)
      || organizer.getPersonNameKey(target.clientName) !== candidate.nameKey
    ) {
      entryOrganizerIndex += 1;
      continue;
    }
    const sources = candidate.sourceIds
      .map((sourceId) => policies.find((policy) => String(policy.id) === sourceId))
      .filter((policy) => (
        policy
        && organizer.getPesel(policy.identityNumber) === candidate.pesel
        && organizer.getPersonNameKey(policy.clientName) === candidate.nameKey
      ));
    if (sources.length === 0) {
      entryOrganizerIndex += 1;
      continue;
    }
    return { candidate, target, sources };
  }
  return null;
}

function getCurrentEntryOrganizerManualRecord() {
  const organizer = getEntryOrganizerApi();
  if (!organizer) return null;
  while (entryOrganizerManualIndex < entryOrganizerManualQueue.length) {
    const item = entryOrganizerManualQueue[entryOrganizerManualIndex];
    const target = policies.find((policy) => String(policy.id) === item.targetId);
    if (!target || !organizer.isMissingIdentity(target.identityNumber)) {
      entryOrganizerManualIndex += 1;
      continue;
    }
    return { item, target };
  }
  return null;
}



function getCurrentEntryOrganizerLinkReview() {
  while (entryOrganizerLinkIndex < entryOrganizerLinkQueue.length) {
    const proposal = entryOrganizerLinkQueue[entryOrganizerLinkIndex];
    const personAnchor = policies.find((policy) => policy.id === proposal.personAnchorId);
    const companyAnchor = policies.find((policy) => policy.id === proposal.companyAnchorId);
    if (!personAnchor || !companyAnchor
      || areClientAccountsLinked(proposal.personKeys, proposal.companyKeys)) {
      entryOrganizerLinkIndex += 1;
      continue;
    }
    const personPolicies = getClientProfilePolicies(personAnchor);
    const companyPolicies = getClientProfilePolicies(companyAnchor);
    const personSets = getClientProfileMergeIdentityTypeSets(personPolicies);
    const companySets = getClientProfileMergeIdentityTypeSets(companyPolicies);
    if (
      personSets.PESEL.size === 0
      || companySets.PESEL.size > 0
      || (companySets.NIP.size === 0 && companySets.REGON.size === 0)
    ) {
      entryOrganizerLinkIndex += 1;
      continue;
    }
    return { proposal, personPolicies, companyPolicies, personSets, companySets };
  }
  return null;
}



function getCurrentEntryOrganizerSplitReview() {
  while (entryOrganizerSplitIndex < entryOrganizerSplitQueue.length) {
    const proposal = entryOrganizerSplitQueue[entryOrganizerSplitIndex];
    const companyKeySet = new Set(proposal.companyKeys);
    const fusedPolicies = proposal.fusedPolicyIds
      .map((policyId) => policies.find((policy) => policy.id === policyId))
      .filter((policy) => {
        if (!policy) return false;
        const identityKeys = getClientProfileIdentityValues(policy).map(getClientProfileIdentityKey);
        return identityKeys.includes(proposal.peselKey)
          && identityKeys.some((key) => companyKeySet.has(key));
      });
    const personAnchor = policies.find((policy) => policy.id === proposal.personAnchorId);
    const personPolicies = personAnchor
      ? getClientProfilePolicies(personAnchor).filter((policy) => {
        const identityKeys = getClientProfileIdentityValues(policy).map(getClientProfileIdentityKey);
        return identityKeys.includes(proposal.peselKey)
          && !identityKeys.some((key) => companyKeySet.has(key));
      })
      : [];
    if (fusedPolicies.length === 0 || personPolicies.length === 0) {
      entryOrganizerSplitIndex += 1;
      continue;
    }
    return { proposal, fusedPolicies, personPolicies };
  }
  return null;
}

function appendEntryOrganizerRecordField(container, label, value) {
  const field = document.createElement("div");
  field.className = "entry-organizer-record-field";
  const fieldLabel = document.createElement("span");
  fieldLabel.textContent = label;
  const fieldValue = document.createElement("strong");
  fieldValue.textContent = String(value || "-");
  field.append(fieldLabel, fieldValue);
  container.append(field);
}

function getEntryOrganizerPolicyPeriod(policy) {
  const validFrom = formatDate(policy?.validFrom);
  const validUntil = formatDate(policy?.validUntil);
  if (validFrom === "-" && validUntil === "-") return "-";
  if (validFrom === "-") return `do ${validUntil}`;
  if (validUntil === "-") return `od ${validFrom}`;
  return `${validFrom} - ${validUntil}`;
}

function renderEntryOrganizerTarget(policy) {
  elements.entryOrganizerTargetName.textContent = policy.clientName || "Bez nazwy klienta";
  elements.entryOrganizerTargetDetails.replaceChildren();
  appendEntryOrganizerRecordField(elements.entryOrganizerTargetDetails, "PESEL", "Brak PESEL-u");
  appendEntryOrganizerRecordField(elements.entryOrganizerTargetDetails, "Towarzystwo", policy.insurer);
  appendEntryOrganizerRecordField(elements.entryOrganizerTargetDetails, "Numer polisy", policy.policyNumber);
  appendEntryOrganizerRecordField(elements.entryOrganizerTargetDetails, "Rejestracja / rodzaj", policy.registration);
  appendEntryOrganizerRecordField(elements.entryOrganizerTargetDetails, "Okres", getEntryOrganizerPolicyPeriod(policy));
}

function renderEntryOrganizerSources(sources) {
  elements.entryOrganizerSourceRecords.replaceChildren();
  for (const policy of sources) {
    const source = document.createElement("div");
    source.className = "entry-organizer-source-record";
    const sourceName = document.createElement("strong");
    sourceName.textContent = policy.clientName || "Bez nazwy klienta";
    const sourceDetails = document.createElement("span");
    const details = [
      policy.insurer,
      policy.policyNumber ? `polisa ${policy.policyNumber}` : "",
      policy.registration,
      policy.validUntil ? `do ${formatDate(policy.validUntil)}` : "",
    ].filter(Boolean);
    sourceDetails.textContent = details.join(" · ") || "Rekord źródłowy";
    source.append(sourceName, sourceDetails);
    elements.entryOrganizerSourceRecords.append(source);
  }
}

function setEntryOrganizerManualError(message = "") {
  const hasError = Boolean(message);
  elements.entryOrganizerManualError.textContent = message;
  elements.entryOrganizerManualError.hidden = !hasError;
  elements.entryOrganizerManualPesel.setAttribute("aria-invalid", String(hasError));
}

function showEntryOrganizerMatchMode(review) {
  elements.entryOrganizerProgress.textContent = `Weryfikacja dopasowania ${entryOrganizerIndex + 1} z ${entryOrganizerQueue.length}`;
  elements.entryOrganizerTitle.textContent = "Czy to ta sama osoba?";
  elements.entryOrganizerCopy.textContent = "Porównaj rekord bez PESEL-u z rekordami źródłowymi. PESEL zostanie wpisany wyłącznie po Twoim potwierdzeniu.";
  if (elements.entryOrganizerTargetLabel) elements.entryOrganizerTargetLabel.textContent = "Rekord do uzupełnienia";
  if (elements.entryOrganizerCandidatePeselLabel) elements.entryOrganizerCandidatePeselLabel.textContent = "PESEL do wpisania";
  elements.entryOrganizerSourceLabel.textContent = "Dane znalezione w bazie";
  elements.entryOrganizerMatchSource.hidden = false;
  elements.entryOrganizerManualSource.hidden = true;
  elements.skipEntryOrganizerManualStage.hidden = true;
  elements.rejectEntryOrganizerMatch.textContent = "Nie, to inna osoba";
  elements.confirmEntryOrganizerMatch.textContent = "Tak, wpisz PESEL";
  elements.entryOrganizerCandidatePesel.textContent = review.candidate.pesel;
  elements.entryOrganizerManualPesel.value = "";
  setEntryOrganizerManualError();
  renderEntryOrganizerTarget(review.target);
  renderEntryOrganizerSources(review.sources);
}




function showEntryOrganizerLinkMode(review) {
  elements.entryOrganizerProgress.textContent = `Propozycja powiązania ${entryOrganizerLinkIndex + 1} z ${entryOrganizerLinkQueue.length}`;
  elements.entryOrganizerTitle.textContent = "Czy to firma tego klienta?";
  elements.entryOrganizerCopy.textContent = "Nazwa firmy zawiera imię i nazwisko klienta. Po potwierdzeniu obie karty będą pokazywać nawzajem swoje numery (PESEL, NIP, REGON), a polisy zostaną dokładnie tak, jak je wystawiono.";
  if (elements.entryOrganizerTargetLabel) elements.entryOrganizerTargetLabel.textContent = "Firma z bazy";
  if (elements.entryOrganizerCandidatePeselLabel) elements.entryOrganizerCandidatePeselLabel.textContent = "PESEL osoby prywatnej";
  elements.entryOrganizerSourceLabel.textContent = "Osoba prywatna z bazy";
  elements.entryOrganizerMatchSource.hidden = false;
  elements.entryOrganizerManualSource.hidden = true;
  elements.skipEntryOrganizerManualStage.hidden = true;
  elements.rejectEntryOrganizerMatch.textContent = "Nie, to inna osoba";
  elements.confirmEntryOrganizerMatch.textContent = "Tak, powiąż konta";
  elements.entryOrganizerCandidatePesel.textContent = review.proposal.personKeys.join(", ");
  elements.entryOrganizerManualPesel.value = "";
  setEntryOrganizerManualError();
  renderEntryOrganizerLinkTarget(review);
  renderEntryOrganizerSources(review.personPolicies.slice(0, 3));
}

function renderEntryOrganizerLinkTarget(review) {
  elements.entryOrganizerTargetName.textContent = review.proposal.companyName || "Firma bez nazwy";
  elements.entryOrganizerTargetDetails.replaceChildren();
  const nipKeys = review.proposal.companyKeys.filter((key) => getIdentityNumberType(key) === "NIP");
  const regonKeys = review.proposal.companyKeys.filter((key) => getIdentityNumberType(key) === "REGON");
  appendEntryOrganizerRecordField(elements.entryOrganizerTargetDetails, "NIP", nipKeys.join(", "));
  appendEntryOrganizerRecordField(elements.entryOrganizerTargetDetails, "REGON", regonKeys.join(", "));
  appendEntryOrganizerRecordField(
    elements.entryOrganizerTargetDetails,
    "Polisy firmy",
    pluralizePolicies(review.companyPolicies.length),
  );
  const insurers = [...new Set(review.companyPolicies.map((policy) => String(policy.insurer ?? "").trim()).filter(Boolean))];
  appendEntryOrganizerRecordField(elements.entryOrganizerTargetDetails, "Towarzystwa", insurers.join(", "));
}





function showEntryOrganizerSplitMode(review) {
  elements.entryOrganizerProgress.textContent = `Rozdzielenie konta ${entryOrganizerSplitIndex + 1} z ${entryOrganizerSplitQueue.length}`;
  elements.entryOrganizerTitle.textContent = "Rozdzielić kartę osoby i firmy?";
  elements.entryOrganizerCopy.textContent = "Polisy firmy mają dopisany PESEL właściciela, więc firma i osoba prywatna wyświetlają się jako jedna karta. Po potwierdzeniu firma dostanie własną kartę, a obie karty zostaną od razu powiązane i będą pokazywać nawzajem swoje numery.";
  if (elements.entryOrganizerTargetLabel) elements.entryOrganizerTargetLabel.textContent = "Firma z bazy";
  if (elements.entryOrganizerCandidatePeselLabel) elements.entryOrganizerCandidatePeselLabel.textContent = "PESEL zostaje na koncie osoby";
  elements.entryOrganizerSourceLabel.textContent = "Osoba prywatna z bazy";
  elements.entryOrganizerMatchSource.hidden = false;
  elements.entryOrganizerManualSource.hidden = true;
  elements.skipEntryOrganizerManualStage.hidden = true;
  elements.rejectEntryOrganizerMatch.textContent = "Nie, zostaw jedną kartę";
  elements.confirmEntryOrganizerMatch.textContent = "Tak, rozdziel i powiąż";
  elements.entryOrganizerCandidatePesel.textContent = review.proposal.peselKey;
  elements.entryOrganizerManualPesel.value = "";
  setEntryOrganizerManualError();
  renderEntryOrganizerSplitTarget(review);
  renderEntryOrganizerSources(review.personPolicies.slice(0, 3));
}

function renderEntryOrganizerSplitTarget(review) {
  const { proposal } = review;
  elements.entryOrganizerTargetName.textContent = proposal.companyName || "Firma bez nazwy";
  elements.entryOrganizerTargetDetails.replaceChildren();
  const nipKeys = proposal.companyKeys.filter((key) => getIdentityNumberType(key) === "NIP");
  const regonKeys = proposal.companyKeys.filter((key) => getIdentityNumberType(key) === "REGON");
  appendEntryOrganizerRecordField(elements.entryOrganizerTargetDetails, "NIP", nipKeys.join(", "));
  appendEntryOrganizerRecordField(elements.entryOrganizerTargetDetails, "REGON", regonKeys.join(", "));
  appendEntryOrganizerRecordField(elements.entryOrganizerTargetDetails, "Polisy firmy", pluralizePolicies(proposal.companyPoliciesCount));
  appendEntryOrganizerRecordField(elements.entryOrganizerTargetDetails, "Towarzystwa", proposal.companyInsurers.join(", "));
}

function showEntryOrganizerManualMode(review) {
  elements.entryOrganizerProgress.textContent = `Brakujące dane ${entryOrganizerManualIndex + 1} z ${entryOrganizerManualQueue.length}`;
  elements.entryOrganizerTitle.textContent = "Uzupełnij brakujący PESEL";
  elements.entryOrganizerCopy.textContent = "To ostatni etap porządkowania. Wpisz poprawny PESEL dla tego rekordu albo pomiń go bez wprowadzania zmian.";
  if (elements.entryOrganizerTargetLabel) elements.entryOrganizerTargetLabel.textContent = "Rekord do uzupełnienia";
  elements.entryOrganizerSourceLabel.textContent = "Ręczne uzupełnienie";
  elements.entryOrganizerMatchSource.hidden = true;
  elements.entryOrganizerManualSource.hidden = false;
  elements.skipEntryOrganizerManualStage.hidden = false;
  elements.rejectEntryOrganizerMatch.textContent = "Pomiń ten wpis";
  elements.confirmEntryOrganizerMatch.textContent = "Zapisz PESEL";
  elements.entryOrganizerManualPesel.value = "";
  setEntryOrganizerManualError();
  renderEntryOrganizerTarget(review.target);
  if (elements.entryOrganizerDialog.open) {
    requestAnimationFrame(() => elements.entryOrganizerManualPesel.focus());
  }
}

async function unifyEntryOrganizerNames() {
  const organizer = getEntryOrganizerApi();
  if (!organizer?.findNameUnificationChanges) return 0;
  if (getEntryOrganizerNameChanges().length === 0) return 0;

  setEntryOrganizerBusy(true);
  if (!(await ensureWritableDataFile({ deferFreshnessCheck: true }))) {
    setEntryOrganizerBusy(false);
    return null;
  }

  let appliedChanges = [];
  const applyNameChanges = () => {
    appliedChanges = [];
    const changes = organizer.findNameUnificationChanges(policies);
    const changedAt = Date.now();
    for (const change of changes) {
      const target = policies.find((policy) => String(policy?.id) === change.targetId);
      if (!target) continue;
      appliedChanges.push({
        target,
        clientName: target.clientName,
        updatedAt: target.updatedAt,
      });
      target.clientName = change.canonicalName;
      target.updatedAt = changedAt;
    }
    return true;
  };

  applyNameChanges();
  await yieldToUi();
  saveStatusPopupSuccessText = appliedChanges.length === 1
    ? "Nazwa klienta została ujednolicona"
    : "Nazwy klientów zostały ujednolicone";
  const saved = await persistPolicies({
    reapplyAfterConflict: applyNameChanges,
    reapplyFailureMessage: "Nie udało się ujednolicić nazw klientów w nowszej bazie.",
  });
  if (!saved) {
    for (const rollback of appliedChanges) {
      if (!policies.includes(rollback.target)) continue;
      rollback.target.clientName = rollback.clientName;
      if (rollback.updatedAt === undefined) delete rollback.target.updatedAt;
      else rollback.target.updatedAt = rollback.updatedAt;
    }
    if (appliedChanges.length > 0) markPoliciesRolledBack();
    render();
    setEntryOrganizerBusy(false);
    return null;
  }

  const unifiedCount = appliedChanges.length;
  render();
  setEntryOrganizerBusy(false);
  return unifiedCount;
}

async function fixEntryOrganizerKnownClassifications() {
  if (getEntryOrganizerKnownClassificationChanges().length === 0) return 0;

  setEntryOrganizerBusy(true);
  if (!(await ensureWritableDataFile({ deferFreshnessCheck: true }))) {
    setEntryOrganizerBusy(false);
    return null;
  }

  let appliedChanges = [];
  const applyClassificationChanges = () => {
    appliedChanges = [];
    const changes = getEntryOrganizerKnownClassificationChanges();
    const changedAt = Date.now();
    for (const change of changes) {
      const target = policies.find((policy) => String(policy?.id) === change.targetId);
      if (!target) continue;
      appliedChanges.push({
        target,
        hasRegistration: Object.prototype.hasOwnProperty.call(target, "registration"),
        registration: target.registration,
        hasRiskSummary: Object.prototype.hasOwnProperty.call(target, "riskSummary"),
        riskSummary: target.riskSummary,
        hasUpdatedAt: Object.prototype.hasOwnProperty.call(target, "updatedAt"),
        updatedAt: target.updatedAt,
      });
      Object.assign(target, change.fields);
      target.updatedAt = changedAt;
    }
    return true;
  };

  applyClassificationChanges();
  await yieldToUi();
  saveStatusPopupSuccessText = appliedChanges.length === 1
    ? "Rodzaj polisy został poprawiony"
    : "Rodzaje polis zostały poprawione";
  const saved = await persistPolicies({
    reapplyAfterConflict: applyClassificationChanges,
    reapplyFailureMessage: "Nie udało się poprawić rodzajów polis w nowszej bazie.",
  });
  if (!saved) {
    for (const rollback of appliedChanges) {
      if (!policies.includes(rollback.target)) continue;
      if (rollback.hasRegistration) rollback.target.registration = rollback.registration;
      else delete rollback.target.registration;
      if (rollback.hasRiskSummary) rollback.target.riskSummary = rollback.riskSummary;
      else delete rollback.target.riskSummary;
      if (rollback.hasUpdatedAt) rollback.target.updatedAt = rollback.updatedAt;
      else delete rollback.target.updatedAt;
    }
    if (appliedChanges.length > 0) markPoliciesRolledBack();
    render();
    setEntryOrganizerBusy(false);
    return null;
  }

  const fixedCount = appliedChanges.length;
  render();
  setEntryOrganizerBusy(false);
  return fixedCount;
}

async function fixEntryOrganizerErgoInsurerLabels() {
  if (getEntryOrganizerErgoInsurerChanges().length === 0) return 0;

  setEntryOrganizerBusy(true);
  if (!(await ensureWritableDataFile({ deferFreshnessCheck: true }))) {
    setEntryOrganizerBusy(false);
    return null;
  }

  let appliedChanges = [];
  const applyErgoInsurerChanges = () => {
    appliedChanges = [];
    const changes = getEntryOrganizerErgoInsurerChanges();
    const changedAt = Date.now();
    for (const change of changes) {
      const target = policies.find((policy) => String(policy?.id) === change.targetId);
      if (!target) continue;
      appliedChanges.push({
        target,
        insurer: target.insurer,
        hasUpdatedAt: Object.prototype.hasOwnProperty.call(target, "updatedAt"),
        updatedAt: target.updatedAt,
      });
      target.insurer = change.insurer;
      target.updatedAt = changedAt;
    }
    return true;
  };

  applyErgoInsurerChanges();
  await yieldToUi();
  saveStatusPopupSuccessText = appliedChanges.length === 1
    ? "Towarzystwo polisy zostało poprawione"
    : "Towarzystwa polis zostały poprawione";
  const saved = await persistPolicies({
    reapplyAfterConflict: applyErgoInsurerChanges,
    reapplyFailureMessage: "Nie udało się poprawić towarzystw polis w nowszej bazie.",
  });
  if (!saved) {
    for (const rollback of appliedChanges) {
      if (!policies.includes(rollback.target)) continue;
      rollback.target.insurer = rollback.insurer;
      if (rollback.hasUpdatedAt) rollback.target.updatedAt = rollback.updatedAt;
      else delete rollback.target.updatedAt;
    }
    if (appliedChanges.length > 0) markPoliciesRolledBack();
    render();
    setEntryOrganizerBusy(false);
    return null;
  }

  const fixedCount = appliedChanges.length;
  render();
  setEntryOrganizerBusy(false);
  return fixedCount;
}

async function fillEntryOrganizerFirstRegistrationDates() {
  const organizer = getEntryOrganizerApi();
  if (!organizer?.findFirstRegistrationDateChanges) return 0;
  if (getEntryOrganizerFirstRegistrationDateChanges().length === 0) return 0;

  setEntryOrganizerBusy(true);
  if (!(await ensureWritableDataFile({ deferFreshnessCheck: true }))) {
    setEntryOrganizerBusy(false);
    return null;
  }

  let mutationStates = new Map();
  const applyFirstRegistrationDateChanges = () => {
    mutationStates = new Map();
    const changes = organizer.findFirstRegistrationDateChanges(policies);
    const changedAt = Date.now();
    for (const change of changes) {
      const target = policies.find((policy) => String(policy?.id) === change.targetId);
      if (!target) continue;
      capturePolicyMutationState(mutationStates, target);
      target.firstRegistrationDate = change.firstRegistrationDate;
      target.updatedAt = changedAt;
    }
    return true;
  };

  applyFirstRegistrationDateChanges();
  await yieldToUi();
  saveStatusPopupSuccessText = mutationStates.size === 1
    ? "Data pierwszej rejestracji została uzupełniona"
    : "Daty pierwszej rejestracji zostały uzupełnione";
  const saved = await persistPolicies({
    reapplyAfterConflict: applyFirstRegistrationDateChanges,
    reapplyFailureMessage: "Nie udało się uzupełnić dat pierwszej rejestracji w nowszej bazie.",
  });
  if (!saved) {
    restorePolicyMutationStates(mutationStates);
    if (mutationStates.size > 0) markPoliciesRolledBack();
    render();
    setEntryOrganizerBusy(false);
    return null;
  }

  const filledCount = mutationStates.size;
  render();
  setEntryOrganizerBusy(false);
  return filledCount;
}



const ENTRY_ORGANIZER_NIP_LOOKUP_LIMIT = 100;

async function fetchRegistryNipForRegon(regon) {
  try {
    const response = await apiFetch("/api/rejestr-firm/nip", {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({ regon }),
    });
    if (response.status === 404) return { dostepne: false };
    if (response.status === 429) return { limit: true };
    if (!response.ok) return { blad: true };
    return { dostepne: true, wynik: await response.json() };
  } catch {
    return { blad: true };
  }
}

async function fillEntryOrganizerNipNumbers() {
  const candidates = getEntryOrganizerNipFillCandidates();
  if (candidates.length === 0) return 0;
  const limitedCandidates = candidates.slice(0, ENTRY_ORGANIZER_NIP_LOOKUP_LIMIT);
  const fills = [];
  let registryUnavailable = false;
  let registryThrottled = false;
  for (let index = 0; index < limitedCandidates.length; index += 1) {
    const candidate = limitedCandidates[index];
    showAppBusyOverlay(`Szukam NIP-ów w rejestrze podatników… ${index + 1} z ${limitedCandidates.length}`);
    const lookup = await fetchRegistryNipForRegon(candidate.regon);
    if (lookup.dostepne === false) {
      registryUnavailable = true;
      break;
    }
    if (lookup.limit) {
      registryThrottled = true;
      break;
    }
    if (lookup.blad) continue;
    if (shouldFillNipFromRegistry(candidate.names, lookup.wynik)) {
      fills.push({ candidate, nip: String(lookup.wynik.nip).replace(/\D/g, "") });
    }
  }
  showAppBusyOverlay("Porządkowanie…");
  if (registryUnavailable) {
    showToast("Uzupełnianie NIP-ów z rejestru będzie dostępne po ponownym uruchomieniu programu.", "warning");
  } else if (registryThrottled) {
    showToast("Rejestr podatników chwilowo ogranicza zapytania - pozostałe NIP-y uzupełnią się przy kolejnym porządkowaniu.", "warning");
  }
  if (fills.length === 0) return 0;

  setEntryOrganizerBusy(true);
  if (!(await ensureWritableDataFile({ deferFreshnessCheck: true }))) {
    setEntryOrganizerBusy(false);
    return null;
  }

  let mutationStates = new Map();
  const applyNipFills = () => {
    mutationStates = new Map();
    const changedAt = Date.now();
    for (const { candidate, nip } of fills) {
      for (const policyId of candidate.policyIds) {
        const policy = policies.find((item) => item.id === policyId);
        if (!policy) continue;
        const identityKeys = getClientProfileIdentityValues(policy).map(getClientProfileIdentityKey);
        
        if (identityKeys.some((key) => getIdentityNumberType(key) === "NIP")) continue;
        if (!identityKeys.includes(candidate.regon)) continue;
        const hasFreeSecondary = !String(policy.secondaryIdentityNumber ?? "").trim();
        const hasFreePrimary = !String(policy.identityNumber ?? "").trim();
        if (!hasFreeSecondary && !hasFreePrimary) continue;
        
        if (!mutationStates.has(policy.id)) {
          mutationStates.set(policy.id, {
            policy,
            identityNumber: policy.identityNumber,
            secondaryIdentityNumber: policy.secondaryIdentityNumber,
            hasUpdatedAt: Object.prototype.hasOwnProperty.call(policy, "updatedAt"),
            updatedAt: policy.updatedAt,
          });
        }
        if (hasFreeSecondary) policy.secondaryIdentityNumber = nip;
        else policy.identityNumber = nip;
        policy.updatedAt = changedAt;
      }
    }
    return true;
  };

  applyNipFills();
  if (mutationStates.size === 0) {
    setEntryOrganizerBusy(false);
    return 0;
  }
  await yieldToUi();
  saveStatusPopupSuccessText = "NIP-y firm uzupełnione z rejestru podatników";
  const saved = await persistPolicies({
    reapplyAfterConflict: applyNipFills,
    reapplyFailureMessage: "Nie udało się uzupełnić NIP-ów w nowszej bazie.",
  });
  if (!saved) {
    mutationStates.forEach((state) => {
      if (!policies.includes(state.policy)) return;
      state.policy.identityNumber = state.identityNumber;
      state.policy.secondaryIdentityNumber = state.secondaryIdentityNumber;
      if (state.hasUpdatedAt) state.policy.updatedAt = state.updatedAt;
      else delete state.policy.updatedAt;
    });
    if (mutationStates.size > 0) markPoliciesRolledBack();
    render();
    setEntryOrganizerBusy(false);
    return null;
  }

  const filledNipCount = mutationStates.size;
  render();
  setEntryOrganizerBusy(false);
  return filledNipCount;
}


function isPolicyInCurrentPdfParserWindow(policy) {
  const validFrom = String(policy?.validFrom ?? "").trim();
  if (!/^\d{4}-\d{2}-\d{2}$/.test(validFrom)) return false;
  const today = new Date();
  const dateFromValue = new Date(today.getFullYear(), today.getMonth() - 12, today.getDate());
  const dateFrom = [dateFromValue.getFullYear(), String(dateFromValue.getMonth() + 1).padStart(2, "0"), String(dateFromValue.getDate()).padStart(2, "0")].join("-");
  const dateToValue = new Date(today.getFullYear(), today.getMonth() + 12, today.getDate());
  const dateTo = [dateToValue.getFullYear(), String(dateToValue.getMonth() + 1).padStart(2, "0"), String(dateToValue.getDate()).padStart(2, "0")].join("-");
  
  
  return validFrom >= dateFrom && validFrom <= dateTo;
}

function getEntryOrganizerAttachmentDataCandidates() {
  return policies.filter((policy) => {
    
    
    if (!isPolicyInCurrentPdfParserWindow(policy)) return false;
    const enrichmentKey = getPolicyAttachmentEnrichmentKey(policy);
    if (!enrichmentKey || enrichmentKey === policy.attachmentEnrichmentKey) return false;
    
    
    return true;
  });
}

async function fillEntryOrganizerAttachmentData() {
  if (!globalThis.PolicyPdfImporter?.importPolicyPdf) return 0;
  const candidates = getEntryOrganizerAttachmentDataCandidates();
  if (candidates.length === 0) return 0;

  setEntryOrganizerBusy(true);
  try {
    await ensureAttachmentsBaseDirectory();
  } catch {
    
    setEntryOrganizerBusy(false);
    return 0;
  }

  const changes = [];
  let insurerConflictCount = 0;
  for (let index = 0; index < candidates.length; index += 1) {
    const candidate = candidates[index];
    showAppBusyOverlay(`Porządkowanie… Czytanie plików polis (${index + 1} z ${candidates.length})`);
    await yieldToUi();
    const result = await parsePolicyAttachmentPdfFields(candidate);
    if (result.status === "unavailable") continue;
    if (result.status === "conflict") insurerConflictCount += 1;
    changes.push({
      policyId: String(candidate.id),
      fields: result.status === "parsed" ? result.fields : {},
      importedPolicy: result.status === "parsed" ? result.importedPolicy : null,
      buyerTransfer: POLICY_BUYER_TRANSFER_FEATURE_ENABLED && result.status === "parsed"
        ? (result.buyerTransfer || null)
        : null,
      enrichmentKey: getPolicyAttachmentEnrichmentKey(candidate),
    });
  }
  showAppBusyOverlay("Porządkowanie…");
  if (changes.length === 0) {
    if (insurerConflictCount > 0) {
      showToast(
        `Pominięto ${insurerConflictCount} plików PDF, ponieważ wskazywały inne towarzystwo niż rekord.`,
        "warning",
      );
    }
    setEntryOrganizerBusy(false);
    return 0;
  }

  if (!(await ensureWritableDataFile({ deferFreshnessCheck: true }))) {
    setEntryOrganizerBusy(false);
    return null;
  }

  const transferRelocations = [];
  try {
    for (const change of changes) {
      if (!change.buyerTransfer) continue;
      const target = policies.find((policy) => String(policy?.id) === change.policyId);
      if (
        !target
        || getPolicyBuyerTransferPrecondition(target) !== change.buyerTransfer.expectedBuyerState
      ) {
        throw new Error("Dane polisy zmieniły się podczas odczytu PDF.");
      }
      const relocation = await prepareRelocatedPolicyAttachments(
        target,
        change.buyerTransfer.ownerValues.clientName,
        target.policyNumber,
      );
      change.relocation = relocation;
      transferRelocations.push(relocation);
    }
  } catch (error) {
    await deleteExternalAttachmentFiles(
      transferRelocations.flatMap((relocation) => relocation.copiedAttachments),
    );
    setEntryOrganizerBusy(false);
    showToast(
      error?.message || "Nie udało się bezpiecznie przenieść plików zbytego pojazdu.",
      "warning",
    );
    return null;
  }

  let appliedStates = [];
  let filledCount = 0;
  let buyerTransferCount = 0;
  const applyAttachmentData = () => {
    appliedStates = [];
    filledCount = 0;
    buyerTransferCount = 0;
    let transferConflict = false;
    const changedAt = Date.now();
    
    
    
    
    const policiesById = new Map();
    for (const policy of policies) {
      const policyKey = String(policy?.id);
      if (!policiesById.has(policyKey)) policiesById.set(policyKey, policy);
    }
    for (const change of changes) {
      const target = policiesById.get(change.policyId);
      if (!target) continue;
      appliedStates.push({
        target,
        fieldState: captureImportedPolicyFieldRollbackState(target),
        buyerTransferState: captureBuyerTransferRollbackState(target, policies),
        hasAttachments: Object.prototype.hasOwnProperty.call(target, "attachments"),
        attachments: target.attachments,
        hasEnrichmentKey: Object.prototype.hasOwnProperty.call(target, "attachmentEnrichmentKey"),
        enrichmentKey: target.attachmentEnrichmentKey,
        hasUpdatedAt: Object.prototype.hasOwnProperty.call(target, "updatedAt"),
        updatedAt: target.updatedAt,
      });
      const buyerTransferApplied = POLICY_BUYER_TRANSFER_FEATURE_ENABLED && change.buyerTransfer
        ? applyPolicyBuyerTransfer(target, change.buyerTransfer, policies)
        : false;
      if (change.buyerTransfer && !buyerTransferApplied) {
        transferConflict = true;
        continue;
      }
      if (buyerTransferApplied) buyerTransferCount += 1;
      if (change.relocation) {
        const desiredAttachments = normalizePolicyAttachments(change.relocation.nextAttachments);
        const desiredIds = new Set(desiredAttachments.map((attachment) => attachment.id));
        const concurrentAttachments = normalizePolicyAttachments(target.attachments)
          .filter((attachment) => !desiredIds.has(attachment.id));
        target.attachments = [...desiredAttachments, ...concurrentAttachments];
      }
      const syncSource = change.buyerTransfer
        ? Object.fromEntries(Object.entries(change.importedPolicy || {}).filter(([fieldName]) => (
            !POLICY_BUYER_TRANSFER_CLIENT_FIELDS.includes(fieldName)
          )))
        : (change.importedPolicy || {});
      const appliedFieldNames = applyImportedPolicyFieldSync(target, syncSource);
      target.attachmentEnrichmentKey = change.relocation
        ? getPolicyAttachmentEnrichmentKey(target)
        : change.enrichmentKey;
      if (appliedFieldNames.length > 0 || buyerTransferApplied) {
        target.updatedAt = changedAt;
        filledCount += 1;
      }
    }
    return !transferConflict;
  };

  if (!applyAttachmentData()) {
    for (const state of appliedStates) {
      if (!policies.includes(state.target)) continue;
      restoreImportedPolicyFieldRollbackState(state.target, state.fieldState);
      if (POLICY_BUYER_TRANSFER_FEATURE_ENABLED) {
        restoreBuyerTransferRollbackState(state.target, state.buyerTransferState);
      }
      if (state.hasAttachments) state.target.attachments = state.attachments;
      else delete state.target.attachments;
      if (state.hasEnrichmentKey) state.target.attachmentEnrichmentKey = state.enrichmentKey;
      else delete state.target.attachmentEnrichmentKey;
      if (state.hasUpdatedAt) state.target.updatedAt = state.updatedAt;
      else delete state.target.updatedAt;
    }
    if (appliedStates.length > 0) markPoliciesRolledBack();
    await deleteExternalAttachmentFiles(
      transferRelocations.flatMap((relocation) => relocation.copiedAttachments),
    );
    render();
    setEntryOrganizerBusy(false);
    showToast(
      "Dane polisy zmieniły się podczas odczytu PDF. Automatyczna korekta zbytego pojazdu została pominięta.",
      "warning",
    );
    return null;
  }
  await yieldToUi();
  saveStatusPopupSuccessText = filledCount === 1
    ? "Dane z pliku polisy zostały uzupełnione"
    : (filledCount > 1 ? "Dane z plików polis zostały uzupełnione" : "Pliki polis zostały przeczytane");
  const saved = await persistPolicies({
    reapplyAfterConflict: applyAttachmentData,
    reapplyFailureMessage: "Nie udało się uzupełnić danych z plików polis w nowszej bazie.",
  });
  if (!saved) {
    for (const state of appliedStates) {
      if (!policies.includes(state.target)) continue;
      restoreImportedPolicyFieldRollbackState(state.target, state.fieldState);
      if (POLICY_BUYER_TRANSFER_FEATURE_ENABLED) {
        restoreBuyerTransferRollbackState(state.target, state.buyerTransferState);
      }
      if (state.hasAttachments) state.target.attachments = state.attachments;
      else delete state.target.attachments;
      if (state.hasEnrichmentKey) state.target.attachmentEnrichmentKey = state.enrichmentKey;
      else delete state.target.attachmentEnrichmentKey;
      if (state.hasUpdatedAt) state.target.updatedAt = state.updatedAt;
      else delete state.target.updatedAt;
    }
    if (appliedStates.length > 0) markPoliciesRolledBack();
    await deleteExternalAttachmentFiles(
      transferRelocations.flatMap((relocation) => relocation.copiedAttachments),
    );
    render();
    setEntryOrganizerBusy(false);
    return null;
  }

  await deleteExternalAttachmentFiles(
    getUnsharedAttachmentsForDeletion(
      transferRelocations.flatMap((relocation) => relocation.sourceAttachments),
    ),
  );
  render();
  setEntryOrganizerBusy(false);
  if (insurerConflictCount > 0) {
    showToast(
      `Pominięto ${insurerConflictCount} plików PDF, ponieważ wskazywały inne towarzystwo niż rekord.`,
      "warning",
    );
  }
  if (POLICY_BUYER_TRANSFER_FEATURE_ENABLED && buyerTransferCount > 0) {
    showToast(
      buyerTransferCount === 1
        ? "1 polisa została oznaczona jako pojazd zbyty - rekord pokazuje pierwotnego właściciela."
        : `${buyerTransferCount} polis zostało oznaczonych jako pojazd zbyty - rekordy pokazują pierwotnych właścicieli.`,
      "warning",
    );
  }
  return filledCount;
}

async function verifyEntryOrganizerRenewals() {
  showAppBusyOverlay("Porządkowanie…");
  await yieldToUi();
  try {
    if (getRenewalVerificationChangeCount() === 0) return 0;
    
    
    await yieldToUi();
    setEntryOrganizerBusy(true);
    if (!(await ensureWritableDataFile({ deferFreshnessCheck: true }))) {
      setEntryOrganizerBusy(false);
      return null;
    }

    let mutationStates = new Map();
    const applyVerification = () => {
      mutationStates = new Map();
      applyRenewalVerification(mutationStates);
      return true;
    };
    applyVerification();
    await yieldToUi();
    saveStatusPopupSuccessText = "Powiązania wznowień zostały zweryfikowane";
    const saved = await persistPolicies({
      reapplyAfterConflict: applyVerification,
      reapplyFailureMessage: "Nie udało się zweryfikować wznowień w nowszej bazie.",
    });
    if (!saved) {
      restorePolicyMutationStates(mutationStates);
      if (mutationStates.size > 0) markPoliciesRolledBack();
      render();
      setEntryOrganizerBusy(false);
      return null;
    }

    const changedCount = mutationStates.size;
    render();
    setEntryOrganizerBusy(false);
    return changedCount;
  } finally {
    hideAppBusyOverlay();
  }
}

async function finishEntryOrganizerReview(completed = false) {
  
  
  if (elements.entryOrganizerDialog.open) elements.entryOrganizerDialog.close();
  if (completed && entryOrganizerSelectedGroups.has("wznowienia")) {
    const verifiedCount = await verifyEntryOrganizerRenewals();
    if (verifiedCount === null) completed = false;
    else entryOrganizerRenewalVerifiedCount += verifiedCount;
  }
  updateEntryOrganizerSettingsSummary();
  const updated = entryOrganizerApprovedCount + entryOrganizerManualSavedCount;
  const skipped = entryOrganizerManualSkippedCount;
  const totalUpdated = updated
    + entryOrganizerNameUnifiedCount
    + entryOrganizerClassificationFixedCount
    + entryOrganizerErgoInsurerFixedCount
    + entryOrganizerFirstRegistrationDateFilledCount
    + entryOrganizerAttachmentDataFilledCount
    + entryOrganizerRenewalVerifiedCount
    + entryOrganizerSplitCount
    + entryOrganizerLinkedCount
    + entryOrganizerNipFilledCount;
  if (completed) {
    if (totalUpdated > 0) {
      showToast(`Porządkowanie zakończone. Zaktualizowano: ${formatEntryOrganizerRecordCount(totalUpdated)}.`);
    } else {
      showToast("Porządkowanie zakończone bez zmian.", skipped > 0 || entryOrganizerRejectedCount > 0 ? "warning" : "success");
    }
  } else if (totalUpdated > 0 || skipped > 0 || entryOrganizerRejectedCount > 0) {
    showToast(`Przerwano porządkowanie. Zaktualizowano: ${formatEntryOrganizerRecordCount(totalUpdated)}.`, "warning");
  }
  if (completed || totalUpdated > 0 || skipped > 0 || entryOrganizerRejectedCount > 0) {
    reportDiagnosticsEvent("porzadkowanie", {
      dokonczono: completed === true,
      zaktualizowano: totalUpdated,
      poprawioneRodzaje: entryOrganizerClassificationFixedCount,
      poprawioneTowarzystwa: entryOrganizerErgoInsurerFixedCount,
      uzupelnioneZPlikow: entryOrganizerAttachmentDataFilledCount,
      rozdzieloneKonta: entryOrganizerSplitCount,
      powiazaneKonta: entryOrganizerLinkedCount,
      uzupelnioneNipy: entryOrganizerNipFilledCount,
      pominieto: skipped,
      odrzucono: entryOrganizerRejectedCount,
    });
  }
  entryOrganizerQueue = [];
  entryOrganizerIndex = 0;
  entryOrganizerStage = "matches";
  entryOrganizerManualQueue = [];
  entryOrganizerManualIndex = 0;
  entryOrganizerLinkQueue = [];
  entryOrganizerLinkIndex = 0;
  entryOrganizerSplitQueue = [];
  entryOrganizerSplitIndex = 0;
  entryOrganizerNameUnifiedCount = 0;
  entryOrganizerClassificationFixedCount = 0;
  entryOrganizerErgoInsurerFixedCount = 0;
  entryOrganizerFirstRegistrationDateFilledCount = 0;
  entryOrganizerAttachmentDataFilledCount = 0;
  entryOrganizerRenewalVerifiedCount = 0;
  entryOrganizerLinkedCount = 0;
  entryOrganizerSplitCount = 0;
  entryOrganizerNipFilledCount = 0;
  elements.skipEntryOrganizerManualStage.hidden = true;
  elements.entryOrganizerManualPesel.value = "";
  setEntryOrganizerManualError();
  setEntryOrganizerBusy(false);
}

function renderEntryOrganizerReview() {
  if (entryOrganizerStage === "matches") {
    const review = getCurrentEntryOrganizerReview();
    if (review) {
      showEntryOrganizerMatchMode(review);
      setEntryOrganizerBusy(false);
      return;
    }
    
    
    
    entryOrganizerStage = "splits";
    entryOrganizerSplitQueue = entryOrganizerSelectedGroups.has("rozdzielenia")
      ? getClientAccountSplitProposals()
      : [];
    entryOrganizerSplitIndex = 0;
  }

  if (entryOrganizerStage === "splits") {
    const splitReview = getCurrentEntryOrganizerSplitReview();
    if (splitReview) {
      showEntryOrganizerSplitMode(splitReview);
      setEntryOrganizerBusy(false);
      return;
    }
    
    
    entryOrganizerStage = "links";
    entryOrganizerLinkQueue = entryOrganizerSelectedGroups.has("powiazania")
      ? getClientAccountLinkProposals()
      : [];
    entryOrganizerLinkIndex = 0;
  }

  if (entryOrganizerStage === "links") {
    const linkReview = getCurrentEntryOrganizerLinkReview();
    if (linkReview) {
      showEntryOrganizerLinkMode(linkReview);
      setEntryOrganizerBusy(false);
      return;
    }
    entryOrganizerStage = "manual";
    entryOrganizerManualQueue = entryOrganizerSelectedGroups.has("pesele")
      ? getEntryOrganizerMissingRecords()
      : [];
    entryOrganizerManualIndex = 0;
  }

  const review = getCurrentEntryOrganizerManualRecord();
  if (!review) {
    void finishEntryOrganizerReview(true);
    return;
  }
  showEntryOrganizerManualMode(review);
  setEntryOrganizerBusy(false);
}

function readEntryOrganizerGroupSelection() {
  const allGroupIds = new Set(ENTRY_ORGANIZER_GROUPS.map((group) => group.id));
  try {
    const stored = JSON.parse(globalThis.localStorage?.getItem(ENTRY_ORGANIZER_GROUP_SELECTION_KEY) || "null");
    if (!Array.isArray(stored)) return allGroupIds;
    const selection = new Set(stored.filter((groupId) => allGroupIds.has(groupId)));
    return selection.size > 0 ? selection : allGroupIds;
  } catch {
    return allGroupIds;
  }
}

function persistEntryOrganizerGroupSelection(selection) {
  try {
    globalThis.localStorage?.setItem(
      ENTRY_ORGANIZER_GROUP_SELECTION_KEY,
      JSON.stringify([...selection]),
    );
  } catch {
  }
}




async function collectEntryOrganizerGroupCounts() {
  const counts = new Map();
  counts.set("pesele", getEntryOrganizerMissingRecords().length);
  await yieldToUi();
  counts.set("nazwy", getEntryOrganizerNameChanges().length);
  await yieldToUi();
  counts.set("rodzaje", getEntryOrganizerKnownClassificationChanges().length);
  await yieldToUi();
  counts.set("towarzystwa", getEntryOrganizerErgoInsurerChanges().length);
  await yieldToUi();
  counts.set("daty", getEntryOrganizerFirstRegistrationDateChanges().length);
  await yieldToUi();
  counts.set("pdf", getEntryOrganizerAttachmentDataCandidates().length);
  await yieldToUi();
  counts.set("wznowienia", getRenewalVerificationChangeCount());
  await yieldToUi();
  counts.set("rozdzielenia", getClientAccountSplitProposals().length);
  await yieldToUi();
  counts.set("powiazania", getClientAccountLinkProposals().length);
  await yieldToUi();
  counts.set("nipy", getEntryOrganizerNipFillCandidates().length);
  return counts;
}

function confirmEntryOrganizerStart(groupCounts) {
  const dialog = elements.entryOrganizerWarningDialog;
  if (!dialog?.showModal || !elements.entryOrganizerWarningConfirm || !elements.entryOrganizerWarningCancel) {
    
    return Promise.resolve(new Set(ENTRY_ORGANIZER_GROUPS.map((group) => group.id)));
  }
  const savedSelection = readEntryOrganizerGroupSelection();
  const groupList = elements.entryOrganizerGroupList;
  if (groupList) {
    groupList.replaceChildren();
    ENTRY_ORGANIZER_GROUPS.forEach((group) => {
      const count = Number(groupCounts?.get?.(group.id)) || 0;
      const row = document.createElement("label");
      row.className = "entry-organizer-group-row";
      if (count === 0) row.classList.add("entry-organizer-group-row--empty");
      const checkbox = document.createElement("input");
      checkbox.type = "checkbox";
      checkbox.dataset.entryOrganizerGroup = group.id;
      checkbox.checked = count > 0 && savedSelection.has(group.id);
      checkbox.disabled = count === 0;
      const labelText = document.createElement("span");
      labelText.textContent = group.label;
      const badge = document.createElement("b");
      badge.textContent = count > 0 ? String(count) : "bez zaległości";
      row.append(checkbox, labelText, badge);
      groupList.append(row);
    });
  }
  return new Promise((resolve) => {
    const readCheckedGroups = () => {
      const checkedGroups = new Set();
      groupList?.querySelectorAll("input[data-entry-organizer-group]").forEach((checkbox) => {
        if (checkbox.checked && !checkbox.disabled) checkedGroups.add(checkbox.dataset.entryOrganizerGroup);
      });
      return checkedGroups;
    };
    const updateConfirmState = () => {
      elements.entryOrganizerWarningConfirm.disabled = readCheckedGroups().size === 0;
    };
    const finish = (selection) => {
      elements.entryOrganizerWarningConfirm.removeEventListener("click", onConfirm);
      elements.entryOrganizerWarningCancel.removeEventListener("click", onCancel);
      dialog.removeEventListener("cancel", onDialogCancel);
      groupList?.removeEventListener("change", updateConfirmState);
      elements.entryOrganizerWarningConfirm.disabled = false;
      if (dialog.open) dialog.close();
      resolve(selection);
    };
    const onConfirm = () => {
      const selection = readCheckedGroups();
      if (selection.size === 0) return;
      
      const nextSaved = new Set(savedSelection);
      ENTRY_ORGANIZER_GROUPS.forEach((group) => {
        const count = Number(groupCounts?.get?.(group.id)) || 0;
        if (count === 0) return;
        if (selection.has(group.id)) nextSaved.add(group.id);
        else nextSaved.delete(group.id);
      });
      persistEntryOrganizerGroupSelection(nextSaved);
      finish(selection);
    };
    const onCancel = () => finish(null);
    const onDialogCancel = (event) => {
      event.preventDefault();
      finish(null);
    };
    elements.entryOrganizerWarningConfirm.addEventListener("click", onConfirm);
    elements.entryOrganizerWarningCancel.addEventListener("click", onCancel);
    dialog.addEventListener("cancel", onDialogCancel);
    groupList?.addEventListener("change", updateConfirmState);
    updateConfirmState();
    dialog.showModal();
  });
}

async function startEntryOrganizerReview() {
  if (entryOrganizerBusy) return;
  showAppBusyOverlay("Sprawdzam, co jest do uporządkowania…");
  await yieldToUi();
  let groupCounts;
  try {
    groupCounts = await collectEntryOrganizerGroupCounts();
  } finally {
    hideAppBusyOverlay();
  }
  if ([...groupCounts.values()].every((count) => count === 0)) {
    updateEntryOrganizerSettingsSummary();
    showToast("Nie znaleziono wpisów wymagających uporządkowania.", "warning");
    return;
  }
  const selectedGroups = await confirmEntryOrganizerStart(groupCounts);
  if (!selectedGroups || selectedGroups.size === 0) return;
  entryOrganizerSelectedGroups = selectedGroups;
  showAppBusyOverlay("Porządkowanie…");
  await yieldToUi();
  try {
    entryOrganizerApprovedCount = 0;
    entryOrganizerRejectedCount = 0;
    entryOrganizerManualSavedCount = 0;
    entryOrganizerManualSkippedCount = 0;
    entryOrganizerNameUnifiedCount = 0;
    entryOrganizerClassificationFixedCount = 0;
    entryOrganizerErgoInsurerFixedCount = 0;
    entryOrganizerFirstRegistrationDateFilledCount = 0;
    entryOrganizerAttachmentDataFilledCount = 0;
    entryOrganizerRenewalVerifiedCount = 0;
    entryOrganizerLinkedCount = 0;
    entryOrganizerSplitCount = 0;
    entryOrganizerNipFilledCount = 0;

    const unifiedCount = selectedGroups.has("nazwy") ? await unifyEntryOrganizerNames() : 0;
    if (unifiedCount === null) return;
    entryOrganizerNameUnifiedCount = unifiedCount;
    await yieldToUi();

    const classificationFixedCount = selectedGroups.has("rodzaje") ? await fixEntryOrganizerKnownClassifications() : 0;
    if (classificationFixedCount === null) return;
    entryOrganizerClassificationFixedCount = classificationFixedCount;
    await yieldToUi();

    const ergoInsurerFixedCount = selectedGroups.has("towarzystwa") ? await fixEntryOrganizerErgoInsurerLabels() : 0;
    if (ergoInsurerFixedCount === null) return;
    entryOrganizerErgoInsurerFixedCount = ergoInsurerFixedCount;
    await yieldToUi();

    const firstRegistrationDateFilledCount = selectedGroups.has("daty") ? await fillEntryOrganizerFirstRegistrationDates() : 0;
    if (firstRegistrationDateFilledCount === null) return;
    entryOrganizerFirstRegistrationDateFilledCount = firstRegistrationDateFilledCount;
    await yieldToUi();

    const attachmentDataFilledCount = selectedGroups.has("pdf") ? await fillEntryOrganizerAttachmentData() : 0;
    if (attachmentDataFilledCount === null) return;
    entryOrganizerAttachmentDataFilledCount = attachmentDataFilledCount;
    await yieldToUi();

    const nipFilledCount = selectedGroups.has("nipy") ? await fillEntryOrganizerNipNumbers() : 0;
    if (nipFilledCount === null) return;
    entryOrganizerNipFilledCount = nipFilledCount;
    await yieldToUi();

    const needsMatchStage = selectedGroups.has("pesele") && getEntryOrganizerMissingRecords().length > 0;
    const needsSplitStage = selectedGroups.has("rozdzielenia") && getClientAccountSplitProposals().length > 0;
    const needsLinkStage = selectedGroups.has("powiazania") && getClientAccountLinkProposals().length > 0;
    if (!needsMatchStage && !needsSplitStage && !needsLinkStage) {
      await finishEntryOrganizerReview(true);
      return;
    }
    entryOrganizerQueue = needsMatchStage ? getEntryOrganizerCandidates() : [];
    entryOrganizerIndex = 0;
    entryOrganizerStage = "matches";
    entryOrganizerManualQueue = [];
    entryOrganizerManualIndex = 0;
    entryOrganizerLinkQueue = [];
    entryOrganizerLinkIndex = 0;
    entryOrganizerSplitQueue = [];
    entryOrganizerSplitIndex = 0;
    renderEntryOrganizerReview();
  } finally {
    hideAppBusyOverlay();
  }
  if (!elements.entryOrganizerDialog.open) {
    elements.entryOrganizerDialog.showModal();
  }
  if (entryOrganizerStage === "manual") {
    requestAnimationFrame(() => elements.entryOrganizerManualPesel.focus());
  }
}

function rejectCurrentEntryOrganizerMatch() {
  if (entryOrganizerBusy || !getCurrentEntryOrganizerReview()) return;
  entryOrganizerRejectedCount += 1;
  entryOrganizerIndex += 1;
  renderEntryOrganizerReview();
}

function rejectCurrentEntryOrganizerLink() {
  if (entryOrganizerBusy || !getCurrentEntryOrganizerLinkReview()) return;
  entryOrganizerRejectedCount += 1;
  entryOrganizerLinkIndex += 1;
  renderEntryOrganizerReview();
}

function rejectCurrentEntryOrganizerSplit() {
  if (entryOrganizerBusy || !getCurrentEntryOrganizerSplitReview()) return;
  entryOrganizerRejectedCount += 1;
  entryOrganizerSplitIndex += 1;
  renderEntryOrganizerReview();
}




async function confirmCurrentEntryOrganizerSplit() {
  if (entryOrganizerBusy) return;
  const review = getCurrentEntryOrganizerSplitReview();
  if (!review) return;
  setEntryOrganizerBusy(true);
  if (!(await ensureWritableDataFile({ deferFreshnessCheck: true }))) {
    setEntryOrganizerBusy(false);
    return;
  }

  const { proposal } = review;
  let mutationStates = new Map();
  let previousLinks = clientAccountLinks;
  const applySplit = () => {
    mutationStates = new Map();
    previousLinks = clientAccountLinks;
    if (applyClientAccountSplitChanges(proposal, policies, mutationStates) === 0) return false;
    clientAccountLinks = normalizeClientAccountLinks([...clientAccountLinks, {
      personKeys: [...proposal.personKeys],
      companyKeys: [...proposal.companyKeys],
      personName: proposal.personName,
      companyName: proposal.companyName,
      createdAt: new Date().toISOString(),
      source: "porzadkowanie",
    }]);
    return true;
  };

  if (!applySplit()) {
    setEntryOrganizerBusy(false);
    showToast("Te konta zmieniły się w międzyczasie. Uruchom porządkowanie ponownie.", "warning");
    entryOrganizerSplitIndex += 1;
    renderEntryOrganizerReview();
    return;
  }

  saveStatusPopupSuccessText = "Konta osoby i firmy rozdzielone";
  const saved = await persistPolicies({
    reapplyAfterConflict: applySplit,
    reapplyFailureMessage: "Nie udało się rozdzielić kont w nowszej bazie.",
  });
  if (!saved) {
    restoreClientAccountSplitMutationStates(mutationStates);
    clientAccountLinks = previousLinks;
    if (mutationStates.size > 0) markPoliciesRolledBack();
    render();
    setEntryOrganizerBusy(false);
    return;
  }

  entryOrganizerSplitCount += 1;
  entryOrganizerSplitIndex += 1;
  render();
  renderEntryOrganizerReview();
}

async function confirmCurrentEntryOrganizerLink() {
  if (entryOrganizerBusy) return;
  const review = getCurrentEntryOrganizerLinkReview();
  if (!review) return;
  setEntryOrganizerBusy(true);
  if (!(await ensureWritableDataFile({ deferFreshnessCheck: true }))) {
    setEntryOrganizerBusy(false);
    return;
  }

  
  
  const newLink = {
    personKeys: [...review.personSets.PESEL].sort(),
    companyKeys: [...review.companySets.NIP, ...review.companySets.REGON].sort(),
    personName: review.proposal.personName,
    companyName: review.proposal.companyName,
    createdAt: new Date().toISOString(),
    source: "porzadkowanie",
  };
  let previousLinks = clientAccountLinks;
  const applyLink = () => {
    previousLinks = clientAccountLinks;
    clientAccountLinks = normalizeClientAccountLinks([...clientAccountLinks, newLink]);
    return true;
  };
  applyLink();
  saveStatusPopupSuccessText = "Powiązanie kont zapisane";
  const saved = await persistPolicies({
    reapplyAfterConflict: applyLink,
    reapplyFailureMessage: "Nie udało się zapisać powiązania w nowszej bazie.",
  });
  if (!saved) {
    clientAccountLinks = previousLinks;
    markPoliciesRolledBack();
    setEntryOrganizerBusy(false);
    return;
  }

  entryOrganizerLinkedCount += 1;
  entryOrganizerLinkIndex += 1;
  renderEntryOrganizerReview();
}

async function confirmCurrentEntryOrganizerMatch() {
  if (entryOrganizerBusy) return;
  const review = getCurrentEntryOrganizerReview();
  if (!review) return;
  setEntryOrganizerBusy(true);
  if (!(await ensureWritableDataFile({ deferFreshnessCheck: true }))) {
    setEntryOrganizerBusy(false);
    return;
  }

  const organizer = getEntryOrganizerApi();
  const { candidate } = review;
  let activeTarget = review.target;
  let rollbackIdentity = activeTarget.identityNumber;
  let rollbackImportedTracking = captureImportedPolicyTrackingRollbackState(activeTarget);
  let rollbackUpdatedAt = activeTarget.updatedAt;
  let mutationApplied = false;
  const applyConfirmedPesel = () => {
    const currentTarget = policies.find((policy) => String(policy.id) === candidate.targetId);
    if (!currentTarget || organizer.getPersonNameKey(currentTarget.clientName) !== candidate.nameKey) return false;
    if (currentTarget !== activeTarget) {
      activeTarget = currentTarget;
      rollbackIdentity = currentTarget.identityNumber;
      rollbackImportedTracking = captureImportedPolicyTrackingRollbackState(currentTarget);
      rollbackUpdatedAt = currentTarget.updatedAt;
      mutationApplied = false;
    }
    const currentIdentity = String(currentTarget.identityNumber ?? "").trim();
    if (!organizer.isMissingIdentity(currentIdentity)) return organizer.getPesel(currentIdentity) === candidate.pesel;
    const matchingSourceExists = candidate.sourceIds.some((sourceId) => {
      const source = policies.find((policy) => String(policy.id) === sourceId);
      return source
        && organizer.getPesel(source.identityNumber) === candidate.pesel
        && organizer.getPersonNameKey(source.clientName) === candidate.nameKey;
    });
    if (!matchingSourceExists) return false;
    markImportedPolicyFieldsManuallyEdited(currentTarget, { identityNumber: candidate.pesel });
    currentTarget.identityNumber = candidate.pesel;
    currentTarget.updatedAt = Date.now();
    mutationApplied = true;
    return true;
  };

  if (!applyConfirmedPesel()) {
    setEntryOrganizerBusy(false);
    showToast("Rekord lub dane źródłowe zmieniły się. Uruchom porządkowanie ponownie.", "warning");
    renderEntryOrganizerReview();
    return;
  }

  saveStatusPopupSuccessText = "PESEL uzupełniony w rekordzie";
  const saved = await persistPolicies({
    reapplyAfterConflict: applyConfirmedPesel,
    reapplyFailureMessage: "Rekord lub dane źródłowe zmieniły się w nowszej bazie. PESEL nie został wpisany.",
  });
  if (!saved) {
    if (mutationApplied && policies.includes(activeTarget)) {
      activeTarget.identityNumber = rollbackIdentity;
      restoreImportedPolicyTrackingRollbackState(activeTarget, rollbackImportedTracking);
      if (rollbackUpdatedAt === undefined) delete activeTarget.updatedAt;
      else activeTarget.updatedAt = rollbackUpdatedAt;
      markPoliciesRolledBack();
    }
    render();
    setEntryOrganizerBusy(false);
    return;
  }

  entryOrganizerApprovedCount += 1;
  entryOrganizerIndex += 1;
  render();
  renderEntryOrganizerReview();
}

function skipCurrentEntryOrganizerManualRecord() {
  if (entryOrganizerBusy || !getCurrentEntryOrganizerManualRecord()) return;
  entryOrganizerManualSkippedCount += 1;
  entryOrganizerManualIndex += 1;
  renderEntryOrganizerReview();
}

function skipEntryOrganizerManualStage() {
  if (entryOrganizerBusy || entryOrganizerStage !== "manual") return;
  const organizer = getEntryOrganizerApi();
  if (!organizer) return;
  const skippedCount = entryOrganizerManualQueue
    .slice(entryOrganizerManualIndex)
    .reduce((count, item) => {
      const target = policies.find((policy) => String(policy.id) === item.targetId);
      return count + (target && organizer.isMissingIdentity(target.identityNumber) ? 1 : 0);
    }, 0);
  entryOrganizerManualSkippedCount += skippedCount;
  entryOrganizerManualIndex = entryOrganizerManualQueue.length;
  renderEntryOrganizerReview();
}

function rejectCurrentEntryOrganizerAction() {
  if (entryOrganizerStage === "manual") {
    skipCurrentEntryOrganizerManualRecord();
    return;
  }
  if (entryOrganizerStage === "splits") {
    rejectCurrentEntryOrganizerSplit();
    return;
  }
  if (entryOrganizerStage === "links") {
    rejectCurrentEntryOrganizerLink();
    return;
  }
  rejectCurrentEntryOrganizerMatch();
}

function normalizeEntryOrganizerManualPeselInput() {
  const digits = elements.entryOrganizerManualPesel.value.replace(/\D/g, "").slice(0, 11);
  elements.entryOrganizerManualPesel.value = digits;
  setEntryOrganizerManualError();
}

async function saveCurrentEntryOrganizerManualPesel() {
  if (entryOrganizerBusy) return;
  const review = getCurrentEntryOrganizerManualRecord();
  if (!review) return;
  const organizer = getEntryOrganizerApi();
  const pesel = organizer.getPesel(elements.entryOrganizerManualPesel.value);
  if (!pesel) {
    setEntryOrganizerManualError("Wpisz dokładnie 11 cyfr numeru PESEL.");
    elements.entryOrganizerManualPesel.focus();
    return;
  }
  if (!organizer.isValidPesel(pesel)) {
    setEntryOrganizerManualError("Ten numer PESEL ma nieprawidłową sumę kontrolną. Sprawdź wpisane cyfry.");
    elements.entryOrganizerManualPesel.focus();
    return;
  }

  setEntryOrganizerBusy(true);
  if (!(await ensureWritableDataFile({ deferFreshnessCheck: true }))) {
    setEntryOrganizerBusy(false);
    return;
  }

  const targetId = review.item.targetId;
  let activeTarget = review.target;
  let rollbackIdentity = activeTarget.identityNumber;
  let rollbackImportedTracking = captureImportedPolicyTrackingRollbackState(activeTarget);
  let rollbackUpdatedAt = activeTarget.updatedAt;
  let mutationApplied = false;
  const applyManualPesel = () => {
    const currentTarget = policies.find((policy) => String(policy.id) === targetId);
    if (!currentTarget) return false;
    if (currentTarget !== activeTarget) {
      activeTarget = currentTarget;
      rollbackIdentity = currentTarget.identityNumber;
      rollbackImportedTracking = captureImportedPolicyTrackingRollbackState(currentTarget);
      rollbackUpdatedAt = currentTarget.updatedAt;
      mutationApplied = false;
    }
    const currentIdentity = String(currentTarget.identityNumber ?? "").trim();
    if (!organizer.isMissingIdentity(currentIdentity)) return organizer.getPesel(currentIdentity) === pesel;
    markImportedPolicyFieldsManuallyEdited(currentTarget, { identityNumber: pesel });
    currentTarget.identityNumber = pesel;
    currentTarget.updatedAt = Date.now();
    mutationApplied = true;
    return true;
  };

  if (!applyManualPesel()) {
    setEntryOrganizerBusy(false);
    showToast("Ten rekord zmienił się. Uruchom porządkowanie ponownie.", "warning");
    renderEntryOrganizerReview();
    return;
  }

  saveStatusPopupSuccessText = "PESEL uzupełniony w rekordzie";
  const saved = await persistPolicies({
    reapplyAfterConflict: applyManualPesel,
    reapplyFailureMessage: "Rekord zmienił się w nowszej bazie. PESEL nie został wpisany.",
  });
  if (!saved) {
    if (mutationApplied && policies.includes(activeTarget)) {
      activeTarget.identityNumber = rollbackIdentity;
      restoreImportedPolicyTrackingRollbackState(activeTarget, rollbackImportedTracking);
      if (rollbackUpdatedAt === undefined) delete activeTarget.updatedAt;
      else activeTarget.updatedAt = rollbackUpdatedAt;
      markPoliciesRolledBack();
    }
    render();
    setEntryOrganizerBusy(false);
    return;
  }

  entryOrganizerManualSavedCount += 1;
  entryOrganizerManualIndex += 1;
  render();
  renderEntryOrganizerReview();
}

async function confirmCurrentEntryOrganizerAction() {
  if (entryOrganizerStage === "manual") {
    await saveCurrentEntryOrganizerManualPesel();
    return;
  }
  if (entryOrganizerStage === "splits") {
    await confirmCurrentEntryOrganizerSplit();
    return;
  }
  if (entryOrganizerStage === "links") {
    await confirmCurrentEntryOrganizerLink();
    return;
  }
  await confirmCurrentEntryOrganizerMatch();
}

function normalizeRegistration(value) {
  const trimmed = String(value ?? "").trim();
  const selectedValue = REGISTRATION_SUGGESTIONS.find((item) => normalize(item) === normalize(trimmed));
  return selectedValue ?? trimmed.toLocaleUpperCase("pl");
}

function normalizeVehicleIdentifier(value) {
  return String(value ?? "")
    .replace(/[^A-Z0-9]/gi, "")
    .toLocaleUpperCase("pl");
}

function normalizeVehicleDetail(value) {
  return String(value ?? "")
    .replace(/\u00a0/g, " ")
    .replace(/\s+/g, " ")
    .trim()
    .slice(0, 120);
}

function normalizeFirstRegistrationDate(value) {
  const date = parseLocalDate(value);
  return date ? formatDateForInput(date) : "";
}

function normalizeDriverLicenseDate(value) {
  const raw = String(value ?? "").trim();
  if (/^(?:19|20)\d{2}$/.test(raw)) return raw;
  return normalizeFirstRegistrationDate(raw);
}

function formatDriverLicenseDateDisplay(value) {
  const normalized = normalizeDriverLicenseDate(value);
  if (!normalized) return "";
  return /^(?:19|20)\d{2}$/.test(normalized) ? `rok ${normalized}` : formatDate(normalized);
}

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





function extractStreetFromClientAddress(value) {
  const address = normalizeClientAddress(value);
  if (!address) return "";
  const postalCodePattern = /\b\d{2}[-\s]\d{3}\b/;
  const streetMarkerPattern = /(?:^|\s)(?:ul|al|pl|os|oś)\.|(?:^|\s)(?:ulica|aleja|aleje|plac|osiedle)\s/iu;
  const street = address
    .split(",")
    .map((segment) => segment.trim())
    .filter((segment) => segment && !postalCodePattern.test(segment))
    .find((segment) => streetMarkerPattern.test(segment) || /\d/.test(segment));
  if (street) return street;
  
  
  
  if (postalCodePattern.test(address)) {
    const beforePostalCode = address.split(postalCodePattern)[0].replace(/[\s,]+$/, "").trim();
    if (beforePostalCode) return beforePostalCode;
  }
  const fromStreetMarker = address.match(/(?:^|\s)((?:ul|al|pl|os|oś)\.\s*.+|(?:ulica|aleja|aleje|plac|osiedle)\s+.+)$/iu);
  return fromStreetMarker ? fromStreetMarker[1].trim() : "";
}

function extractCityFromClientAddress(value) {
  const address = normalizeClientAddress(value);
  if (!address) return "";
  const postalCodeMatch = address.match(/\b\d{2}[-\s]\d{3}\b/);
  if (postalCodeMatch) {
    const afterPostalCode = address
      .slice((postalCodeMatch.index ?? 0) + postalCodeMatch[0].length)
      .replace(/^[\s,]+/, "");
    const cityBeforeStreet = afterPostalCode
      .split(",")[0]
      .split(/(?=\s+(?:ul|al|pl|os|oś)\.\s|\s+(?:ulica|aleja|aleje|plac|osiedle)\s)/iu)[0]
      .trim();
    if (cityBeforeStreet) return cityBeforeStreet;
  }

  const street = extractStreetFromClientAddress(address);
  return address
    .split(",")
    .map((segment) => segment.trim())
    .find((segment) => (
      segment
      && normalize(segment) !== normalize(street)
      && !/\d/.test(segment)
    )) || "";
}

function formatHomeAddressLabel(value) {
  const street = extractStreetFromClientAddress(value);
  if (!street) return "";
  const city = extractCityFromClientAddress(value);
  return city && !normalize(street).includes(normalize(city))
    ? `${street}, ${city}`
    : street;
}

function normalizeClientPhone(value) {
  return String(value ?? "")
    .replace(/[^\d+\s()-]/g, "")
    .replace(/\s+/g, " ")
    .trim()
    .slice(0, 40);
}

function normalizeClientEmail(value) {
  return String(value ?? "")
    .replace(/\s+/g, "")
    .trim()
    .toLocaleLowerCase("pl")
    .slice(0, 120);
}

function extractClientEmail(value) {
  return String(value ?? "").match(/[\w.!#$%&'*+/=?^`{|}~-]+@[a-z0-9-]+(?:\.[a-z0-9-]+)+/i)?.[0] || "";
}

function extractClientPhone(value) {
  const candidates = String(value ?? "").match(/(?:\+?\d[\d\s()-]{7,}\d)/g) || [];
  return normalizeClientPhone(candidates.find((candidate) => {
    const digits = candidate.replace(/\D/g, "");
    return digits.length >= 9 && digits.length <= 15;
  }) || "");
}

function formatClientPostalCodeInput(value) {
  const digits = String(value ?? "").replace(/\D/g, "").slice(0, 5);
  return digits.length > 2 ? `${digits.slice(0, 2)}-${digits.slice(2)}` : digits;
}

function normalizeClientPostalCode(value) {
  const formatted = formatClientPostalCodeInput(value);
  return /^\d{2}-\d{3}$/.test(formatted) ? formatted : "";
}

function extractClientPostalCode(value) {
  const match = String(value ?? "").match(/\b\d{2}[-\s]\d{3}\b/)?.[0] || "";
  return normalizeClientPostalCode(match);
}

function getSuggestionsForField(fieldName) {
  if (fieldName === "insurer") return getServedInsurerSettings().map((insurer) => insurer.name);
  if (fieldName === "registration") return REGISTRATION_SUGGESTIONS;
  if (fieldName === "clientName") {
    const uniqueNames = new Map();
    policies.forEach((policy) => {
      const clientName = String(policy.clientName ?? "").trim();
      const key = normalize(clientName);
      if (key && !uniqueNames.has(key)) uniqueNames.set(key, clientName);
    });
    return [...uniqueNames.values()];
  }
  return [];
}

function getAlwaysSuggestionInput(target) {
  const input = target?.closest?.("input[data-always-suggestions]");
  if (input) return input;
  return target?.dataset?.alwaysSuggestions ? target : null;
}

function getClientSuggestionInput(target) {
  const input = target?.closest?.('input[name="clientName"][list="clientOptions"]');
  if (input) return input;
  return target?.name === "clientName" && target?.getAttribute?.("list") === "clientOptions"
    ? target
    : null;
}

function positionAlwaysVisibleSuggestions(input) {
  const rect = input?.getBoundingClientRect?.();
  if (!rect) return;
  const viewportWidth = Number(globalThis.innerWidth) || document.documentElement.clientWidth || 1280;
  const viewportHeight = Number(globalThis.innerHeight) || document.documentElement.clientHeight || 720;
  const width = Math.min(Math.max(rect.width, 190), Math.max(190, viewportWidth - 16));
  const left = Math.max(8, Math.min(rect.left, viewportWidth - width - 8));
  elements.alwaysVisibleSuggestions.style.width = `${width}px`;
  elements.alwaysVisibleSuggestions.style.left = `${left}px`;

  if (viewportHeight - rect.bottom < 190 && rect.top > 190) {
    elements.alwaysVisibleSuggestions.style.top = "auto";
    elements.alwaysVisibleSuggestions.style.bottom = `${Math.max(8, viewportHeight - rect.top + 4)}px`;
  } else {
    elements.alwaysVisibleSuggestions.style.top = `${rect.bottom + 4}px`;
    elements.alwaysVisibleSuggestions.style.bottom = "auto";
  }
}

function showAlwaysVisibleSuggestions(input, showAll = true) {
  const suggestions = getSuggestionsForField(input?.name);
  if (suggestions.length === 0) return;

  if (activeAlwaysSuggestionInput && activeAlwaysSuggestionInput !== input) {
    activeAlwaysSuggestionInput.setAttribute("aria-expanded", "false");
  }
  activeAlwaysSuggestionInput = input;
  const typedValue = normalize(input.value);
  visibleAlwaysSuggestions = showAll || !typedValue
    ? suggestions
    : suggestions.filter((suggestion) => normalize(suggestion).includes(typedValue));

  const clearSuggestionLabel = input?.name === "registration" ? "Nr Rej..." : "Wyczyść...";
  const clearSuggestion = `<button class="always-visible-suggestions-clear" type="button" role="option" aria-selected="false" data-always-suggestion-clear>${clearSuggestionLabel}</button>`;
  const matchingSuggestions = visibleAlwaysSuggestions.length > 0
    ? visibleAlwaysSuggestions.map((suggestion, index) => `
        <button type="button" role="option" aria-selected="false" data-always-suggestion="${index}">${escapeHtml(suggestion)}</button>
      `).join("")
    : '<span class="always-visible-suggestions-empty">Brak pasujących opcji</span>';
  elements.alwaysVisibleSuggestions.innerHTML = clearSuggestion + matchingSuggestions;
  elements.alwaysVisibleSuggestions.hidden = false;
  input.setAttribute("aria-expanded", "true");
  positionAlwaysVisibleSuggestions(input);
}

function hideAlwaysVisibleSuggestions() {
  if (activeAlwaysSuggestionInput) {
    activeAlwaysSuggestionInput.setAttribute("aria-expanded", "false");
  }
  activeAlwaysSuggestionInput = null;
  visibleAlwaysSuggestions = [];
  elements.alwaysVisibleSuggestions.hidden = true;
}

function selectAlwaysVisibleSuggestion(index) {
  const suggestion = visibleAlwaysSuggestions[Number(index)];
  if (!activeAlwaysSuggestionInput || !suggestion) return;
  const input = activeAlwaysSuggestionInput;
  input.value = suggestion;
  if (typeof input.dispatchEvent === "function" && typeof globalThis.Event === "function") {
    input.dispatchEvent(new Event("input", { bubbles: true }));
    input.dispatchEvent(new Event("change", { bubbles: true }));
  }
  input.focus();
  hideAlwaysVisibleSuggestions();
}

function clearAlwaysVisibleSuggestion() {
  if (!activeAlwaysSuggestionInput) return;
  const input = activeAlwaysSuggestionInput;
  input.value = "";
  if (input === elements.registrationInput) {
    updateAddFormEndDateForPolicyType();
  }
  input.focus();
  hideAlwaysVisibleSuggestions();
}

function moveAlwaysSuggestionFocus(currentButton, direction) {
  const buttons = [...elements.alwaysVisibleSuggestions.querySelectorAll('button[role="option"]')];
  if (buttons.length === 0) return;
  const currentIndex = buttons.indexOf(currentButton);
  let nextIndex;
  if (direction === "first") {
    nextIndex = 0;
  } else if (direction === "last") {
    nextIndex = buttons.length - 1;
  } else {
    nextIndex = (Math.max(0, currentIndex) + Number(direction) + buttons.length) % buttons.length;
  }
  buttons.forEach((button, index) => button.setAttribute("aria-selected", String(index === nextIndex)));
  buttons[nextIndex].focus();
}

function acceptBestSuggestion(input) {
  const typedValue = String(input.value ?? "").trim();
  if (!typedValue) return;

  const normalizedValue = normalize(typedValue);
  const suggestions = getSuggestionsForField(input.name);
  const exactMatch = suggestions.find((suggestion) => normalize(suggestion) === normalizedValue);
  if (input.name === "clientName") {
    input.value = exactMatch ?? typedValue;
    return;
  }
  const startsWithMatch = suggestions.find((suggestion) => normalize(suggestion).startsWith(normalizedValue));
  const containsMatch = suggestions.find((suggestion) => normalize(suggestion).includes(normalizedValue));
  input.value = exactMatch ?? startsWithMatch ?? containsMatch ?? typedValue;
}

function getUniqueIdentityNumberForClient(clientName) {
  const normalizedName = normalize(clientName);
  if (!normalizedName) return "";

  const matchingIdentityNumbers = new Map();
  policies.forEach((policy) => {
    if (normalize(policy.clientName) !== normalizedName) return;
    const identityNumber = String(policy.identityNumber ?? "").trim();
    if (!identityNumber) return;

    const digits = identityNumber.replace(/\D/g, "");
    const hasOnlyNumberFormatting = /^[\d\s.-]+$/.test(identityNumber);
    const identityKey = hasOnlyNumberFormatting && [9, 10, 11].includes(digits.length)
      ? `digits:${digits}`
      : `text:${normalize(identityNumber)}`;
    if (!matchingIdentityNumbers.has(identityKey)) {
      matchingIdentityNumbers.set(identityKey, identityNumber);
    }
  });

  return matchingIdentityNumbers.size === 1
    ? [...matchingIdentityNumbers.values()][0]
    : "";
}

function updateAddFormIdentityFromClientName() {
  const currentIdentity = String(elements.identityNumberInput.value ?? "").trim();
  const canReplaceIdentity = !currentIdentity || currentIdentity === addFormAutoFilledIdentity;
  if (!canReplaceIdentity) {
    addFormAutoFilledIdentity = "";
    return;
  }

  const uniqueIdentity = getUniqueIdentityNumberForClient(elements.clientNameInput.value);
  elements.identityNumberInput.value = uniqueIdentity;
  addFormAutoFilledIdentity = uniqueIdentity;
}

function handleAddFormEnter(event) {
  if (event.key !== "Enter" || event.isComposing) return;
  const fields = [
    elements.clientNameInput,
    elements.identityNumberInput,
    elements.insurerInput,
    elements.policyNumberInput,
    elements.registrationInput,
    ...(document.documentElement.dataset.startDateInput === "visible" ? [elements.validFromInput] : []),
    elements.validUntilInput,
    elements.premiumInput,
    elements.contactInput,
  ];
  const currentIndex = fields.indexOf(event.target);
  if (currentIndex < 0) return;

  event.preventDefault();
  acceptBestSuggestion(event.target);
  if (event.target === elements.clientNameInput) {
    updateAddFormIdentityFromClientName();
  }
  if (event.target === elements.registrationInput) {
    updateAddFormEndDateForPolicyType();
  }

  if (event.target === elements.contactInput) {
    return elements.form.requestSubmit();
  }

  fields[currentIndex + 1]?.focus();
}

function clearPolicyFormFields() {
  elements.form.reset();
  clearNewPolicyAttachments();
  delete elements.form.dataset.importedValidFrom;
  addFormAutoFilledIdentity = "";
  [
    elements.clientNameInput,
    elements.identityNumberInput,
    elements.insurerInput,
    elements.policyNumberInput,
    elements.registrationInput,
    elements.validFromInput,
    elements.validUntilInput,
    elements.premiumInput,
    elements.contactInput,
  ].forEach((input) => {
    input.value = "";
  });
  refreshAddFormStartDateVisibility();
  resizeAutoGrowingTextarea(elements.contactInput);
  elements.startDateFormField.dataset.manuallyEdited = "false";
  delete elements.validUntilInput.dataset.travelDerived;
  updateAddPolicyButtonState();
  elements.clientNameInput.focus();
  showToast("Pola formularza zostały wyczyszczone");
}

function resizeAutoGrowingTextarea(textarea) {
  if (!textarea?.style) return;
  textarea.style.height = "auto";
  const contentHeight = Number(textarea.scrollHeight);
  if (Number.isFinite(contentHeight) && contentHeight > 0) {
    textarea.style.height = `${Math.max(42, Math.min(contentHeight, 150))}px`;
    textarea.style.overflowY = contentHeight > 150 ? "auto" : "hidden";
  }
}

function getSelectedPrintColumns() {
  const selectedKeys = new Set(
    printColumnInputs
      .filter((input) => input.checked)
      .map((input) => input.dataset.printColumn),
  );
  return PRINT_COLUMNS.filter((column) => selectedKeys.has(column.key));
}

function getPrintCellValue(policy, columnKey) {
  if (columnKey === "validFrom") return formatStartDate(policy);
  if (columnKey === "validUntil") return formatDate(policy.validUntil);
  if (columnKey === "premium") return formatPremium(policy.premium);
  return policy[columnKey] || "-";
}

function updatePrintOptionsState() {
  const selectedCount = getSelectedPrintColumns().length;
  elements.confirmPrint.disabled = selectedCount === 0;
  elements.confirmPrint.textContent = selectedCount === 0
    ? "Wybierz co najmniej jedną kolumnę"
    : `Otwórz PDF (${selectedCount})`;
}

function setAllPrintColumns(checked) {
  printColumnInputs.forEach((input) => {
    input.checked = checked;
  });
  updatePrintOptionsState();
}

function closePrintOptionsDialog() {
  elements.printOptionsDialog.close();
}

function openPrintOptionsDialog() {
  const visiblePolicies = getPaginatedPolicies(getVisiblePolicies());
  if (visiblePolicies.length === 0) {
    showToast("Brak widocznych polis do zapisania w PDF");
    return;
  }

  elements.printVisibleCount.textContent = `Do PDF: ${pluralizePolicies(visiblePolicies.length)}`;
  updatePrintOptionsState();
  elements.printOptionsDialog.showModal();
}

async function createPoliciesPdf(visiblePolicies, selectedColumns, now, printedAt) {
  if (!globalThis.PoliciesPdfRenderer?.create) {
    throw new Error("Brakuje lokalnego modułu do tworzenia PDF.");
  }

  const includesPremium = selectedColumns.some((column) => column.key === "premium");
  const totalPremium = visiblePolicies.reduce(
    (sum, policy) => sum + (parsePremiumValue(policy.premium) ?? 0),
    0,
  );

  return globalThis.PoliciesPdfRenderer.create({
    title: "Iseca",
    meta: `${pluralizePolicies(visiblePolicies.length)} • ${selectedColumns.length} z ${PRINT_COLUMNS.length} kolumn • wygenerowano ${printedAt}`,
    columns: selectedColumns.map((column) => ({ label: column.label, weight: column.weight })),
    rows: visiblePolicies.map((policy) => (
      selectedColumns.map((column) => getPrintCellValue(policy, column.key))
    )),
    totalPremium: includesPremium ? formatPremium(totalPremium) : "",
    fileTitle: `Polisy ${formatDateForInput(now)}`,
    generatedAt: now,
  });
}

function openOrDownloadPoliciesPdf(pdfBytes, previewWindow, fileName) {
  const pdfBlob = new Blob([pdfBytes], { type: "application/pdf" });
  const pdfUrl = URL.createObjectURL(pdfBlob);
  let openedInNewTab = false;

  if (previewWindow && !previewWindow.closed) {
    try {
      previewWindow.location.replace(pdfUrl);
      openedInNewTab = true;
    } catch {
      previewWindow.close();
    }
  }

  if (!openedInNewTab) {
    const downloadLink = document.createElement("a");
    downloadLink.href = pdfUrl;
    downloadLink.download = fileName;
    document.body.append(downloadLink);
    downloadLink.click();
    downloadLink.remove();
  }

  globalThis.setTimeout(() => URL.revokeObjectURL(pdfUrl), 5 * 60 * 1000);
  return openedInNewTab;
}

function showPreviewLoadingMessage(previewWindow, title, message, fontWeight = 400) {
  const previewDocument = previewWindow.document;
  previewDocument.title = title;

  const stylesheet = previewDocument.createElement("link");
  stylesheet.rel = "stylesheet";
  stylesheet.href = new URL("pliki/vhwsorwqtxdyzietldhegbsptp.css", document.baseURI).href;
  previewDocument.head.append(stylesheet);

  const messageElement = previewDocument.createElement("p");
  messageElement.textContent = message;
  messageElement.style.cssText = `margin: 0; padding: 24px; font-size: 16px; font-weight: ${fontWeight}; color: #26354a`;
  previewDocument.body.replaceChildren(messageElement);
}

async function printVisiblePolicies() {
  const visiblePolicies = getPaginatedPolicies(getVisiblePolicies());
  const selectedColumns = getSelectedPrintColumns();
  if (visiblePolicies.length === 0) {
    closePrintOptionsDialog();
    showToast("Brak widocznych polis do zapisania w PDF");
    return;
  }
  if (selectedColumns.length === 0) {
    showToast("Wybierz co najmniej jedną kolumnę");
    return;
  }

  const now = new Date();
  const printedAt = new Intl.DateTimeFormat("pl-PL", {
    dateStyle: "long",
    timeStyle: "short",
  }).format(now);
  const previewWindow = globalThis.open("", "_blank");
  if (previewWindow) {
    showPreviewLoadingMessage(previewWindow, "Przygotowywanie PDF", "Przygotowywanie pliku PDF…");
  }
  closePrintOptionsDialog();

  try {
    const pdfBytes = await createPoliciesPdf(visiblePolicies, selectedColumns, now, printedAt);
    const fileName = `polisy-${formatDateForInput(now)}.pdf`;
    const openedInNewTab = openOrDownloadPoliciesPdf(pdfBytes, previewWindow, fileName);
    showToast(openedInNewTab
      ? "PDF został otwarty w nowej karcie"
      : "PDF został przygotowany do zapisu");
  } catch (error) {
    if (previewWindow && !previewWindow.closed) previewWindow.close();
    console.error(error);
    showToast("Nie udało się przygotować pliku PDF");
  }
}

function escapeHtml(value) {
  return String(value ?? "")
    .replaceAll("&", "&amp;")
    .replaceAll("<", "&lt;")
    .replaceAll(">", "&gt;")
    .replaceAll('"', "&quot;")
    .replaceAll("'", "&#039;");
}

function formatContactWithEmailLinks(value) {
  const contact = String(value ?? "");
  if (!contact) return "-";

  const emailPattern = /[\w.!#$%&'*+/=?^`{|}~-]+@[a-z0-9-]+(?:\.[a-z0-9-]+)+/gi;
  let result = "";
  let lastIndex = 0;

  for (const match of contact.matchAll(emailPattern)) {
    const email = match[0];
    const matchIndex = match.index ?? 0;
    result += escapeHtml(contact.slice(lastIndex, matchIndex));
    result += `<a class="contact-email-link" href="mailto:${escapeHtml(email)}">${escapeHtml(email)}</a>`;
    lastIndex = matchIndex + email.length;
  }

  return result + escapeHtml(contact.slice(lastIndex));
}

function getIdentityNumberType(value) {
  const digitsLength = String(value ?? "").replace(/\D/g, "").length;
  if (digitsLength === 9) return "REGON";
  if (digitsLength === 10) return "NIP";
  if (digitsLength === 11) return "PESEL";
  return "";
}

function formatIdentityNumberCopyButton(value) {
  const identityNumber = String(value ?? "").trim();
  if (!identityNumber) return "-";

  const hasOnlyNumberFormatting = /^[\d\s.-]+$/.test(identityNumber);
  const copyValue = hasOnlyNumberFormatting ? identityNumber.replace(/\D/g, "") : identityNumber;
  const typeLabel = getIdentityNumberType(identityNumber) || "numer";
  return `<button
    type="button"
    class="copy-value-button"
    data-action="copy-value"
    data-copy-value="${escapeHtml(copyValue)}"
    aria-label="Skopiuj ${typeLabel} ${escapeHtml(identityNumber)}"
    title="Kliknij, aby skopiować"
  >${escapeHtml(identityNumber)}</button>`;
}

function formatIdentityNumberTypeBadge(value) {
  const identityNumber = String(value ?? "").trim();
  const identityNumberType = getIdentityNumberType(identityNumber);
  if (!identityNumberType) return "";

  const hasOnlyNumberFormatting = /^[\d\s.-]+$/.test(identityNumber);
  const searchType = identityNumberType === "NIP" || identityNumberType === "REGON"
    ? identityNumberType
    : "";
  if (!hasOnlyNumberFormatting || !searchType) {
    return `<small class="identity-type-badge">${identityNumberType}</small>`;
  }

  const digits = identityNumber.replace(/\D/g, "");
  const searchQuery = encodeURIComponent(`${searchType} ${digits}`);
  return `<a
    class="identity-type-badge identity-type-badge--search"
    href="https://www.google.com/search?q=${searchQuery}"
    target="_blank"
    rel="noopener noreferrer"
    aria-label="Wyszukaj ${searchType} ${escapeHtml(digits)} w Google"
    title="Wyszukaj ${searchType} w Google"
  >${searchType}</a>`;
}

function formatInsurerCalculatorLink(value) {
  const insurer = String(value ?? "").trim();
  if (!insurer) return "-";

  const calculatorUrl = findInsurerWebsiteUrl(insurer);
  if (!calculatorUrl) return escapeHtml(insurer);

  return `<a
    class="insurer-calculator-link"
    href="${escapeHtml(calculatorUrl)}"
    target="_blank"
    rel="noopener noreferrer"
    aria-label="Otwórz stronę ${escapeHtml(insurer)} w nowej karcie"
    title="Otwórz stronę ${escapeHtml(insurer)}"
  >${escapeHtml(insurer)}</a>`;
}

function pluralizePolicies(count) {
  if (count === 1) return "1 polisa";
  const lastTwo = count % 100;
  const last = count % 10;
  if (last >= 2 && last <= 4 && !(lastTwo >= 12 && lastTwo <= 14)) {
    return `${count} polisy`;
  }
  return `${count} polis`;
}

function parseLocalDate(dateString) {
  if (!dateString) return null;
  const value = String(dateString).trim();
  let year;
  let month;
  let day;

  const isoMatch = value.match(/^(\d{4})-(\d{1,2})-(\d{1,2})$/);
  const polishMatch = value.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 null;
  }

  const parsed = new Date(year, month - 1, day);
  if (
    Number.isNaN(parsed.getTime())
    || parsed.getFullYear() !== year
    || parsed.getMonth() !== month - 1
    || parsed.getDate() !== day
  ) return null;
  return parsed;
}

function startOfToday() {
  const today = new Date();
  return new Date(today.getFullYear(), today.getMonth(), today.getDate());
}

function daysFromToday(dateString) {
  const date = parseLocalDate(dateString);
  if (!date) return null;
  return Math.round((date.getTime() - startOfToday().getTime()) / 86400000);
}

function isTravelPolicy(policy) {
  const policyType = normalize(policy?.registration);
  return policyType === normalize("Podróż") || policyType === normalize("Podróże");
}

function getRenewalClientMatch(policy) {
  const rawIdentityNumber = String(policy?.identityNumber ?? "").trim();
  const identityDigits = rawIdentityNumber.replace(/\D/g, "");
  const identityNumber = identityDigits || normalize(rawIdentityNumber).replace(/\s+/g, "");
  return {
    identityNumber,
    clientName: normalize(policy?.clientName),
  };
}

function haveMatchingRenewalClient(firstPolicy, secondPolicy) {
  const firstClient = getRenewalClientMatch(firstPolicy);
  const secondClient = getRenewalClientMatch(secondPolicy);
  if (firstClient.identityNumber && secondClient.identityNumber) {
    if (firstClient.identityNumber === secondClient.identityNumber) return true;
    
    
    
    
    const firstType = getIdentityNumberType(firstClient.identityNumber);
    const secondType = getIdentityNumberType(secondClient.identityNumber);
    if (firstType === secondType) return false;
  }
  return Boolean(firstClient.clientName) && firstClient.clientName === secondClient.clientName;
}

function getRenewalSubjectKey(policy) {
  if (
    isTravelPolicy(policy)
    || (POLICY_BUYER_TRANSFER_FEATURE_ENABLED && policy?.transferredToBuyer === true)
  ) return "";
  return normalize(policy?.registration).replace(/\s+/g, "");
}

function getRenewalPairScore(previousPolicy, currentPolicy) {
  if (!previousPolicy || !currentPolicy || previousPolicy.id === currentPolicy.id) return null;
  if (isTravelPolicy(previousPolicy) || isTravelPolicy(currentPolicy)) return null;
  if (
    POLICY_BUYER_TRANSFER_FEATURE_ENABLED
    && (previousPolicy.transferredToBuyer === true || currentPolicy.transferredToBuyer === true)
  ) return null;
  if (!haveMatchingRenewalClient(previousPolicy, currentPolicy)) return null;
  const previousSubject = getRenewalSubjectKey(previousPolicy);
  const currentSubject = getRenewalSubjectKey(currentPolicy);
  if (!previousSubject || previousSubject !== currentSubject) return null;

  const previousEnd = parseLocalDate(previousPolicy.validUntil);
  const previousStart = getPolicyStartDate(previousPolicy);
  const currentStart = getPolicyStartDate(currentPolicy);
  const currentEnd = parseLocalDate(currentPolicy.validUntil);
  if (!previousStart || !previousEnd || !currentStart || !currentEnd || currentEnd <= previousEnd) return null;

  const expectedPreviousEnd = calculateEndDate(formatDateForInput(previousStart));
  if (formatDateForInput(previousEnd) !== formatDateForInput(expectedPreviousEnd)) return null;

  const expectedStart = new Date(previousEnd);
  expectedStart.setDate(expectedStart.getDate() + 1);
  const expectedEnd = calculateEndDate(formatDateForInput(expectedStart));
  if (
    formatDateForInput(currentStart) !== formatDateForInput(expectedStart)
    || formatDateForInput(currentEnd) !== formatDateForInput(expectedEnd)
  ) return null;

  const firstIdentity = getRenewalClientMatch(previousPolicy).identityNumber;
  const secondIdentity = getRenewalClientMatch(currentPolicy).identityNumber;
  
  
  const identityScore = firstIdentity && secondIdentity && firstIdentity === secondIdentity ? 1000 : 500;
  return identityScore + 500;
}





function setPolicyRenewalStatusValue(policy, status, manuallyEdited = false) {
  const normalizedStatus = status === "renewed" || status === "not-renewed" ? status : null;
  policy.renewalStatus = normalizedStatus;
  if (normalizedStatus) {
    policy.renewalStatusManuallyEdited = manuallyEdited === true;
  } else {
    delete policy.renewalStatusManuallyEdited;
  }
}

function setPolicyRenewalPredecessor(policy, previousPolicyId, manuallyEdited = false) {
  const normalizedPreviousPolicyId = String(previousPolicyId || "").trim();
  if (normalizedPreviousPolicyId) {
    policy.previousPolicyId = normalizedPreviousPolicyId;
    policy.previousPolicyIdManuallyEdited = manuallyEdited === true;
  } else {
    delete policy.previousPolicyId;
    delete policy.previousPolicyIdManuallyEdited;
  }
}

function createRenewalManualTrackingContext(policyRecords = policies) {
  const policiesById = new Map();
  const predecessorIdsWithSuccessors = new Set();
  for (const policy of policyRecords) {
    policiesById.set(policy.id, policy);
    if (policy.previousPolicyId) predecessorIdsWithSuccessors.add(policy.previousPolicyId);
  }
  return { policiesById, predecessorIdsWithSuccessors };
}

function isRenewalStatusManuallyEdited(policy, trackingContext = null) {
  if (!policy?.renewalStatus) return false;
  if (Object.prototype.hasOwnProperty.call(policy, "renewalStatusManuallyEdited")) {
    return policy.renewalStatusManuallyEdited === true;
  }
  
  
  if (policy.renewalStatus === "not-renewed") return true;
  const context = trackingContext || createRenewalManualTrackingContext();
  return policy.renewalStatus === "renewed"
    && !context.predecessorIdsWithSuccessors.has(policy.id);
}

function isRenewalPredecessorManuallyEdited(policy, trackingContext = null) {
  if (!policy?.previousPolicyId) return false;
  if (Object.prototype.hasOwnProperty.call(policy, "previousPolicyIdManuallyEdited")) {
    return policy.previousPolicyIdManuallyEdited === true;
  }
  
  
  
  const context = trackingContext || createRenewalManualTrackingContext();
  const previousPolicy = context.policiesById.get(policy.previousPolicyId);
  return Boolean(previousPolicy) && getRenewalPairScore(previousPolicy, policy) === null;
}







function createRenewalLinkContext() {
  const manualTracking = createRenewalManualTrackingContext();
  const { policiesById } = manualTracking;
  const claimedPreviousIds = new Set();
  for (const policy of policies) {
    if (!policy.previousPolicyId) continue;
    const linkedPrevious = policiesById.get(policy.previousPolicyId);
    if (
      linkedPrevious
      && (
        getRenewalPairScore(linkedPrevious, policy) !== null
        || isRenewalPredecessorManuallyEdited(policy, manualTracking)
      )
    ) {
      claimedPreviousIds.add(linkedPrevious.id);
    }
  }
  const candidatesBySubject = new Map();
  for (const policy of policies) {
    const subjectKey = getRenewalSubjectKey(policy);
    if (!subjectKey) continue;
    const group = candidatesBySubject.get(subjectKey);
    if (group) group.push(policy);
    else candidatesBySubject.set(subjectKey, [policy]);
  }
  return { claimedPreviousIds, candidatesBySubject, manualTracking };
}




function findBestRenewalPredecessor(currentPolicy, linkContext = null) {
  const subjectKey = getRenewalSubjectKey(currentPolicy);
  if (!subjectKey) return null;
  const context = linkContext || createRenewalLinkContext();
  const manualTracking = context.manualTracking || createRenewalManualTrackingContext();
  const candidates = (context.candidatesBySubject.get(subjectKey) || [])
    .filter((candidate) => candidate.id !== currentPolicy.id
      && !context.claimedPreviousIds.has(candidate.id)
      && !(
        candidate.renewalStatus === "not-renewed"
        && isRenewalStatusManuallyEdited(candidate, manualTracking)
      ))
    .map((candidate) => ({ candidate, score: getRenewalPairScore(candidate, currentPolicy) }))
    .filter((entry) => entry.score !== null)
    .sort((first, second) => second.score - first.score);
  return candidates[0]?.candidate || null;
}

function findBestRenewalSuccessor(previousPolicy) {
  const manualTracking = createRenewalManualTrackingContext();
  if (
    previousPolicy?.renewalStatus === "not-renewed"
    && isRenewalStatusManuallyEdited(previousPolicy, manualTracking)
  ) return null;
  const manualSuccessor = policies.find(
    (policy) => policy.previousPolicyId === previousPolicy.id
      && isRenewalPredecessorManuallyEdited(policy, manualTracking),
  );
  if (manualSuccessor) return manualSuccessor;
  const existingSuccessor = policies.find(
    (policy) => policy.previousPolicyId === previousPolicy.id
      && getRenewalPairScore(previousPolicy, policy) !== null,
  );
  if (existingSuccessor) return existingSuccessor;
  const candidates = policies
    .filter((candidate) => candidate.id !== previousPolicy.id)
    .filter((candidate) => {
      if (!candidate.previousPolicyId) return true;
      if (isRenewalPredecessorManuallyEdited(candidate, manualTracking)) return false;
      const linkedPrevious = policies.find((policy) => policy.id === candidate.previousPolicyId);
      return !linkedPrevious || getRenewalPairScore(linkedPrevious, candidate) === null;
    })
    .map((candidate) => ({ candidate, score: getRenewalPairScore(previousPolicy, candidate) }))
    .filter((entry) => entry.score !== null)
    .sort((first, second) => second.score - first.score);
  return candidates[0]?.candidate || null;
}

function capturePolicyMutationState(states, policy) {
  if (!policy || states.has(policy.id)) return;
  states.set(policy.id, {
    policy,
    hasRenewalStatus: Object.prototype.hasOwnProperty.call(policy, "renewalStatus"),
    renewalStatus: policy.renewalStatus,
    hasRenewalStatusManuallyEdited: Object.prototype.hasOwnProperty.call(
      policy,
      "renewalStatusManuallyEdited",
    ),
    renewalStatusManuallyEdited: policy.renewalStatusManuallyEdited,
    hasPreviousPolicyId: Object.prototype.hasOwnProperty.call(policy, "previousPolicyId"),
    previousPolicyId: policy.previousPolicyId,
    hasPreviousPolicyIdManuallyEdited: Object.prototype.hasOwnProperty.call(
      policy,
      "previousPolicyIdManuallyEdited",
    ),
    previousPolicyIdManuallyEdited: policy.previousPolicyIdManuallyEdited,
    hasFirstRegistrationDate: Object.prototype.hasOwnProperty.call(policy, "firstRegistrationDate"),
    firstRegistrationDate: policy.firstRegistrationDate,
    hasVin: Object.prototype.hasOwnProperty.call(policy, "vin"),
    vin: policy.vin,
    hasContact: Object.prototype.hasOwnProperty.call(policy, "contact"),
    contact: policy.contact,
    importedPolicyTracking: captureImportedPolicyTrackingRollbackState(policy),
    hasUpdatedAt: Object.prototype.hasOwnProperty.call(policy, "updatedAt"),
    updatedAt: policy.updatedAt,
  });
}

function restorePolicyMutationStates(states) {
  states.forEach((state) => {
    if (!policies.includes(state.policy)) return;
    if (state.hasRenewalStatus) state.policy.renewalStatus = state.renewalStatus;
    else delete state.policy.renewalStatus;
    if (state.hasRenewalStatusManuallyEdited) {
      state.policy.renewalStatusManuallyEdited = state.renewalStatusManuallyEdited;
    } else {
      delete state.policy.renewalStatusManuallyEdited;
    }
    if (state.hasPreviousPolicyId) state.policy.previousPolicyId = state.previousPolicyId;
    else delete state.policy.previousPolicyId;
    if (state.hasPreviousPolicyIdManuallyEdited) {
      state.policy.previousPolicyIdManuallyEdited = state.previousPolicyIdManuallyEdited;
    } else {
      delete state.policy.previousPolicyIdManuallyEdited;
    }
    if (state.hasFirstRegistrationDate) state.policy.firstRegistrationDate = state.firstRegistrationDate;
    else delete state.policy.firstRegistrationDate;
    if (state.hasVin) state.policy.vin = state.vin;
    else delete state.policy.vin;
    if (state.hasContact) state.policy.contact = state.contact;
    else delete state.policy.contact;
    restoreImportedPolicyTrackingRollbackState(state.policy, state.importedPolicyTracking);
    if (state.hasUpdatedAt) state.policy.updatedAt = state.updatedAt;
    else delete state.policy.updatedAt;
  });
}










function splitRenewalGroupByClient(group) {
  if (group.length <= 2) return [group];
  const parents = new Map();
  const findRoot = (key) => {
    let root = key;
    while (parents.get(root) !== root) root = parents.get(root);
    let cursor = key;
    while (parents.get(cursor) !== cursor) {
      const next = parents.get(cursor);
      parents.set(cursor, root);
      cursor = next;
    }
    return root;
  };
  const unionKeys = (first, second) => {
    const firstRoot = findRoot(first);
    const secondRoot = findRoot(second);
    if (firstRoot !== secondRoot) parents.set(firstRoot, secondRoot);
  };
  group.forEach((policy, index) => {
    const memberKey = `#${index}`;
    parents.set(memberKey, memberKey);
    const client = getRenewalClientMatch(policy);
    for (const clientKey of [
      client.identityNumber && `id\u0000${client.identityNumber}`,
      client.clientName && `nm\u0000${client.clientName}`,
    ]) {
      if (!clientKey) continue;
      if (!parents.has(clientKey)) parents.set(clientKey, clientKey);
      unionKeys(memberKey, clientKey);
    }
  });
  const subgroups = new Map();
  group.forEach((policy, index) => {
    const root = findRoot(`#${index}`);
    const subgroup = subgroups.get(root);
    if (subgroup) subgroup.push(policy);
    else subgroups.set(root, [policy]);
  });
  return [...subgroups.values()];
}

function getRenewalVerificationPlan() {
  const manualTracking = createRenewalManualTrackingContext();
  const predecessorByCurrentId = new Map();
  const claimedPreviousIds = new Set();
  
  
  
  for (const currentPolicy of policies) {
    const previousPolicy = manualTracking.policiesById.get(currentPolicy.previousPolicyId);
    if (
      !previousPolicy
      || previousPolicy.id === currentPolicy.id
      || !isRenewalPredecessorManuallyEdited(currentPolicy, manualTracking)
    ) continue;
    predecessorByCurrentId.set(currentPolicy.id, previousPolicy.id);
    claimedPreviousIds.add(previousPolicy.id);
  }

  
  
  
  
  const groupsBySubject = new Map();
  for (const policy of policies) {
    if (isTravelPolicy(policy)) continue;
    const subjectKey = getRenewalSubjectKey(policy);
    if (!subjectKey) continue;
    const group = groupsBySubject.get(subjectKey);
    if (group) group.push(policy);
    else groupsBySubject.set(subjectKey, [policy]);
  }

  const candidates = [];
  for (const group of groupsBySubject.values()) {
    for (const clientGroup of splitRenewalGroupByClient(group)) {
      for (const currentPolicy of clientGroup) {
        if (predecessorByCurrentId.has(currentPolicy.id)) continue;
        for (const previousPolicy of clientGroup) {
          if (
            previousPolicy.renewalStatus === "not-renewed"
            && isRenewalStatusManuallyEdited(previousPolicy, manualTracking)
          ) continue;
          const score = getRenewalPairScore(previousPolicy, currentPolicy);
          if (score === null) continue;
          candidates.push({
            previousPolicy,
            currentPolicy,
            score,
            existing: currentPolicy.previousPolicyId === previousPolicy.id,
          });
        }
      }
    }
  }

  candidates.sort((first, second) => {
    const existingDifference = Number(second.existing) - Number(first.existing);
    if (existingDifference !== 0) return existingDifference;
    const scoreDifference = second.score - first.score;
    if (scoreDifference !== 0) return scoreDifference;
    const currentDateDifference = (parseLocalDate(first.currentPolicy.validUntil)?.getTime() || 0)
      - (parseLocalDate(second.currentPolicy.validUntil)?.getTime() || 0);
    if (currentDateDifference !== 0) return currentDateDifference;
    return String(first.currentPolicy.id).localeCompare(String(second.currentPolicy.id));
  });

  for (const candidate of candidates) {
    if (
      predecessorByCurrentId.has(candidate.currentPolicy.id)
      || claimedPreviousIds.has(candidate.previousPolicy.id)
    ) continue;
    predecessorByCurrentId.set(candidate.currentPolicy.id, candidate.previousPolicy.id);
    claimedPreviousIds.add(candidate.previousPolicy.id);
  }
  return predecessorByCurrentId;
}

function getRenewalVerificationChangeCount() {
  const manualTracking = createRenewalManualTrackingContext();
  const predecessorByCurrentId = getRenewalVerificationPlan();
  const renewedPolicyIds = new Set(predecessorByCurrentId.values());
  const changedPolicyIds = new Set();
  for (const currentPolicy of policies) {
    const desiredPreviousId = predecessorByCurrentId.get(currentPolicy.id) || null;
    const currentPreviousId = currentPolicy.previousPolicyId || null;
    if (currentPreviousId !== desiredPreviousId) changedPolicyIds.add(currentPolicy.id);
  }
  for (const policy of policies) {
    if (isRenewalStatusManuallyEdited(policy, manualTracking)) continue;
    const shouldBeRenewed = renewedPolicyIds.has(policy.id);
    if (shouldBeRenewed && policy.renewalStatus !== "renewed") changedPolicyIds.add(policy.id);
    if (!shouldBeRenewed && policy.renewalStatus === "renewed") changedPolicyIds.add(policy.id);
  }
  return changedPolicyIds.size;
}

function applyRenewalVerification(mutationStates = new Map()) {
  const manualTracking = createRenewalManualTrackingContext();
  const predecessorByCurrentId = getRenewalVerificationPlan();
  const renewedPolicyIds = new Set(predecessorByCurrentId.values());
  const changedAt = Date.now();
  for (const currentPolicy of policies) {
    const desiredPreviousId = predecessorByCurrentId.get(currentPolicy.id) || null;
    const currentPreviousId = currentPolicy.previousPolicyId || null;
    if (currentPreviousId === desiredPreviousId) continue;
    capturePolicyMutationState(mutationStates, currentPolicy);
    setPolicyRenewalPredecessor(currentPolicy, desiredPreviousId, false);
    currentPolicy.updatedAt = changedAt;
  }
  for (const policy of policies) {
    if (isRenewalStatusManuallyEdited(policy, manualTracking)) continue;
    const shouldBeRenewed = renewedPolicyIds.has(policy.id);
    if (shouldBeRenewed && policy.renewalStatus !== "renewed") {
      capturePolicyMutationState(mutationStates, policy);
      setPolicyRenewalStatusValue(policy, "renewed", false);
      policy.updatedAt = changedAt;
    } else if (!shouldBeRenewed && policy.renewalStatus === "renewed") {
      capturePolicyMutationState(mutationStates, policy);
      setPolicyRenewalStatusValue(policy, null, false);
      policy.updatedAt = changedAt;
    }
  }
  return predecessorByCurrentId.size;
}

function linkPolicyToBestRenewalPredecessor(currentPolicy, mutationStates = new Map(), linkContext = null) {
  if (isTravelPolicy(currentPolicy)) return null;
  const manualTracking = linkContext?.manualTracking || createRenewalManualTrackingContext();
  const linkedPrevious = manualTracking.policiesById.get(currentPolicy.previousPolicyId);
  const existingPrevious = linkedPrevious && (
    isRenewalPredecessorManuallyEdited(currentPolicy, manualTracking)
    || getRenewalPairScore(linkedPrevious, currentPolicy) !== null
  ) ? linkedPrevious : null;
  if (currentPolicy.previousPolicyId && !existingPrevious) {
    capturePolicyMutationState(mutationStates, currentPolicy);
    setPolicyRenewalPredecessor(currentPolicy, null, false);
    currentPolicy.updatedAt = Date.now();
  }
  const previousPolicy = existingPrevious || findBestRenewalPredecessor(currentPolicy, linkContext);
  if (!previousPolicy) return null;
  
  
  linkContext?.claimedPreviousIds.add(previousPolicy.id);
  if (currentPolicy.previousPolicyId !== previousPolicy.id) {
    capturePolicyMutationState(mutationStates, currentPolicy);
    setPolicyRenewalPredecessor(currentPolicy, previousPolicy.id, false);
    currentPolicy.updatedAt = Date.now();
  }
  if (
    previousPolicy.renewalStatus !== "renewed"
    && !isRenewalStatusManuallyEdited(previousPolicy, manualTracking)
  ) {
    capturePolicyMutationState(mutationStates, previousPolicy);
    setPolicyRenewalStatusValue(previousPolicy, "renewed", false);
    previousPolicy.updatedAt = Date.now();
  }
  return previousPolicy;
}

function linkRenewalSuccessor(previousPolicy, mutationStates = new Map()) {
  if (isTravelPolicy(previousPolicy)) return null;
  const successor = findBestRenewalSuccessor(previousPolicy);
  if (!successor) return null;
  if (successor.previousPolicyId !== previousPolicy.id) {
    capturePolicyMutationState(mutationStates, successor);
    setPolicyRenewalPredecessor(successor, previousPolicy.id, false);
    successor.updatedAt = Date.now();
  }
  return successor;
}

function unlinkRenewalSuccessors(previousPolicy, mutationStates = new Map()) {
  const successors = policies.filter((policy) => policy.previousPolicyId === previousPolicy.id);
  successors.forEach((successor) => {
    capturePolicyMutationState(mutationStates, successor);
    setPolicyRenewalPredecessor(successor, null, false);
    successor.updatedAt = Date.now();
  });
  return successors;
}

function detachRemovedPolicyRenewalRelationships(removedPolicy, mutationStates = new Map()) {
  if (!removedPolicy) return mutationStates;
  const changedAt = Date.now();
  const manualTracking = createRenewalManualTrackingContext();
  const removedLinkWasManual = isRenewalPredecessorManuallyEdited(
    removedPolicy,
    manualTracking,
  );

  policies
    .filter((policy) => policy.id !== removedPolicy.id && policy.previousPolicyId === removedPolicy.id)
    .forEach((successor) => {
      capturePolicyMutationState(mutationStates, successor);
      setPolicyRenewalPredecessor(successor, null, false);
      successor.updatedAt = changedAt;
    });

  const previousPolicy = policies.find(
    (policy) => policy.id !== removedPolicy.id && policy.id === removedPolicy.previousPolicyId,
  );
  if (!previousPolicy) return mutationStates;
  const hasAnotherSuccessor = policies.some(
    (policy) => policy.id !== removedPolicy.id
      && policy.previousPolicyId === previousPolicy.id
      && getRenewalPairScore(previousPolicy, policy) !== null,
  );
  if (
    !hasAnotherSuccessor
    && previousPolicy.renewalStatus === "renewed"
    && !removedLinkWasManual
    && !isRenewalStatusManuallyEdited(previousPolicy, manualTracking)
  ) {
    capturePolicyMutationState(mutationStates, previousPolicy);
    setPolicyRenewalStatusValue(previousPolicy, null, false);
    previousPolicy.updatedAt = changedAt;
  }
  return mutationStates;
}

function reconnectPolicyRenewalRelationships(policy, mutationStates = new Map()) {
  if (!policy || isTravelPolicy(policy)) return null;
  const previousPolicy = linkPolicyToBestRenewalPredecessor(policy, mutationStates);
  const successor = linkRenewalSuccessor(policy, mutationStates);
  if (
    successor
    && policy.renewalStatus !== "renewed"
    && !isRenewalStatusManuallyEdited(policy)
  ) {
    capturePolicyMutationState(mutationStates, policy);
    setPolicyRenewalStatusValue(policy, "renewed", false);
    policy.updatedAt = Date.now();
  }
  return { previousPolicy, successor };
}




let renewalRelationIndexCache = null;

function getRenewalRelationIndex() {
  if (!renewalRelationIndexCache) {
    const policiesById = new Map();
    const successorsByPreviousId = new Map();
    for (const policy of policies) {
      policiesById.set(policy.id, policy);
      if (!policy.previousPolicyId) continue;
      const group = successorsByPreviousId.get(policy.previousPolicyId);
      if (group) group.push(policy);
      else successorsByPreviousId.set(policy.previousPolicyId, [policy]);
    }
    renewalRelationIndexCache = { policiesById, successorsByPreviousId };
  }
  return renewalRelationIndexCache;
}

function getRenewalRelationMarkup(policy) {
  if (isTravelPolicy(policy)) return "";
  const { policiesById, successorsByPreviousId } = getRenewalRelationIndex();
  const linkedPrevious = policy.previousPolicyId ? policiesById.get(policy.previousPolicyId) : undefined;
  const previousPolicy = linkedPrevious && getRenewalPairScore(linkedPrevious, policy) !== null
    ? linkedPrevious
    : undefined;
  const successor = (successorsByPreviousId.get(policy.id) || []).find(
    (candidate) => getRenewalPairScore(policy, candidate) !== null,
  );
  const relations = [];
  if (previousPolicy?.policyNumber) {
    const safePreviousPolicyNumber = escapeHtml(previousPolicy.policyNumber);
    relations.push(`<button class="renewal-relation" type="button" data-action="search-related-policy" data-policy-number="${safePreviousPolicyNumber}" aria-label="Pokaż ubiegłoroczną polisę ${safePreviousPolicyNumber}"><span>Ubiegłoroczna</span><span>${safePreviousPolicyNumber}</span></button>`);
  }
  if (successor?.policyNumber) {
    const safeSuccessorPolicyNumber = escapeHtml(successor.policyNumber);
    relations.push(`<button class="renewal-relation renewal-relation--next" type="button" data-action="search-related-policy" data-policy-number="${safeSuccessorPolicyNumber}" aria-label="Pokaż wznowienie ${safeSuccessorPolicyNumber}"><span>Wznowienie</span><span>${safeSuccessorPolicyNumber}</span></button>`);
  }
  return relations.join("");
}

function isDueForRenewal(policy) {
  if (isTravelPolicy(policy)) return false;
  
  if (POLICY_BUYER_TRANSFER_FEATURE_ENABLED && policy?.transferredToBuyer === true) return false;
  
  if (policy?.vehicleSold === true) return false;
  const days = daysFromToday(policy.validUntil);
  const earliestVisibleDay = renewalShowExpired ? -RENEWAL_PAST_DAYS : 0;
  return days !== null && days >= earliestVisibleDay && days <= renewalWindowDays;
}

function isRenewalPending(policy) {
  return isDueForRenewal(policy) && !policy.renewalStatus;
}

function formatDate(dateString) {
  const date = parseLocalDate(dateString);
  if (!date) return "-";
  return SHORT_DATE_FORMAT.format(date);
}

function hasRegistrationNumber(policy) {
  const registration = String(policy?.registration ?? "").trim();
  return Boolean(registration) && getPolicyTypeIndex(registration) < 0;
}

function formatTerminationInsurancePeriod(policy) {
  const validFrom = formatStartDate(policy);
  const validUntil = formatDate(policy.validUntil);
  if (validFrom === "-" && validUntil === "-") return "";
  if (validFrom === "-") return `do ${validUntil}`;
  if (validUntil === "-") return `od ${validFrom}`;
  return `od ${validFrom} do ${validUntil}`;
}

function decodeBase64Bytes(value) {
  const binary = globalThis.atob(String(value ?? ""));
  const bytes = new Uint8Array(binary.length);
  for (let index = 0; index < binary.length; index += 1) {
    bytes[index] = binary.charCodeAt(index);
  }
  return bytes;
}

function normalizeTerminationType(terminationType) {
  return TERMINATION_PDF_TEMPLATE_URLS[terminationType] ? terminationType : "koniec";
}

async function loadTerminationPdfTemplate(terminationType) {
  const templateType = normalizeTerminationType(terminationType);
  if (!terminationPdfTemplatePromises.has(templateType)) {
    const templatePromise = (async () => {
      try {
        const response = await globalThis.fetch(TERMINATION_PDF_TEMPLATE_URLS[templateType], { cache: "no-store" });
        if (response.ok) return new Uint8Array(await response.arrayBuffer());
      } catch {
      }

      const embeddedTemplate = globalThis.TERMINATION_PDF_TEMPLATES_BASE64?.[templateType];
      if (embeddedTemplate) return decodeBase64Bytes(embeddedTemplate);
      throw new Error("Nie udało się wczytać wzoru wypowiedzenia.");
    })().catch((error) => {
      terminationPdfTemplatePromises.delete(templateType);
      throw error;
    });
    terminationPdfTemplatePromises.set(templateType, templatePromise);
  }
  return terminationPdfTemplatePromises.get(templateType);
}

function createPdfFieldTextImage(text, maxWidth, fontSize = 10) {
  const scale = 4;
  const canvas = document.createElement("canvas");
  const context = canvas.getContext("2d");
  if (!context) throw new Error("Przeglądarka nie może przygotować tekstu do PDF.");

  const value = String(text ?? "").trim();
  let fittedFontSize = fontSize;
  context.font = `400 ${fittedFontSize * scale}px Arial, sans-serif`;
  const availablePixelWidth = Math.max(1, (maxWidth - 4) * scale);
  const measuredWidth = context.measureText(value).width;
  if (measuredWidth > availablePixelWidth) {
    fittedFontSize = Math.max(6, fittedFontSize * (availablePixelWidth / measuredWidth));
  }

  context.font = `400 ${fittedFontSize * scale}px Arial, sans-serif`;
  const textWidth = Math.min(context.measureText(value).width, availablePixelWidth);
  canvas.width = Math.max(1, Math.ceil(textWidth + (4 * scale)));
  canvas.height = Math.max(1, Math.ceil((fontSize + 4) * scale));

  const drawContext = canvas.getContext("2d");
  drawContext.clearRect(0, 0, canvas.width, canvas.height);
  drawContext.fillStyle = "#000000";
  drawContext.font = `400 ${fittedFontSize * scale}px Arial, sans-serif`;
  drawContext.textBaseline = "middle";
  drawContext.fillText(value, 2 * scale, canvas.height / 2, availablePixelWidth);

  return {
    dataUrl: canvas.toDataURL("image/png"),
    width: canvas.width / scale,
    height: canvas.height / scale,
  };
}

async function placeTextInTerminationField(pdfDocument, form, page, fieldName, value) {
  const field = form.getTextField(fieldName);
  const widget = field.acroField.getWidgets()[0];
  const rectangle = widget?.getRectangle();
  if (!rectangle) throw new Error(`Brak położenia pola „${fieldName}” w PDF.`);

  const normalizedValue = String(value ?? "").trim();
  if (normalizedValue) {
    const textImage = createPdfFieldTextImage(normalizedValue, rectangle.width);
    const embeddedImage = await pdfDocument.embedPng(textImage.dataUrl);
    page.drawImage(embeddedImage, {
      x: rectangle.x,
      y: rectangle.y + Math.max(0, (rectangle.height - textImage.height) / 2),
      width: Math.min(textImage.width, rectangle.width),
      height: Math.min(textImage.height, rectangle.height),
    });
  }

}


function formatTerminationVehicle(policy) {
  const vehicleName = [policy?.vehicleMake, policy?.vehicleModel].filter(Boolean).join(" ").trim();
  return [vehicleName, String(policy?.registration ?? "").trim()].filter(Boolean).join(", ");
}

async function createFilledTerminationPdf(policy, terminationDetails) {
  if (!globalThis.PDFLib?.PDFDocument) {
    throw new Error("Brakuje lokalnego modułu do obsługi PDF.");
  }

  const terminationType = normalizeTerminationType(terminationDetails?.terminationType);
  const templateBytes = await loadTerminationPdfTemplate(terminationType);
  const pdfDocument = await globalThis.PDFLib.PDFDocument.load(templateBytes);
  const form = pdfDocument.getForm();
  const [page] = pdfDocument.getPages();
  const dateAndCity = [formatDate(terminationDetails?.signatureDate), terminationDetails?.city]
    .filter(Boolean)
    .join(", ");
  
  
  const signerName = terminationType === "nabywca" ? terminationDetails?.buyerName : policy.clientName;
  const fieldValues = [
    [TERMINATION_PDF_FIELD_NAMES.dateAndCity, dateAndCity],
    [TERMINATION_PDF_FIELD_NAMES.clientName, signerName],
    [TERMINATION_PDF_FIELD_NAMES.vehicle, formatTerminationVehicle(policy)],
    [TERMINATION_PDF_FIELD_NAMES.insurer, policy.insurer],
    [TERMINATION_PDF_FIELD_NAMES.policyNumber, policy.policyNumber],
    [TERMINATION_PDF_FIELD_NAMES.insurancePeriod, formatTerminationInsurancePeriod(policy)],
  ];

  for (const [fieldName, value] of fieldValues) {
    await placeTextInTerminationField(pdfDocument, form, page, fieldName, value);
  }

  page.node.delete(globalThis.PDFLib.PDFName.of("Annots"));
  pdfDocument.catalog.delete(globalThis.PDFLib.PDFName.of("AcroForm"));

  pdfDocument.setTitle(`${TERMINATION_PDF_TITLES[terminationType]} - ${policy.registration}`);
  pdfDocument.setSubject("Wypowiedzenie umowy ubezpieczenia OC");
  return pdfDocument.save({ useObjectStreams: false, updateFieldAppearances: false });
}

function finishTerminationDetailsSelection(terminationDetails = null) {
  const resolver = terminationDetailsResolver;
  terminationDetailsResolver = null;
  if (elements.terminationDateDialog.open) elements.terminationDateDialog.close();
  resolver?.(terminationDetails);
}

function getSelectedTerminationType() {
  const checkedInput = elements.terminationDateForm.querySelector('input[name="terminationType"]:checked');
  return normalizeTerminationType(checkedInput?.value);
}



function applyTerminationTypeToDialog() {
  elements.terminationBuyerField.hidden = getSelectedTerminationType() !== "nabywca";
}

function getSavedTerminationCity() {
  try {
    return String(localStorage.getItem(TERMINATION_CITY_KEY) ?? "").trim();
  } catch {
    return "";
  }
}

function rememberTerminationCity(city) {
  try {
    if (city) {
      localStorage.setItem(TERMINATION_CITY_KEY, city);
    } else {
      localStorage.removeItem(TERMINATION_CITY_KEY);
    }
  } catch {
  }
}

function getDefaultTerminationSignatureDate(policyEndDate) {
  const today = startOfToday();
  const endDate = parseLocalDate(policyEndDate);
  if (!endDate || today <= endDate) return today;

  const dayBeforePolicyEnd = new Date(endDate);
  dayBeforePolicyEnd.setDate(dayBeforePolicyEnd.getDate() - 1);
  return dayBeforePolicyEnd;
}

function requestTerminationDetails(policy) {
  if (terminationDetailsResolver) return Promise.resolve(null);

  const defaultTypeInput = elements.terminationDateForm.querySelector(
    'input[name="terminationType"][value="koniec"]',
  );
  if (defaultTypeInput) defaultTypeInput.checked = true;
  elements.terminationBuyerName.value = "";
  elements.terminationCity.value = getSavedTerminationCity();
  applyTerminationTypeToDialog();
  elements.terminationPolicyEndDate.textContent = formatDate(policy?.validUntil);
  elements.terminationSignatureDate.value = formatDateForInput(
    getDefaultTerminationSignatureDate(policy?.validUntil),
  );
  return new Promise((resolve) => {
    terminationDetailsResolver = resolve;
    elements.terminationDateDialog.showModal();
    requestAnimationFrame(() => elements.terminationSignatureDate.focus());
  });
}

function confirmTerminationDetails() {
  const terminationType = getSelectedTerminationType();
  const signatureDate = elements.terminationSignatureDate.value;
  if (!parseLocalDate(signatureDate)) {
    showToast("Wybierz poprawną datę podpisu", "error");
    elements.terminationSignatureDate.focus();
    return;
  }
  const city = elements.terminationCity.value.trim();
  const buyerName = elements.terminationBuyerName.value.trim();
  if (terminationType === "nabywca" && !buyerName) {
    showToast("Wpisz imię i nazwisko nabywcy pojazdu", "error");
    elements.terminationBuyerName.focus();
    return;
  }
  rememberTerminationCity(city);
  finishTerminationDetailsSelection({ terminationType, signatureDate, city, buyerName });
}

async function openTerminationNotice(policyId) {
  const policy = policies.find((item) => item.id === policyId);
  if (!policy || !hasRegistrationNumber(policy)) return;

  const terminationDetails = await requestTerminationDetails(policy);
  if (!terminationDetails) return;

  const previewWindow = globalThis.open("", "_blank");
  if (!previewWindow) {
    showToast("Przeglądarka zablokowała nowe okno z wypowiedzeniem");
    return;
  }

  showPreviewLoadingMessage(
    previewWindow,
    "Przygotowywanie wypowiedzenia…",
    "Przygotowywanie wypełnionego wypowiedzenia…",
    600,
  );

  try {
    const pdfBytes = await createFilledTerminationPdf(policy, terminationDetails);
    const pdfUrl = URL.createObjectURL(new Blob([pdfBytes], { type: "application/pdf" }));
    previewWindow.location.replace(pdfUrl);
    setTimeout(() => URL.revokeObjectURL(pdfUrl), 5 * 60 * 1000);
    showToast("Wypowiedzenie zostało uzupełnione");
  } catch (error) {
    previewWindow.close();
    showToast(error?.message || "Nie udało się przygotować wypowiedzenia");
  }
}

function calculateStartDate(validUntil) {
  const endDate = parseLocalDate(validUntil);
  if (!endDate) return null;

  const previousYear = endDate.getFullYear() - 1;
  const month = endDate.getMonth();
  const day = endDate.getDate();
  const lastDayInMonth = new Date(previousYear, month + 1, 0).getDate();
  const startDate = new Date(previousYear, month, Math.min(day, lastDayInMonth));
  startDate.setDate(startDate.getDate() + 1);
  return startDate;
}

function calculateEndDate(validFrom) {
  const startDate = parseLocalDate(validFrom);
  if (!startDate) return null;

  const endDate = new Date(startDate);
  endDate.setFullYear(startDate.getFullYear() + 1);
  endDate.setDate(endDate.getDate() - 1);
  return endDate;
}

function calculateTravelEndDate(validFrom) {
  const startDate = parseLocalDate(validFrom);
  if (!startDate) return null;
  const endDate = new Date(startDate);
  endDate.setDate(endDate.getDate() + 7);
  return endDate;
}

function calculateTravelStartDate(validUntil) {
  const endDate = parseLocalDate(validUntil);
  if (!endDate) return null;
  const startDate = new Date(endDate);
  startDate.setDate(startDate.getDate() - 7);
  return startDate;
}

function formatDateForInput(date) {
  if (!date) return "";
  const year = date.getFullYear();
  const month = String(date.getMonth() + 1).padStart(2, "0");
  const day = String(date.getDate()).padStart(2, "0");
  return `${year}-${month}-${day}`;
}

function updateAddFormEndDateForPolicyType() {
  const isTravelPolicy = isTravelPolicySelected();
  refreshAddFormStartDateVisibility();
  if (isTravelPolicy) {
    if (elements.startDateFormField.dataset.manuallyEdited === "true" && elements.validFromInput.value) {
      elements.validUntilInput.value = formatDateForInput(calculateTravelEndDate(elements.validFromInput.value));
      elements.validUntilInput.dataset.travelDerived = "true";
    } else {
      elements.validUntilInput.value = "";
      elements.validFromInput.value = "";
      delete elements.validUntilInput.dataset.travelDerived;
    }
    return;
  }
  if (elements.validUntilInput.dataset.travelDerived === "true") {
    elements.validUntilInput.value = "";
    delete elements.validUntilInput.dataset.travelDerived;
  }
  updateAddFormStartDateFromEnd();
}

function getPolicyStartDate(policy) {
  if (Object.prototype.hasOwnProperty.call(policy, "validFrom")) {
    const storedStartDate = parseLocalDate(policy.validFrom);
    if (storedStartDate) return storedStartDate;
  }
  return calculateStartDate(policy.validUntil);
}

function formatStartDate(policy) {
  const date = getPolicyStartDate(policy);
  if (!date) return "-";
  return SHORT_DATE_FORMAT.format(date);
}

function formatPremium(value) {
  const trimmed = String(value ?? "").trim();
  if (!trimmed) return "-";

  const numericValue = parsePremiumValue(trimmed);

  if (numericValue !== null) {
    return `${new Intl.NumberFormat("pl-PL", {
      minimumFractionDigits: 2,
      maximumFractionDigits: 2,
    }).format(numericValue)} zł`;
  }

  return trimmed;
}

function parsePremiumValue(value) {
  let numericText = String(value ?? "")
    .trim()
    .replace(/[\s\u00a0]/g, "")
    .replace(/zł/gi, "")
    .replace(/[^0-9,.-]/g, "");
  if (!numericText) return null;

  const isNegative = numericText.startsWith("-");
  numericText = numericText.replace(/-/g, "");
  const lastComma = numericText.lastIndexOf(",");
  const lastDot = numericText.lastIndexOf(".");
  if (lastComma >= 0 && lastDot >= 0) {
    const decimalPosition = Math.max(lastComma, lastDot);
    const integerPart = numericText.slice(0, decimalPosition).replace(/[.,]/g, "");
    const decimalPart = numericText.slice(decimalPosition + 1).replace(/[.,]/g, "");
    numericText = decimalPart ? `${integerPart}.${decimalPart}` : integerPart;
  } else {
    const separator = lastComma >= 0 ? "," : lastDot >= 0 ? "." : "";
    if (separator) {
      const parts = numericText.split(separator);
      const looksLikeThousands = parts.length > 1
        && parts.slice(1).every((part) => part.length === 3)
        && parts[0].length >= 1;
      if (looksLikeThousands) {
        numericText = parts.join("");
      } else {
        const decimalPart = parts.pop() || "";
        const integerPart = parts.join("");
        numericText = decimalPart ? `${integerPart}.${decimalPart}` : integerPart;
      }
    }
  }
  if (isNegative) numericText = `-${numericText}`;

  const numericValue = Number(numericText);
  return Number.isNaN(numericValue) ? null : numericValue;
}

function compareAlphabetically(firstValue, secondValue) {
  const firstText = String(firstValue ?? "").trim();
  const secondText = String(secondValue ?? "").trim();
  if (!firstText && !secondText) return 0;
  if (!firstText) return 1;
  if (!secondText) return -1;
  return firstText.localeCompare(secondText, "pl", { sensitivity: "base", numeric: true });
}

function getPolicyTypeIndex(value) {
  const normalizedValue = normalize(value);
  return REGISTRATION_SUGGESTIONS.findIndex((policyType) => normalize(policyType) === normalizedValue);
}




function getInsurerSortGroups(policyList) {
  const configuredNames = new Map();
  for (const insurer of getServedInsurerSettings()) {
    const nameKey = normalize(insurer.name);
    if (nameKey && !configuredNames.has(nameKey)) configuredNames.set(nameKey, insurer.name);
  }
  const groupsByKey = new Map();
  for (const policy of policyList) {
    const rawName = String(policy.insurer ?? "").trim();
    if (!rawName) continue;
    const key = normalize(rawName);
    if (!key || groupsByKey.has(key) || !isInsurerServed(rawName)) continue;
    groupsByKey.set(key, configuredNames.get(key) || rawName);
  }
  return [...groupsByKey.entries()]
    .map(([key, label]) => ({ key, label }))
    .sort((first, second) => compareAlphabetically(first.label, second.label));
}

const REGISTRATION_GROUP_LABEL = "Nr rejestracyjne";




function getRegistrationSortGroups(policyList) {
  let hasRegistrationNumbers = false;
  const presentTypeIndexes = new Set();
  for (const policy of policyList) {
    const text = String(policy.registration ?? "").trim();
    if (!text) continue;
    const typeIndex = getPolicyTypeIndex(text);
    if (typeIndex >= 0) presentTypeIndexes.add(typeIndex);
    else hasRegistrationNumbers = true;
  }
  const groups = [];
  if (hasRegistrationNumbers) groups.push({ token: "registration", label: REGISTRATION_GROUP_LABEL });
  REGISTRATION_SUGGESTIONS.forEach((typeName, typeIndex) => {
    if (presentTypeIndexes.has(typeIndex)) groups.push({ token: `type:${typeIndex}`, label: typeName });
  });
  return groups;
}

function getRegistrationGroupToken(registration) {
  const text = String(registration ?? "").trim();
  if (!text) return null;
  const typeIndex = getPolicyTypeIndex(text);
  return typeIndex >= 0 ? `type:${typeIndex}` : "registration";
}


function setSortCycleValue(button, label) {
  const valueElement = button.querySelector(".sort-cycle-value");
  if (!valueElement) return;
  valueElement.textContent = label;
  valueElement.hidden = !label;
}

function getPolicyStatus(dateString) {
  const days = daysFromToday(dateString);
  if (days === null) return { label: "Brak daty", modifier: "unknown" };
  if (days < 0) return { label: "Po terminie", modifier: "expired" };
  if (days <= renewalWindowDays) return { label: "Wkrótce", modifier: "soon" };
  return { label: "Aktywna", modifier: "active" };
}

function isPolicyActive(policy) {
  const days = daysFromToday(policy?.validUntil);
  return days !== null && days >= 0;
}



function isPolicyExpired(policy) {
  const days = daysFromToday(policy?.validUntil);
  return days !== null && days < 0;
}

function isPolicyHiddenByVisibilityToggles(policy) {
  if (hideRenewedPolicies && policy.renewalStatus === "renewed") return true;
  if (hideInactivePolicies && isPolicyExpired(policy)) return true;
  return false;
}

const MINIMUM_SEARCH_QUERY_LENGTH = 2;



const SEARCH_EMAIL_PATTERN = /[\w.!#$%&'*+/=?^`{|}~-]+@[a-z0-9-]+(?:\.[a-z0-9-]+)+/gi;

function getEffectiveSearchQuery() {
  const query = normalize(elements.search.value);
  return query.length >= MINIMUM_SEARCH_QUERY_LENGTH ? query : "";
}

function getVisiblePolicies() {
  const query = getEffectiveSearchQuery();
  const searchTerms = query.split(/[\s,;]+/).filter(Boolean);
  const dateFrom = parseLocalDate(elements.dateFilterFrom.value);
  const dateTo = parseLocalDate(elements.dateFilterTo.value);
  const directionMultiplier = sortDirection === "desc" ? -1 : 1;
  let visible = policies.filter((policy) => !renewalsOnly || isDueForRenewal(policy));
  visible = visible.filter((policy) => !isPolicyHiddenByVisibilityToggles(policy));
  
  if (activeProfileFilter) {
    visible = visible.filter((policy) => getPolicyOwnerIdForFiltering(policy) === activeProfileFilter);
  }
  
  
  
  if (renewalsOnly && agencyMembers.length > 0 && renewalOwnerExclusions.size > 0) {
    visible = visible.filter((policy) => !renewalOwnerExclusions.has(getPolicyOwnerIdForFiltering(policy)));
  }

  if (dateFrom || dateTo) {
    visible = visible.filter((policy) => {
      const policyDate = getPolicyStartDate(policy);
      if (!policyDate) return false;
      if (dateFrom && policyDate < dateFrom) return false;
      if (dateTo && policyDate > dateTo) return false;
      return true;
    });
  }

  
  
  
  const emailOnlySearchMatches = new Set();
  visible = visible.filter((policy) => {
    if (searchTerms.length === 0) return true;
    const contact = String(policy.contact ?? "");
    const toSearchEntries = (values) => values.map(getSearchEntry);
    const primaryFields = toSearchEntries([
      policy.clientName,
      policy.identityNumber,
      policy.secondaryIdentityNumber,
      ...(POLICY_BUYER_TRANSFER_FEATURE_ENABLED
        ? [policy.buyerName, policy.buyerIdentityNumber]
        : []),
      policy.clientPhone,
      policy.clientAddress,
      contact.replace(SEARCH_EMAIL_PATTERN, " "),
      policy.insurer,
      policy.policyNumber,
      policy.registration,
      formatStartDate(policy),
      formatDate(policy.validUntil),
      policy.validUntil,
      policy.premium,
      ...normalizePolicyAttachments(policy.attachments).map((attachment) => attachment.name),
    ]);
    const emailFields = toSearchEntries([
      policy.clientEmail,
      ...(contact.match(SEARCH_EMAIL_PATTERN) ?? []),
    ]);
    const matchesAny = (entries, term, compactTerm) => entries.some(({ value, compactValue }) => (
      value.includes(term)
      || (compactTerm.length > 0 && compactValue.includes(compactTerm))
    ));
    let matchedOnlyByEmail = false;
    for (const term of searchTerms) {
      const compactTerm = term.replace(/[^a-z0-9]/g, "");
      if (matchesAny(primaryFields, term, compactTerm)) continue;
      if (!matchesAny(emailFields, term, compactTerm)) return false;
      matchedOnlyByEmail = true;
    }
    if (matchedOnlyByEmail) emailOnlySearchMatches.add(policy);
    return true;
  });

  if (sortMode === "date") {
    visible = [...visible].sort((first, second) => {
      const firstDate = parseLocalDate(first.validUntil);
      const secondDate = parseLocalDate(second.validUntil);
      if (!firstDate && !secondDate) return (Number(second.createdAt) || 0) - (Number(first.createdAt) || 0);
      if (!firstDate) return 1;
      if (!secondDate) return -1;
      const dateDifference = firstDate.getTime() - secondDate.getTime();
      return dateDifference !== 0
        ? dateDifference * directionMultiplier
        : (Number(second.createdAt) || 0) - (Number(first.createdAt) || 0);
    });
  } else if (sortMode === "startDate") {
    visible = [...visible].sort((first, second) => {
      const firstDate = getPolicyStartDate(first);
      const secondDate = getPolicyStartDate(second);
      if (!firstDate && !secondDate) return (Number(second.createdAt) || 0) - (Number(first.createdAt) || 0);
      if (!firstDate) return 1;
      if (!secondDate) return -1;
      const dateDifference = firstDate.getTime() - secondDate.getTime();
      return dateDifference !== 0
        ? dateDifference * directionMultiplier
        : (Number(second.createdAt) || 0) - (Number(first.createdAt) || 0);
    });
  } else if (sortMode === "premium") {
    visible = [...visible].sort((first, second) => {
      const firstPremium = parsePremiumValue(first.premium);
      const secondPremium = parsePremiumValue(second.premium);
      if (firstPremium === null && secondPremium === null) return (Number(second.createdAt) || 0) - (Number(first.createdAt) || 0);
      if (firstPremium === null) return 1;
      if (secondPremium === null) return -1;
      const premiumDifference = firstPremium - secondPremium;
      return premiumDifference !== 0
        ? premiumDifference * directionMultiplier
        : (Number(second.createdAt) || 0) - (Number(first.createdAt) || 0);
    });
  } else if (sortMode === "clientName") {
    visible = [...visible].sort((first, second) => {
      const alphabeticalDifference = compareAlphabetically(first.clientName, second.clientName);
      return alphabeticalDifference !== 0
        ? alphabeticalDifference * directionMultiplier
        : (Number(second.createdAt) || 0) - (Number(first.createdAt) || 0);
    });
  } else if (sortMode === "insurer") {
    
    
    const insurerGroups = getInsurerSortGroups(visible);
    const groupCount = insurerGroups.length;
    const rankByInsurerKey = new Map(insurerGroups.map((group, index) => [group.key, index]));
    const selectedRank = insurerSortSelection ? rankByInsurerKey.get(insurerSortSelection.key) : undefined;
    const policyRanks = new Map(visible.map((policy) => {
      const rank = rankByInsurerKey.get(normalize(policy.insurer));
      if (rank === undefined) return [policy, groupCount];
      return [policy, selectedRank === undefined ? rank : (rank - selectedRank + groupCount) % groupCount];
    }));
    visible = [...visible].sort((first, second) => {
      const rankDifference = policyRanks.get(first) - policyRanks.get(second);
      return rankDifference !== 0
        ? rankDifference
        : (Number(second.createdAt) || 0) - (Number(first.createdAt) || 0);
    });
  } else if (sortMode === "registration" || sortMode === "policyType") {
    
    
    const registrationGroups = getRegistrationSortGroups(visible);
    const groupCount = registrationGroups.length;
    const rankByToken = new Map(registrationGroups.map((group, index) => [group.token, index]));
    const selectedToken = sortMode === "policyType" && policyTypeSortIndex >= 0
      ? `type:${policyTypeSortIndex}`
      : "registration";
    const selectedRank = rankByToken.get(selectedToken);
    const policyRanks = new Map(visible.map((policy) => {
      const rank = rankByToken.get(getRegistrationGroupToken(policy.registration));
      if (rank === undefined) return [policy, groupCount];
      return [policy, selectedRank === undefined ? rank : (rank - selectedRank + groupCount) % groupCount];
    }));
    visible = [...visible].sort((first, second) => {
      const rankDifference = policyRanks.get(first) - policyRanks.get(second);
      if (rankDifference !== 0) return rankDifference;
      const registrationDifference = compareAlphabetically(first.registration, second.registration);
      return registrationDifference !== 0
        ? registrationDifference
        : (Number(second.createdAt) || 0) - (Number(first.createdAt) || 0);
    });
  } else {
    
    
    
    const defaultSortKeys = new Map(visible.map((policy) => [policy, {
      expiredRank: isPolicyExpired(policy) ? 1 : 0,
      startTime: getPolicyStartDate(policy)?.getTime() ?? null,
    }]));
    visible = [...visible].sort((first, second) => {
      const firstKey = defaultSortKeys.get(first);
      const secondKey = defaultSortKeys.get(second);
      if (firstKey.expiredRank !== secondKey.expiredRank) return firstKey.expiredRank - secondKey.expiredRank;
      if (firstKey.startTime === null && secondKey.startTime !== null) return 1;
      if (firstKey.startTime !== null && secondKey.startTime === null) return -1;
      if (firstKey.startTime !== null && firstKey.startTime !== secondKey.startTime) {
        return secondKey.startTime - firstKey.startTime;
      }
      return (Number(second.createdAt) || 0) - (Number(first.createdAt) || 0);
    });
  }

  
  
  if (emailOnlySearchMatches.size > 0) {
    visible = [...visible].sort(
      (first, second) => Number(emailOnlySearchMatches.has(first)) - Number(emailOnlySearchMatches.has(second)),
    );
  }

  if (renewalsOnly) {
    visible = [...visible].sort(
      (first, second) => Number(Boolean(first.renewalStatus)) - Number(Boolean(second.renewalStatus)),
    );
  }

  return visible;
}

function getRecordsPerPageLimit() {
  return typeof uiSettings.recordsPerPage === "number"
    && RECORDS_PER_PAGE_OPTIONS.has(uiSettings.recordsPerPage)
    ? uiSettings.recordsPerPage
    : null;
}

function getPageStartIndex(totalRecords, limit, page, totalPages) {
  if (totalRecords <= limit) return 0;
  return (page - 1) * limit;
}

function getPaginatedPolicies(visiblePolicies) {
  const limit = getRecordsPerPageLimit();
  if (!limit) {
    currentPage = 1;
    pageJumpOpen = false;
    return visiblePolicies;
  }

  const totalPages = Math.max(1, Math.ceil(visiblePolicies.length / limit));
  currentPage = Math.min(Math.max(1, currentPage), totalPages);
  const firstRecordIndex = getPageStartIndex(visiblePolicies.length, limit, currentPage, totalPages);
  return visiblePolicies.slice(firstRecordIndex, firstRecordIndex + limit);
}

function createPageButton(page, label = String(page)) {
  const isCurrent = page === currentPage;
  return `<button
    class="pagination-page${isCurrent ? " pagination-page--current" : ""}"
    type="button"
    data-page="${page}"
    aria-label="Strona ${page}"
    aria-current="${isCurrent ? "page" : "false"}"
  >${escapeHtml(label)}</button>`;
}

function createPageJumpButton() {
  return '<button class="pagination-ellipsis" type="button" data-page-jump aria-label="Wpisz numer strony">…</button>';
}

function updatePaginationControls(totalRecords) {
  const limit = getRecordsPerPageLimit();
  elements.recordsPerPage.value = limit ? String(limit) : "unlimited";

  if (!limit) {
    currentPage = 1;
    pageJumpOpen = false;
    elements.paginationNav.hidden = true;
    elements.paginationNav.innerHTML = "";
    elements.paginationStatus.textContent = `Wszystkie: ${totalRecords}`;
    return;
  }

  const totalPages = Math.max(1, Math.ceil(totalRecords / limit));
  currentPage = Math.min(Math.max(1, currentPage), totalPages);
  const firstRecordIndex = getPageStartIndex(totalRecords, limit, currentPage, totalPages);
  const firstVisibleRecord = totalRecords === 0 ? 0 : firstRecordIndex + 1;
  const lastVisibleRecord = Math.min(firstRecordIndex + limit, totalRecords);
  elements.paginationStatus.textContent = `${firstVisibleRecord}-${lastVisibleRecord} z ${totalRecords}`;

  if (totalPages <= 1) {
    pageJumpOpen = false;
    elements.paginationNav.hidden = true;
    elements.paginationNav.innerHTML = "";
    return;
  }

  elements.paginationNav.hidden = false;
  if (pageJumpOpen) {
    elements.paginationNav.innerHTML = `
      <span class="pagination-jump">
        <label for="paginationJumpInput">Strona</label>
        <input id="paginationJumpInput" data-page-jump-input type="number" min="1" max="${totalPages}" value="${currentPage}" inputmode="numeric" />
        <span>z ${totalPages}</span>
        <button type="button" data-page-jump-confirm>Przejdź</button>
        <button type="button" data-page-jump-cancel aria-label="Anuluj wpisywanie strony">×</button>
      </span>
    `;
    elements.paginationNav.querySelector?.("[data-page-jump-input]")?.focus();
    return;
  }

  const controls = [];
  if (totalPages <= 5) {
    for (let page = 1; page <= totalPages; page += 1) {
      controls.push(createPageButton(page));
    }
  } else {
    let windowStart;
    let windowEnd;
    if (currentPage <= 2) {
      windowStart = 1;
      windowEnd = 3;
    } else if (currentPage >= totalPages - 1) {
      windowStart = totalPages - 3;
      windowEnd = totalPages - 1;
    } else {
      windowStart = currentPage - 1;
      windowEnd = currentPage + 1;
    }

    if (windowStart > 2) controls.push(createPageJumpButton());
    for (let page = windowStart; page <= windowEnd && page < totalPages; page += 1) {
      controls.push(createPageButton(page));
    }
    if (windowEnd < totalPages - 1) controls.push(createPageJumpButton());
    controls.push(createPageButton(totalPages, "Ostatnia"));
  }

  elements.paginationNav.innerHTML = controls.join('<span class="pagination-separator" aria-hidden="true">|</span>');
}

function resetPaginationAndRender() {
  currentPage = 1;
  pageJumpOpen = false;
  render();
}

function goToPage(pageValue) {
  const limit = getRecordsPerPageLimit();
  if (!limit) return;
  const totalPages = Math.max(1, Math.ceil(getVisiblePolicies().length / limit));
  const requestedPage = Number.parseInt(String(pageValue ?? ""), 10);
  if (!Number.isFinite(requestedPage)) return;
  currentPage = Math.min(Math.max(1, requestedPage), totalPages);
  pageJumpOpen = false;
  render();
}

async function changeRecordsPerPage() {
  const previousValue = uiSettings.recordsPerPage;
  const selectedNumber = Number(elements.recordsPerPage.value);
  const selectedValue = RECORDS_PER_PAGE_OPTIONS.has(selectedNumber) ? selectedNumber : "unlimited";
  if (selectedValue === previousValue) return;

  const nextUiSettings = normalizeUiSettings({ ...uiSettings, recordsPerPage: selectedValue });
  if (!(await persistUiSettings(nextUiSettings))) {
    elements.recordsPerPage.value = String(previousValue);
    return;
  }

  uiSettings = nextUiSettings;
  currentPage = 1;
  pageJumpOpen = false;
  render();
  showToast(selectedValue === "unlimited"
    ? "Wyświetlanie rekordów bez limitu"
    : `Wyświetlanie po ${selectedValue} rekordów`);
}

function updateClientSuggestions(input = getClientSuggestionInput(document.activeElement)) {
  const typedValue = normalize(input?.value);
  if (typedValue.length < 3) {
    elements.clientOptions.innerHTML = "";
    return;
  }

  const uniqueNames = new Map();
  policies.forEach((policy) => {
    const clientName = String(policy.clientName ?? "").trim();
    const key = normalize(clientName);
    if (key && key.includes(typedValue) && !uniqueNames.has(key)) uniqueNames.set(key, clientName);
  });

  const sortedNames = [...uniqueNames.values()].sort((first, second) =>
    first.localeCompare(second, "pl", { sensitivity: "base" }),
  );
  elements.clientOptions.innerHTML = sortedNames
    .map((clientName) => `<option value="${escapeHtml(clientName)}"></option>`)
    .join("");
}

function formatAttachmentSize(bytes) {
  const size = Math.max(0, Number(bytes) || 0);
  if (size < 1024) return `${Math.round(size)} B`;
  if (size < 1024 * 1024) return `${(size / 1024).toFixed(size < 10 * 1024 ? 1 : 0)} KB`;
  return `${(size / (1024 * 1024)).toFixed(size < 10 * 1024 * 1024 ? 1 : 0)} MB`;
}

function pluralizeAttachments(count) {
  if (count === 1) return "1 załącznik";
  const lastTwo = count % 100;
  const last = count % 10;
  if (last >= 2 && last <= 4 && !(lastTwo >= 12 && lastTwo <= 14)) return `${count} załączniki`;
  return `${count} załączników`;
}

const ATTACHMENT_PROGRESS_REVEAL_DELAY_MS = 400;
let attachmentProgressRevealTimer = null;

function startAttachmentOperation(total, title = "Przygotowywanie załączników") {
  const normalizedTotal = Math.max(1, Number(total) || 1);
  attachmentOperationActive = true;
  if (elements.attachmentProgress.hidden && attachmentProgressRevealTimer === null) {
    attachmentProgressRevealTimer = globalThis.setTimeout(() => {
      attachmentProgressRevealTimer = null;
      if (!attachmentOperationActive) return;
      elements.attachmentProgress.hidden = false;
      elements.attachmentProgress.setAttribute("aria-busy", "true");
    }, ATTACHMENT_PROGRESS_REVEAL_DELAY_MS);
  }
  elements.attachmentProgressTitle.textContent = title;
  elements.attachmentProgressDetail.textContent = `${pluralizeAttachments(Number(total) || 0)} - proszę czekać…`;
  elements.attachmentProgressBar.max = normalizedTotal;
  elements.attachmentProgressBar.value = 0;
  elements.attachmentProgressBar.setAttribute("max", String(normalizedTotal));
  elements.attachmentProgressBar.setAttribute("value", "0");
  elements.card.setAttribute("aria-busy", "true");
  elements.importPolicies.disabled = true;
  elements.policyImportInput.disabled = true;
  elements.policyAttachmentInput.disabled = true;
  elements.recordAttachmentInput.disabled = true;
}

function updateAttachmentOperation(title, current, total, fileName = "") {
  const normalizedTotal = Math.max(1, Number(total) || 1);
  const normalizedCurrent = Math.min(normalizedTotal, Math.max(0, Number(current) || 0));
  elements.attachmentProgressTitle.textContent = title;
  elements.attachmentProgressDetail.textContent = fileName
    ? `${normalizedCurrent} z ${normalizedTotal} - ${fileName}`
    : `${normalizedCurrent} z ${normalizedTotal}`;
  elements.attachmentProgressBar.max = normalizedTotal;
  elements.attachmentProgressBar.value = normalizedCurrent;
  elements.attachmentProgressBar.setAttribute("max", String(normalizedTotal));
  elements.attachmentProgressBar.setAttribute("value", String(normalizedCurrent));
}

function finishAttachmentOperation() {
  attachmentOperationActive = false;
  if (attachmentProgressRevealTimer !== null) {
    globalThis.clearTimeout(attachmentProgressRevealTimer);
    attachmentProgressRevealTimer = null;
  }
  elements.attachmentProgress.hidden = true;
  elements.attachmentProgress.setAttribute("aria-busy", "false");
  elements.card.removeAttribute("aria-busy");
  elements.importPolicies.disabled = false;
  elements.policyImportInput.disabled = false;
  elements.policyAttachmentInput.disabled = false;
  elements.recordAttachmentInput.disabled = false;
}

function getAttachmentTypeLabel(attachment) {
  if (attachment.type === "application/pdf") return "PDF";
  const extension = String(attachment.name ?? "").split(".").pop()?.toLocaleUpperCase("pl");
  return extension && extension.length <= 5 ? extension : "IMG";
}

function readAttachmentFile(file) {
  return new Promise((resolve, reject) => {
    const reader = new FileReader();
    reader.onload = () => resolve(String(reader.result ?? ""));
    reader.onerror = () => reject(new Error(`Nie udało się odczytać pliku „${file.name}”.`));
    reader.readAsDataURL(file);
  });
}

function sanitizePathPart(value, fallback, maxLength = 120) {
  let sanitized = String(value ?? "")
    .replace(/[<>:"/\\|?*\u0000-\u001F]/g, "_")
    .replace(/\s+/g, " ")
    .trim()
    .replace(/[. ]+$/g, "")
    .slice(0, maxLength)
    .replace(/[. ]+$/g, "");
  if (!sanitized) sanitized = fallback;
  if (/^(con|prn|aux|nul|com[1-9]|lpt[1-9])(\..*)?$/i.test(sanitized)) sanitized = `${sanitized}_`;
  return sanitized;
}

function getPolicyAttachmentDirectoryPath(clientName, policyNumber) {
  return [
    ATTACHMENTS_DIRECTORY_NAME,
    sanitizePathPart(clientName, "Bez nazwy", MAX_ATTACHMENT_DIRECTORY_SEGMENT_LENGTH),
    sanitizePathPart(policyNumber, "Bez numeru polisy", MAX_ATTACHMENT_DIRECTORY_SEGMENT_LENGTH),
  ];
}

async function resolveAttachmentsRootDirectory(baseDirectory, { create = false } = {}) {
  if (baseDirectory?.name === ATTACHMENTS_DIRECTORY_NAME) return baseDirectory;
  return baseDirectory.getDirectoryHandle(ATTACHMENTS_DIRECTORY_NAME, { create });
}

async function getAttachmentDirectoryFromBase(baseDirectory, relativeDirectoryPath, { create = false } = {}) {
  let directory = await resolveAttachmentsRootDirectory(baseDirectory, { create });
  for (const directoryName of relativeDirectoryPath.slice(1)) {
    directory = await directory.getDirectoryHandle(directoryName, { create });
  }
  return directory;
}

function showAttachmentsFolderInfo() {
  const dialog = elements.attachmentsInfoDialog;
  if (!dialog?.showModal || !elements.attachmentsInfoConfirm || !elements.attachmentsInfoCancel) {
    return Promise.resolve(true);
  }
  return new Promise((resolve) => {
    const finish = (accepted) => {
      elements.attachmentsInfoConfirm.removeEventListener("click", onConfirm);
      elements.attachmentsInfoCancel.removeEventListener("click", onCancel);
      dialog.removeEventListener("cancel", onDialogCancel);
      if (dialog.open) dialog.close();
      resolve(accepted);
    };
    const onConfirm = () => finish(true);
    const onCancel = () => finish(false);
    const onDialogCancel = (event) => {
      event.preventDefault();
      finish(false);
    };
    elements.attachmentsInfoConfirm.addEventListener("click", onConfirm);
    elements.attachmentsInfoCancel.addEventListener("click", onCancel);
    dialog.addEventListener("cancel", onDialogCancel);
    dialog.showModal();
  });
}





async function ensureAttachmentsBaseDirectory() {
  let handle = attachmentsBaseDirectoryHandle
    || rememberedAttachmentsBaseDirectoryHandle
    || await getRememberedAttachmentsDirectoryHandle();

  let rememberedBaseDenied = false;
  if (handle) {
    let permissionDenied = false;
    try {
      if (await requestWritePermission(handle)) {
        attachmentsBaseDirectoryHandle = handle;
        await resolveAttachmentsRootDirectory(handle, { create: true });
        return handle;
      }
      permissionDenied = true;
    } catch {
    }
    if (permissionDenied) {
      rememberedBaseDenied = true;
    } else {
      await forgetRememberedAttachmentsDirectoryHandle();
    }
    handle = null;
  }

  const appFolder = rememberedBaseDenied
    ? null
    : appDirectoryHandle
      || rememberedAppDirectoryHandle
      || await getRememberedAppDirectoryHandle();
  if (appFolder) {
    try {
      if (await requestWritePermission(appFolder)) {
        await resolveAttachmentsRootDirectory(appFolder, { create: true });
        attachmentsBaseDirectoryHandle = appFolder;
        rememberedAttachmentsBaseDirectoryHandle = appFolder;
        await rememberAttachmentsDirectoryHandle(appFolder);
        return appFolder;
      }
    } catch {
    }
  }

  if (typeof globalThis.showDirectoryPicker !== "function") {
    throw new Error("Ta przeglądarka nie pozwala zapisywać załączników w folderze. Otwórz aplikację w Chrome albo Edge.");
  }

  
  
  
  if (!(await showAttachmentsFolderInfo())) {
    const cancelError = new Error("Anulowano wybór folderu bazy.");
    cancelError.name = "AbortError";
    throw cancelError;
  }
  const pickerOptions = {
    id: "baza-polis-folder",
    mode: "readwrite",
  };
  const dataHandleForStart = dataFileHandle || rememberedDataFileHandle;
  if (dataHandleForStart?.kind === "file") pickerOptions.startIn = dataHandleForStart;
  else pickerOptions.startIn = "desktop";
  handle = await showSystemPicker("showDirectoryPicker", pickerOptions);
  if (!(await requestWritePermission(handle))) {
    throw new Error("Brak zgody na zapis w wybranym folderze.");
  }
  if (!(await directoryHoldsCurrentDataFile(handle))) {
    throw new Error("W tym folderze nie ma pliku bazy. Wskaż folder, w którym leży baza polis.");
  }
  await resolveAttachmentsRootDirectory(handle, { create: true });
  
  
  appDirectoryHandle = handle;
  rememberedAppDirectoryHandle = handle;
  await rememberAppDirectoryHandle(handle);
  attachmentsBaseDirectoryHandle = handle;
  rememberedAttachmentsBaseDirectoryHandle = handle;
  await rememberAttachmentsDirectoryHandle(handle);
  return handle;
}




async function directoryHoldsCurrentDataFile(directoryHandle) {
  const currentDataFile = dataFileHandle || rememberedDataFileHandle;
  if (!currentDataFile?.name) return true;
  try {
    const candidate = await directoryHandle.getFileHandle(currentDataFile.name);
    return await candidate.isSameEntry(currentDataFile);
  } catch {
    return false;
  }
}

async function getUniqueAttachmentFileName(directoryHandle, originalName, relativeDirectoryPath) {
  const directoryPathLength = relativeDirectoryPath.join("\\").length;
  const availableFileNameLength = Math.max(
    24,
    MAX_ATTACHMENT_RELATIVE_PATH_LENGTH - directoryPathLength - 1,
  );
  const safeName = sanitizePathPart(originalName, "zalacznik", availableFileNameLength);
  const dotIndex = safeName.lastIndexOf(".");
  const baseName = dotIndex > 0 ? safeName.slice(0, dotIndex) : safeName;
  const extension = dotIndex > 0 ? safeName.slice(dotIndex) : "";
  let suffix = 1;

  while (true) {
    const suffixText = suffix > 1 ? ` (${suffix})` : "";
    const maximumBaseLength = Math.max(1, availableFileNameLength - extension.length - suffixText.length);
    const candidate = `${baseName.slice(0, maximumBaseLength).replace(/[. ]+$/g, "") || "zalacznik"}${suffixText}${extension}`;
    if ([...relativeDirectoryPath, candidate].join("\\").length > MAX_ATTACHMENT_RELATIVE_PATH_LENGTH) {
      throw new Error(`Ścieżka załącznika „${originalName}” jest zbyt długa. Skróć nazwę pliku, klienta lub numer polisy.`);
    }
    try {
      await directoryHandle.getFileHandle(candidate);
      suffix += 1;
    } catch (error) {
      if (error?.name === "NotFoundError") return candidate;
      throw error;
    }
  }
}

async function writeAttachmentToPolicyDirectory(
  policyDirectory,
  relativeDirectoryPath,
  attachment,
  lifecycle = null,
) {
  const storedFileName = await getUniqueAttachmentFileName(
    policyDirectory,
    attachment.name,
    relativeDirectoryPath,
  );
  try {
    
    
    
    lifecycle?.beforeWrite?.({
      storage: "file",
      relativePath: [...relativeDirectoryPath, storedFileName],
    });
    const fileHandle = await policyDirectory.getFileHandle(storedFileName, { create: true });
    const writable = await fileHandle.createWritable();
    try {
      const fileContents = attachment.sourceFile instanceof Blob
        ? attachment.sourceFile
        : attachmentDataUrlToBlob(attachment);
      await writable.write(fileContents);
    } finally {
      await writable.close();
    }
  } catch (error) {
    let removedPartialFile = false;
    try {
      await policyDirectory.removeEntry(storedFileName);
      removedPartialFile = true;
    } catch {
    }
    const writeError = error instanceof Error
      ? error
      : new Error("Nie udało się zapisać załącznika.");
    if (!removedPartialFile) {
      
      
      writeError.portfolioPdfRecoveryAttachments = [{
        storage: "file",
        relativePath: [...relativeDirectoryPath, storedFileName],
      }];
    }
    throw writeError;
  }

  return normalizeAttachment({
    ...attachment,
    storage: "file",
    relativePath: [...relativeDirectoryPath, storedFileName],
  });
}

async function writeAttachmentsToFolder(
  clientName,
  policyNumber,
  attachments,
  onProgress = null,
  lifecycle = null,
) {
  const writtenAttachments = [];
  const relativeDirectoryPath = getPolicyAttachmentDirectoryPath(clientName, policyNumber);
  const reachedDirectoryPath = [];
  let baseDirectory = null;
  try {
    baseDirectory = await ensureAttachmentsBaseDirectory();
    let policyDirectory = await resolveAttachmentsRootDirectory(baseDirectory, { create: true });
    reachedDirectoryPath.push(relativeDirectoryPath[0]);
    for (const directoryName of relativeDirectoryPath.slice(1)) {
      policyDirectory = await policyDirectory.getDirectoryHandle(directoryName, { create: true });
      reachedDirectoryPath.push(directoryName);
    }
    for (let index = 0; index < attachments.length; index += 1) {
      const attachment = attachments[index];
      onProgress?.("Zapisywanie załączników", index + 1, attachments.length, attachment.name);
      writtenAttachments.push(await writeAttachmentToPolicyDirectory(
        policyDirectory,
        relativeDirectoryPath,
        attachment,
        lifecycle,
      ));
    }
    return writtenAttachments;
  } catch (error) {
    const uncertainAttachments = [
      ...writtenAttachments,
      ...(Array.isArray(error?.portfolioPdfRecoveryAttachments)
        ? error.portfolioPdfRecoveryAttachments
        : []),
    ];
    const deletedAll = await deleteExternalAttachmentFiles(uncertainAttachments);
    if (uncertainAttachments.length > 0 && error && typeof error === "object") {
      error.portfolioPdfRecoveryAttachments = uncertainAttachments;
      error.portfolioPdfRecoveryFilesDeleted = deletedAll;
    } else if (error && typeof error === "object") {
      delete error.portfolioPdfRecoveryAttachments;
      delete error.portfolioPdfRecoveryFilesDeleted;
    }
    if (baseDirectory && reachedDirectoryPath.length > 1) {
      await cleanupEmptyAttachmentDirectories(reachedDirectoryPath, baseDirectory);
    }
    throw error;
  }
}

async function isDirectoryHandleEmpty(directoryHandle) {
  if (typeof directoryHandle.values === "function") {
    for await (const _handle of directoryHandle.values()) return false;
    return true;
  }
  if (typeof directoryHandle.entries === "function") {
    for await (const _entry of directoryHandle.entries()) return false;
    return true;
  }
  return false;
}

async function cleanupEmptyAttachmentDirectories(relativeDirectoryPath, existingBaseDirectory = null) {
  const path = Array.isArray(relativeDirectoryPath) ? relativeDirectoryPath : [];
  if (path.length < 2 || path[0] !== ATTACHMENTS_DIRECTORY_NAME) return;
  const baseDirectory = existingBaseDirectory || await ensureAttachmentsBaseDirectory();
  const traversed = [];
  try {
    let directory = await resolveAttachmentsRootDirectory(baseDirectory);
    for (const directoryName of path.slice(1)) {
      const child = await directory.getDirectoryHandle(directoryName);
      traversed.push({ parent: directory, name: directoryName, handle: child });
      directory = child;
    }
  } catch (error) {
    if (error?.name === "NotFoundError") return;
    throw error;
  }

  for (let index = traversed.length - 1; index >= 0; index -= 1) {
    const entry = traversed[index];
    if (!(await isDirectoryHandleEmpty(entry.handle))) break;
    try {
      await entry.parent.removeEntry(entry.name);
    } catch (error) {
      if (error?.name !== "NotFoundError") throw error;
    }
  }
}

async function getExternalAttachmentFileHandle(attachment) {
  const relativePath = normalizeAttachmentRelativePath(attachment.relativePath);
  if (!relativePath) throw new Error("Załącznik ma nieprawidłową ścieżkę.");
  const baseDirectory = await ensureAttachmentsBaseDirectory();
  const directory = await getAttachmentDirectoryFromBase(baseDirectory, relativePath.slice(0, -1));
  return directory.getFileHandle(relativePath.at(-1));
}

async function deleteExternalAttachmentFile(attachment) {
  if (!isExternalAttachment(attachment)) return true;
  const relativePath = normalizeAttachmentRelativePath(attachment.relativePath);
  const baseDirectory = await ensureAttachmentsBaseDirectory();
  try {
    const directory = await getAttachmentDirectoryFromBase(baseDirectory, relativePath.slice(0, -1));
    await directory.removeEntry(relativePath.at(-1));
    await cleanupEmptyAttachmentDirectories(relativePath.slice(0, -1), baseDirectory);
  } catch (error) {
    if (error?.name !== "NotFoundError") throw error;
  }
  return true;
}

async function deleteExternalAttachmentFiles(attachments) {
  let deletedAll = true;
  for (const attachment of attachments) {
    if (!isExternalAttachment(attachment)) continue;
    try {
      await deleteExternalAttachmentFile(attachment);
    } catch {
      deletedAll = false;
    }
  }
  return deletedAll;
}

async function prepareRelocatedPolicyAttachments(policy, nextClientName, nextPolicyNumber, onProgress = null) {
  const currentAttachments = normalizePolicyAttachments(policy.attachments);
  const targetDirectoryPath = getPolicyAttachmentDirectoryPath(nextClientName, nextPolicyNumber);
  const attachmentsToCopy = currentAttachments.filter((attachment) => {
    if (!isExternalAttachment(attachment)) return false;
    const currentDirectoryPath = normalizeAttachmentRelativePath(attachment.relativePath)?.slice(0, -1);
    return JSON.stringify(currentDirectoryPath) !== JSON.stringify(targetDirectoryPath);
  });
  if (attachmentsToCopy.length === 0) {
    return {
      nextAttachments: currentAttachments,
      copiedAttachments: [],
      sourceAttachments: [],
      missingAttachments: [],
    };
  }

  const preparedAttachments = [];
  const missingAttachments = [];
  for (let index = 0; index < attachmentsToCopy.length; index += 1) {
    const attachment = attachmentsToCopy[index];
    onProgress?.("Przenoszenie załączników", index + 1, attachmentsToCopy.length, attachment.name);
    try {
      preparedAttachments.push({
        ...attachment,
        sourceFile: await getPolicyAttachmentBlob(attachment),
      });
    } catch (error) {
      if (error?.name !== "NotFoundError") throw error;
      missingAttachments.push(attachment);
    }
  }
  const copiedAttachments = preparedAttachments.length > 0
    ? await writeAttachmentsToFolder(
        nextClientName,
        nextPolicyNumber,
        preparedAttachments,
        onProgress,
      )
    : [];
  const copiedById = new Map(copiedAttachments.map((attachment) => [attachment.id, attachment]));
  const copiedAttachmentIds = new Set(copiedAttachments.map((attachment) => attachment.id));
  return {
    nextAttachments: currentAttachments.map((attachment) => copiedById.get(attachment.id) || attachment),
    copiedAttachments,
    sourceAttachments: attachmentsToCopy.filter((attachment) => copiedAttachmentIds.has(attachment.id)),
    missingAttachments,
  };
}

function lookupAttachmentDirectoryInIndex(directoryIndex, relativeDirectoryPath) {
  if (!Array.isArray(relativeDirectoryPath) || relativeDirectoryPath[0] !== ATTACHMENTS_DIRECTORY_NAME) return null;
  if (relativeDirectoryPath.length < 2 || relativeDirectoryPath.length > 3) return null;
  const clientEntry = directoryIndex.get(foldAttachmentPathSegment(relativeDirectoryPath[1]));
  if (!clientEntry) return null;
  if (relativeDirectoryPath.length === 2) return clientEntry.handle;
  return clientEntry.children.get(foldAttachmentPathSegment(relativeDirectoryPath[2])) || null;
}



async function buildAttachmentsDirectoryIndex(baseDirectory) {
  const rootDirectory = await resolveAttachmentsRootDirectory(baseDirectory);
  const directoryIndex = new Map();
  for (const clientDirectory of await listDirectoryHandles(rootDirectory)) {
    const clientKey = foldAttachmentPathSegment(clientDirectory.name);
    if (directoryIndex.has(clientKey)) continue;
    const children = new Map();
    for (const childDirectory of await listDirectoryHandles(clientDirectory)) {
      const childKey = foldAttachmentPathSegment(childDirectory.name);
      if (!children.has(childKey)) children.set(childKey, childDirectory);
    }
    directoryIndex.set(clientKey, { handle: clientDirectory, children });
  }
  return directoryIndex;
}

async function getExistingPolicyAttachmentDirectory(baseDirectory, policy, directoryIndex = null) {
  const canonicalPath = getPolicyAttachmentDirectoryPath(policy.clientName, policy.policyNumber);
  const storedPaths = normalizePolicyAttachments(policy.attachments)
    .filter(isExternalAttachment)
    .map((attachment) => normalizeAttachmentRelativePath(attachment.relativePath)?.slice(0, -1))
    .filter(Boolean);
  const candidatePaths = [canonicalPath, ...storedPaths]
    .filter((path, index, paths) => paths.findIndex((candidate) => (
      JSON.stringify(candidate) === JSON.stringify(path)
    )) === index);

  for (const relativeDirectoryPath of candidatePaths) {
    if (directoryIndex) {
      const directory = lookupAttachmentDirectoryInIndex(directoryIndex, relativeDirectoryPath);
      if (directory) return { directory, relativeDirectoryPath };
      continue;
    }
    try {
      const directory = await getAttachmentDirectoryFromBase(baseDirectory, relativeDirectoryPath);
      return { directory, relativeDirectoryPath };
    } catch (error) {
      if (error?.name !== "NotFoundError") throw error;
    }
  }

  const policyNumberSegment = policy.policyNumber
    ? sanitizePathPart(policy.policyNumber, "", MAX_ATTACHMENT_DIRECTORY_SEGMENT_LENGTH)
    : "";
  if (policyNumberSegment) {
    if (directoryIndex) {
      const targetKey = foldAttachmentPathSegment(policyNumberSegment);
      for (const clientEntry of directoryIndex.values()) {
        const match = clientEntry.children.get(targetKey);
        if (match) {
          return {
            directory: match,
            relativeDirectoryPath: [ATTACHMENTS_DIRECTORY_NAME, clientEntry.handle.name, match.name],
          };
        }
      }
      return null;
    }
    let rootDirectory = null;
    try {
      rootDirectory = await resolveAttachmentsRootDirectory(baseDirectory);
    } catch (error) {
      if (error?.name !== "NotFoundError") throw error;
    }
    if (rootDirectory) {
      for (const clientDirectory of await listDirectoryHandles(rootDirectory)) {
        try {
          const directory = await clientDirectory.getDirectoryHandle(policyNumberSegment);
          return {
            directory,
            relativeDirectoryPath: [ATTACHMENTS_DIRECTORY_NAME, clientDirectory.name, policyNumberSegment],
          };
        } catch (error) {
          if (error?.name !== "NotFoundError") throw error;
        }
      }
    }
  }
  return null;
}

async function listAttachmentFileHandles(directory) {
  const fileHandles = [];
  if (typeof directory.values === "function") {
    for await (const handle of directory.values()) {
      if (handle?.kind === "file") fileHandles.push(handle);
    }
    return fileHandles;
  }
  if (typeof directory.entries === "function") {
    for await (const [, handle] of directory.entries()) {
      if (handle?.kind === "file") fileHandles.push(handle);
    }
  }
  return fileHandles;
}

async function listDirectoryHandles(directory) {
  const directoryHandles = [];
  if (typeof directory.values === "function") {
    for await (const handle of directory.values()) {
      if (handle?.kind === "directory") directoryHandles.push(handle);
    }
    return directoryHandles;
  }
  if (typeof directory.entries === "function") {
    for await (const [, handle] of directory.entries()) {
      if (handle?.kind === "directory") directoryHandles.push(handle);
    }
  }
  return directoryHandles;
}

function foldAttachmentPathSegment(segment) {
  return String(segment ?? "").normalize("NFKC").toLocaleLowerCase("pl");
}

function getAttachmentPathKey(relativePath) {
  return normalizeAttachmentRelativePath(relativePath)?.map(foldAttachmentPathSegment).join("\u0000") ?? "";
}

function getAttachmentDirectoryPathKey(relativeDirectoryPath) {
  if (
    !Array.isArray(relativeDirectoryPath)
    || relativeDirectoryPath[0] !== ATTACHMENTS_DIRECTORY_NAME
    || relativeDirectoryPath.length < 2
    || relativeDirectoryPath.length > 3
  ) return "";
  return relativeDirectoryPath.map(foldAttachmentPathSegment).join("\u0000");
}

function createDiscoveredAttachmentId(relativePath) {
  const value = relativePath.join("/");
  let hash = 2166136261;
  for (let index = 0; index < value.length; index += 1) {
    hash ^= value.charCodeAt(index);
    hash = Math.imul(hash, 16777619);
  }
  return `folder-${(hash >>> 0).toString(36)}`;
}

function getAttachmentComparisonKey(attachment) {
  return JSON.stringify({
    id: attachment.id,
    name: attachment.name,
    type: attachment.type,
    size: attachment.size,
    category: attachment.category || "",
    path: normalizeAttachmentRelativePath(attachment.relativePath),
    embedded: Boolean(attachment.dataUrl),
  });
}

async function getAttachmentDirectoryFileState(
  baseDirectory,
  relativeDirectoryPath,
  directoryIndex,
  directoryFileCache,
  knownDirectory = null,
) {
  const directoryKey = getAttachmentDirectoryPathKey(relativeDirectoryPath);
  if (!directoryKey) return { status: "unknown" };
  const cached = directoryFileCache.get(directoryKey);
  if (cached) return cached;

  let directory = knownDirectory
    || (directoryIndex ? lookupAttachmentDirectoryInIndex(directoryIndex, relativeDirectoryPath) : null);
  if (!directory) {
    try {
      directory = await getAttachmentDirectoryFromBase(baseDirectory, relativeDirectoryPath);
    } catch (error) {
      const state = { status: error?.name === "NotFoundError" ? "confirmed-missing" : "unknown" };
      directoryFileCache.set(directoryKey, state);
      return state;
    }
  }

  try {
    const fileHandles = await listAttachmentFileHandles(directory);
    const state = {
      status: "present",
      directory,
      fileHandles,
      fileNames: new Set(fileHandles.map((handle) => foldAttachmentPathSegment(handle.name))),
    };
    directoryFileCache.set(directoryKey, state);
    return state;
  } catch {
    const state = { status: "unknown" };
    directoryFileCache.set(directoryKey, state);
    return state;
  }
}

async function classifyExternalAttachmentPresence(
  attachment,
  baseDirectory,
  directoryIndex,
  directoryFileCache,
) {
  const relativePath = normalizeAttachmentRelativePath(attachment.relativePath);
  if (!relativePath) return "unknown";
  const relativeDirectoryPath = relativePath.slice(0, -1);
  const directoryState = await getAttachmentDirectoryFileState(
    baseDirectory,
    relativeDirectoryPath,
    directoryIndex,
    directoryFileCache,
  );
  if (directoryState.status === "confirmed-missing") return "confirmed-missing";
  if (directoryState.status !== "present") return "unknown";

  const fileName = relativePath.at(-1);
  if (directoryState.fileNames.has(foldAttachmentPathSegment(fileName))) return "present";

  
  
  try {
    const exactDirectory = await getAttachmentDirectoryFromBase(baseDirectory, relativeDirectoryPath);
    await exactDirectory.getFileHandle(fileName);
    return "present";
  } catch (error) {
    return error?.name === "NotFoundError" ? "confirmed-missing" : "unknown";
  }
}

async function syncPolicyAttachmentsFromFolder(
  policy,
  baseDirectory,
  directoryIndex = null,
  directoryFileCache = new Map(),
) {
  const existingDirectory = await getExistingPolicyAttachmentDirectory(baseDirectory, policy, directoryIndex);
  const currentAttachments = normalizePolicyAttachments(policy.attachments);
  const currentByPath = new Map(
    currentAttachments
      .filter(isExternalAttachment)
      .map((attachment) => [getAttachmentPathKey(attachment.relativePath), attachment]),
  );
  const discoveredAttachments = [];
  let discoveredCount = 0;

  if (existingDirectory) {
    const { directory: policyDirectory, relativeDirectoryPath } = existingDirectory;
    const directoryState = await getAttachmentDirectoryFileState(
      baseDirectory,
      relativeDirectoryPath,
      directoryIndex,
      directoryFileCache,
      policyDirectory,
    );
    if (directoryState.status === "present") {
      for (const fileHandle of directoryState.fileHandles) {
        try {
          const file = await fileHandle.getFile();
          const type = getAttachmentMimeType(file);
          if (!type) continue;
          const relativePath = [...relativeDirectoryPath, fileHandle.name];
          const pathKey = getAttachmentPathKey(relativePath);
          const existingAttachment = currentByPath.get(pathKey);
          if (!existingAttachment) discoveredCount += 1;
          const discoveredAttachment = normalizeAttachment({
            id: existingAttachment?.id || createDiscoveredAttachmentId(relativePath),
            name: fileHandle.name,
            type,
            size: file.size,
            
            
            category: existingAttachment?.category,
            storage: "file",
            relativePath,
            createdAt: existingAttachment?.createdAt || file.lastModified || Date.now(),
          });
          if (discoveredAttachment) discoveredAttachments.push(discoveredAttachment);
        } catch {
        }
      }
    }
  }

  const discoveredKeys = new Set(discoveredAttachments.map((attachment) => getAttachmentPathKey(attachment.relativePath)));
  const retainedAttachments = [];
  let removedCount = 0;
  for (const attachment of currentAttachments) {
    if (!isExternalAttachment(attachment)) {
      retainedAttachments.push(attachment);
      continue;
    }
    if (discoveredKeys.has(getAttachmentPathKey(attachment.relativePath))) continue;
    const presence = await classifyExternalAttachmentPresence(
      attachment,
      baseDirectory,
      directoryIndex,
      directoryFileCache,
    );
    if (presence === "confirmed-missing") {
      removedCount += 1;
      continue;
    }
    retainedAttachments.push(attachment);
  }
  const nextAttachments = [...retainedAttachments, ...discoveredAttachments];
  const currentKey = currentAttachments.map(getAttachmentComparisonKey).sort().join("|");
  const nextKey = nextAttachments.map(getAttachmentComparisonKey).sort().join("|");
  if (currentKey === nextKey) return { changed: false, discoveredCount, removedCount };

  policy.attachments = nextAttachments;
  policy.updatedAt = Date.now();
  return { changed: true, discoveredCount, removedCount };
}

let attachmentsFolderReconciliationDone = false;
let attachmentsFolderReconciliationPromise = null;

async function resolveAttachmentsBaseDirectorySilently() {
  const candidates = [
    attachmentsBaseDirectoryHandle,
    rememberedAttachmentsBaseDirectoryHandle || await getRememberedAttachmentsDirectoryHandle(),
    appDirectoryHandle,
    rememberedAppDirectoryHandle || await getRememberedAppDirectoryHandle(),
  ];
  for (const candidate of candidates) {
    if (!candidate) continue;
    try {
      const permission = candidate.queryPermission
        ? await candidate.queryPermission({ mode: "readwrite" })
        : "granted";
      if (permission !== "granted") continue;
      await resolveAttachmentsRootDirectory(candidate);
      return candidate;
    } catch {
    }
  }
  return null;
}

async function reconcileAttachmentsFromFolderUnlocked({ force = false } = {}) {
  
  
  if (attachmentsFolderReconciliationPromise) return attachmentsFolderReconciliationPromise;
  if (attachmentOperationActive) return;
  if (attachmentsFolderReconciliationDone && !force) return;
  if (force) attachmentsFolderReconciliationDone = false;
  attachmentsFolderReconciliationPromise = (async () => {
    try {
      if (!dataFileHandle || !Array.isArray(policies) || policies.length === 0) return;
      const baseDirectory = await resolveAttachmentsBaseDirectorySilently();
      if (!baseDirectory) return;
      let directoryIndex;
      try {
        directoryIndex = await buildAttachmentsDirectoryIndex(baseDirectory);
      } catch {
        return;
      }
      const directoryFileCache = new Map();
      let changedCount = 0;
      let discoveredTotal = 0;
      let removedTotal = 0;
      let fullScanCompleted = true;
      const rollbackStates = [];
      for (const policy of [...policies]) {
        if (attachmentOperationActive) {
          fullScanCompleted = false;
          break;
        }
        try {
          const rollbackState = {
            policy,
            hadAttachments: Object.prototype.hasOwnProperty.call(policy, "attachments"),
            attachments: policy.attachments,
            hadUpdatedAt: Object.prototype.hasOwnProperty.call(policy, "updatedAt"),
            updatedAt: policy.updatedAt,
          };
          const result = await syncPolicyAttachmentsFromFolder(
            policy,
            baseDirectory,
            directoryIndex,
            directoryFileCache,
          );
          if (result.changed) {
            rollbackStates.push(rollbackState);
            changedCount += 1;
          }
          discoveredTotal += result.discoveredCount;
          removedTotal += result.removedCount;
          if (attachmentOperationActive) {
            fullScanCompleted = false;
            break;
          }
        } catch {
          fullScanCompleted = false;
          break;
        }
      }
      if (!fullScanCompleted) {
        for (const state of rollbackStates.reverse()) {
          if (!policies.includes(state.policy)) continue;
          if (state.hadAttachments) state.policy.attachments = state.attachments;
          else delete state.policy.attachments;
          if (state.hadUpdatedAt) state.policy.updatedAt = state.updatedAt;
          else delete state.policy.updatedAt;
        }
        return;
      }
      if (changedCount === 0) {
        attachmentsFolderReconciliationDone = true;
        return;
      }
      if (await persistPolicies({ employeePackageImportLockHeld: true })) {
        attachmentsFolderReconciliationDone = true;
        render();
        const report = [];
        if (discoveredTotal > 0) {
          report.push(`Podłączono ${pluralizeAttachments(discoveredTotal)} z folderu Zalaczniki`);
        }
        if (removedTotal > 0) {
          report.push(
            removedTotal === 1
              ? "Usunięto 1 nieaktualne odwołanie do brakującego załącznika"
              : `Usunięto ${removedTotal} nieaktualnych odwołań do brakujących załączników`,
          );
        }
        if (report.length > 0) showToast(report.join(". "));
      }
    } finally {
      attachmentsFolderReconciliationPromise = null;
    }
  })();
  return attachmentsFolderReconciliationPromise;
}

function reconcileAttachmentsFromFolder(options = {}) {
  if (globalThis.navigator?.locks?.request) {
    return globalThis.navigator.locks.request(
      EMPLOYEE_PACKAGE_IMPORT_LOCK_NAME,
      { mode: "exclusive" },
      () => reconcileAttachmentsFromFolderUnlocked(options),
    );
  }
  return reconcileAttachmentsFromFolderUnlocked(options);
}

async function createAttachmentsFromFiles(fileList, currentAttachments = [], onProgress = null, useSourceFiles = false, category = "") {
  const files = [...(fileList ?? [])];
  if (files.length === 0) return [];

  const normalizedCategory = normalizeAttachmentCategory(category);
  let totalSize = normalizePolicyAttachments(currentAttachments)
    .reduce((sum, attachment) => sum + attachment.size, 0);
  const createdAttachments = [];
  const preparedFiles = [];

  for (const file of files) {
    const type = getAttachmentMimeType(file);
    if (!type) {
      throw new Error(`Plik „${file.name}” ma nieobsługiwany format. Wybierz PDF, JPG, PNG lub WEBP.`);
    }
    if (file.size > MAX_ATTACHMENT_FILE_SIZE) {
      throw new Error(`Plik „${file.name}” jest większy niż 25 MB.`);
    }
    if (totalSize + file.size > MAX_POLICY_ATTACHMENTS_SIZE) {
      throw new Error("Łączny rozmiar załączników jednego rekordu nie może przekroczyć 75 MB.");
    }
    preparedFiles.push({ file, type });
    totalSize += file.size;
  }

  for (let index = 0; index < preparedFiles.length; index += 1) {
    const { file, type } = preparedFiles[index];
    onProgress?.(useSourceFiles ? "Przygotowywanie załączników" : "Wczytywanie załączników", index + 1, preparedFiles.length, file.name);
    if (useSourceFiles) {
      createdAttachments.push({
        id: globalThis.crypto?.randomUUID?.() ?? `${Date.now()}-${Math.random()}`,
        name: sanitizeAttachmentDisplayName(file.name, type),
        type,
        size: file.size,
        ...(normalizedCategory ? { category: normalizedCategory } : {}),
        sourceFile: file,
        createdAt: Date.now(),
      });
      continue;
    }
    const fileDataUrl = await readAttachmentFile(file);
    const dataSeparatorIndex = fileDataUrl.indexOf(",");
    const normalizedDataUrl = dataSeparatorIndex >= 0
      ? `data:${type};base64,${fileDataUrl.slice(dataSeparatorIndex + 1)}`
      : fileDataUrl;
    const attachment = normalizeAttachment({
      id: globalThis.crypto?.randomUUID?.() ?? `${Date.now()}-${Math.random()}`,
      name: file.name,
      type,
      size: file.size,
      category: normalizedCategory,
      dataUrl: normalizedDataUrl,
      createdAt: Date.now(),
    });
    if (!attachment) throw new Error(`Nie udało się przygotować pliku „${file.name}”.`);
    createdAttachments.push(attachment);
  }

  return createdAttachments;
}

function createPendingAttachmentChip(attachment) {
  const safeId = escapeHtml(attachment.id);
  const safeName = escapeHtml(attachment.name);
  const preview = attachment.type.startsWith("image/")
    ? `<img src="${escapeHtml(attachment.dataUrl)}" alt="" />`
    : `<span class="pending-attachment-chip__pdf" aria-hidden="true">PDF</span>`;
  return `
    <div class="pending-attachment-chip">
      <span class="pending-attachment-chip__preview">${preview}</span>
      <span class="pending-attachment-chip__copy">
        <strong title="${safeName}">${safeName}</strong>
        <small>${formatAttachmentSize(attachment.size)}</small>
      </span>
      <button
        type="button"
        data-pending-attachment-id="${safeId}"
        aria-label="Usuń załącznik ${safeName}"
        title="Usuń załącznik"
      >×</button>
    </div>
  `;
}

function renderPendingAttachments() {
  elements.pendingAttachments.hidden = pendingAttachments.length === 0;
  elements.pendingAttachmentList.innerHTML = pendingAttachments.map(createPendingAttachmentChip).join("");
}

function clearNewPolicyAttachments() {
  pendingAttachments = [];
  elements.policyAttachmentInput.value = "";
  renderPendingAttachments();
}

function getAttachmentPanelId(policyId) {
  return `policy-attachments-${String(policyId).replace(/[^a-zA-Z0-9_-]/g, "_")}`;
}

function createAttachmentTile(policy, attachment) {
  const safePolicyId = escapeHtml(policy.id);
  const safeAttachmentId = escapeHtml(attachment.id);
  const safeName = escapeHtml(attachment.name);
  const isPdf = attachment.type === "application/pdf";
  const preview = isPdf || isExternalAttachment(attachment)
    ? `<span
         class="attachment-tile__file-placeholder attachment-tile__file-placeholder--loading"
         data-attachment-preview="true"
         data-policy-id="${safePolicyId}"
         data-attachment-id="${safeAttachmentId}"
         aria-hidden="true"
       >${isPdf ? "PDF" : "IMG"}</span>`
    : `<img src="${escapeHtml(attachment.dataUrl)}" alt="Podgląd pliku ${safeName}" loading="lazy" />`;

  return `
    <article class="attachment-tile">
      <div class="attachment-tile__preview">
        ${preview}
        <button
          class="attachment-tile__open"
          type="button"
          data-action="open-attachment"
          data-policy-id="${safePolicyId}"
          data-attachment-id="${safeAttachmentId}"
          aria-label="Otwórz załącznik ${safeName}"
          title="Otwórz załącznik"
        >
          <svg viewBox="0 0 20 20" fill="none" aria-hidden="true">
            <path d="M7 4H4v12h12v-3M10 4h6v6M9 11l7-7" />
          </svg>
        </button>
        <span class="attachment-tile__type">${escapeHtml(getAttachmentTypeLabel(attachment))}</span>
      </div>
      <div class="attachment-tile__meta">
        <span>
          <strong title="${safeName}">${safeName}</strong>
          <small>${formatAttachmentSize(attachment.size)}</small>
        </span>
        <button
          class="attachment-tile__remove"
          type="button"
          data-action="remove-attachment"
          data-policy-id="${safePolicyId}"
          data-attachment-id="${safeAttachmentId}"
          aria-label="Usuń załącznik ${safeName}"
          title="Usuń załącznik"
        >×</button>
      </div>
    </article>
  `;
}

async function renderPdfAttachmentPreview(target, policyId, attachment) {
  const pdfjs = globalThis.pdfjsLib;
  if (!pdfjs?.getDocument) throw new Error("Brakuje lokalnego modułu PDF.js.");
  if (pdfjs.GlobalWorkerOptions && !pdfjs.GlobalWorkerOptions.workerSrc) {
    pdfjs.GlobalWorkerOptions.workerSrc = "pliki/vendor/pdf.worker.min.js";
  }

  const attachmentBlob = await getPolicyAttachmentBlob(attachment);
  const bytes = new Uint8Array(await attachmentBlob.arrayBuffer());
  const loadingTask = pdfjs.getDocument({
    data: bytes,
    isEvalSupported: false,
    stopAtErrors: false,
  });
  let documentProxy = null;
  let page = null;

  try {
    documentProxy = await loadingTask.promise;
    if (!target.isConnected || expandedPolicyId !== policyId) return;
    page = await documentProxy.getPage(1);
    const baseViewport = page.getViewport({ scale: 1 });
    const scale = Math.min(1.5, 480 / Math.max(1, baseViewport.width));
    const viewport = page.getViewport({ scale });
    const canvas = document.createElement("canvas");
    const canvasContext = canvas.getContext("2d", { alpha: false });
    if (!canvasContext) throw new Error("Przeglądarka nie może utworzyć miniatury PDF.");
    canvas.className = "attachment-tile__pdf-preview";
    canvas.width = Math.max(1, Math.ceil(viewport.width));
    canvas.height = Math.max(1, Math.ceil(viewport.height));
    canvas.setAttribute("aria-hidden", "true");
    await page.render({
      canvasContext,
      viewport,
      background: "rgb(255, 255, 255)",
    }).promise;
    if (!target.isConnected || expandedPolicyId !== policyId) return;
    target.replaceWith(canvas);
  } finally {
    page?.cleanup();
    if (documentProxy) await documentProxy.destroy();
    else if (typeof loadingTask.destroy === "function") await loadingTask.destroy();
  }
}

async function loadAttachmentPreviews(policyId) {
  if (!policyId || expandedPolicyId !== policyId) return;
  const policy = policies.find((item) => item.id === policyId);
  const panel = document.getElementById(getAttachmentPanelId(policyId));
  if (!policy || !panel) return;

  const previewTargets = [...panel.querySelectorAll("[data-attachment-preview]")]
    .filter((target) => target.dataset.previewLoading !== "true");

  await Promise.all(previewTargets.map(async (target) => {
    const attachment = policy.attachments?.find((item) => item.id === target.dataset.attachmentId);
    if (!attachment) return;
    const isPdf = attachment.type === "application/pdf";
    if (!isPdf && !isExternalAttachment(attachment)) return;
    
    
    if (isExternalAttachment(attachment) && !attachmentsBaseDirectoryHandle) return;
    target.dataset.previewLoading = "true";

    try {
      if (isPdf) {
        await renderPdfAttachmentPreview(target, policyId, attachment);
        return;
      }
      const attachmentFile = await (await getExternalAttachmentFileHandle(attachment)).getFile();
      const previewUrl = URL.createObjectURL(attachmentFile);
      if (!target.isConnected || expandedPolicyId !== policyId) {
        URL.revokeObjectURL(previewUrl);
        return;
      }

      const previewImage = document.createElement("img");
      previewImage.alt = `Podgląd pliku ${attachment.name}`;
      previewImage.loading = "lazy";
      previewImage.addEventListener("load", () => URL.revokeObjectURL(previewUrl), { once: true });
      previewImage.addEventListener("error", () => URL.revokeObjectURL(previewUrl), { once: true });
      previewImage.src = previewUrl;
      target.replaceWith(previewImage);
    } catch {
      target.classList.remove("attachment-tile__file-placeholder--loading");
      target.classList.add("attachment-tile__file-placeholder--error");
      target.title = "Nie udało się wczytać miniatury. Kliknij kafelek, aby spróbować otworzyć plik.";
    }
  }));
}





function getAttachmentCategoryRank(categoryName) {
  const foldedName = categoryName.toLocaleLowerCase("pl");
  if (foldedName === DEFAULT_ATTACHMENT_CATEGORY.toLocaleLowerCase("pl")) return 0;
  if (foldedName === ATTACHMENT_PHOTOS_CATEGORY.toLocaleLowerCase("pl")) return Number.MAX_SAFE_INTEGER;
  const presetIndex = ATTACHMENT_CATEGORY_PRESETS
    .findIndex((name) => name.toLocaleLowerCase("pl") === foldedName);
  return presetIndex >= 0 ? presetIndex : ATTACHMENT_CATEGORY_PRESETS.length;
}

function groupPolicyAttachmentsByCategory(attachments) {
  const groups = new Map();
  for (const attachment of attachments) {
    const categoryName = String(attachment.category ?? "").trim() || DEFAULT_ATTACHMENT_CATEGORY;
    if (!groups.has(categoryName)) groups.set(categoryName, []);
    groups.get(categoryName).push(attachment);
  }
  return [...groups.entries()].sort((first, second) => {
    const firstOrder = getAttachmentCategoryRank(first[0]);
    const secondOrder = getAttachmentCategoryRank(second[0]);
    if (firstOrder !== secondOrder) return firstOrder - secondOrder;
    return first[0].localeCompare(second[0], "pl", { sensitivity: "base" });
  });
}

function createAttachmentSections(policy, attachments) {
  return groupPolicyAttachmentsByCategory(attachments).map(([categoryName, categoryAttachments]) => `
    <section class="attachment-section" aria-label="Załączniki: ${escapeHtml(categoryName)}">
      <h4 class="attachment-section__label" title="${escapeHtml(categoryName)}">${escapeHtml(categoryName)}</h4>
      <span class="attachment-section__divider" aria-hidden="true"></span>
      <div class="attachment-tiles">${categoryAttachments.map((attachment) => createAttachmentTile(policy, attachment)).join("")}</div>
    </section>
  `).join("");
}

function createAttachmentsPanel(policy) {
  const attachments = normalizePolicyAttachments(policy.attachments);
  const safeId = escapeHtml(policy.id);
  const folderPath = escapeHtml(getPolicyAttachmentDirectoryPath(policy.clientName, policy.policyNumber).join("\\"));
  return `
    <section
      id="${escapeHtml(getAttachmentPanelId(policy.id))}"
      class="attachments-panel attachments-panel--opening"
      data-attachment-drop-policy-id="${safeId}"
      aria-label="Załączniki rekordu ${escapeHtml(policy.clientName || policy.policyNumber || "polisy")}"
    >
      <div class="attachments-panel__clip">
        <div class="attachments-panel__content">
        <header class="attachments-panel__header">
          <div>
            <span class="attachments-panel__icon" aria-hidden="true">
              <svg viewBox="0 0 20 20" fill="none">
                <path d="m7.2 10.8 5.4-5.4a2.35 2.35 0 0 1 3.3 3.3l-7.2 7.2a3.65 3.65 0 0 1-5.2-5.1l7-7a2.45 2.45 0 0 1 3.45 3.45l-6.7 6.7a1.25 1.25 0 0 1-1.8-1.75l5.9-5.9" />
              </svg>
            </span>
            <span>
              <strong>Załączniki</strong>
              <small>${attachments.length > 0 ? `${pluralizeAttachments(attachments.length)} - kliknij kafelek, aby otworzyć lub przeciągnij tu nowe pliki` : "Brak załączników - przeciągnij pliki tutaj lub użyj przycisku Dodaj pliki"}</small>
            </span>
          </div>
          <span class="attachments-panel__actions">
            ${attachments.length > 0
              ? `<button class="attachments-panel__download" type="button" data-action="download-attachments" data-policy-id="${safeId}">
                   <svg viewBox="0 0 20 20" fill="none" aria-hidden="true">
                     <path d="M10 3v9m0 0 4-4m-4 4-4-4M4 16h12" />
                   </svg>
                   Pobierz wszystko
                 </button>`
              : ""}
            <button class="attachments-panel__add" type="button" data-action="add-attachments" data-policy-id="${safeId}">
              <svg viewBox="0 0 20 20" fill="none" aria-hidden="true">
                <path d="M10 4v12M4 10h12" />
              </svg>
              Dodaj pliki
            </button>
          </span>
        </header>
        ${attachments.length > 0
          ? `<div class="attachment-sections">${createAttachmentSections(policy, attachments)}</div>`
          : `<div class="attachments-panel__empty">
               <span>Przeciągnij lub dodaj dowolny plik w formacie PDF, JPG, PNG lub WEBP</span>
               <small>Pliki znajdują się w folderze - ${folderPath}</small>
             </div>`}
        </div>
      </div>
    </section>
  `;
}

function startAttachmentPanelOpenTransition(policyId) {
  const panel = document.getElementById(getAttachmentPanelId(policyId));
  if (!panel) return;
  if (globalThis.matchMedia?.("(prefers-reduced-motion: reduce)").matches) {
    panel.classList.remove("attachments-panel--opening");
    return;
  }
  requestAnimationFrame(() => {
    if (panel.isConnected) panel.classList.remove("attachments-panel--opening");
  });
}

function expandPolicyAttachmentsInPlace(policyId) {
  const policy = policies.find((item) => item.id === policyId);
  const entry = elements.rows.querySelector(`[data-policy-entry="${CSS.escape(policyId)}"]`);
  if (!policy || !entry || entry.querySelector("[data-edit-form]")) return false;
  entry.classList.add("policy-entry--expanded");
  const button = entry.querySelector('[data-action="toggle-attachments"]');
  button?.classList.add("attachment-button--active");
  button?.setAttribute("aria-expanded", "true");
  entry.insertAdjacentHTML("beforeend", createAttachmentsPanel(policy));
  startAttachmentPanelOpenTransition(policyId);
  return true;
}

async function closePolicyAttachments(policyId) {
  const panel = document.getElementById(getAttachmentPanelId(policyId));
  expandedPolicyId = null;
  if (!panel) {
    render();
    return;
  }

  const entry = panel.closest("[data-policy-entry]");
  const button = entry?.querySelector('[data-action="toggle-attachments"]');
  entry?.classList.remove("policy-entry--expanded");
  button?.classList.remove("attachment-button--active");
  button?.setAttribute("aria-expanded", "false");

  if (globalThis.matchMedia?.("(prefers-reduced-motion: reduce)").matches) {
    panel.remove();
    return;
  }

  attachmentPanelTransitioning = true;
  panel.classList.remove("attachments-panel--opening");
  panel.classList.add("attachments-panel--closing");

  try {
    await new Promise((resolve) => {
      let finished = false;
      const finish = () => {
        if (finished) return;
        finished = true;
        clearTimeout(fallbackTimer);
        panel.removeEventListener("transitionend", handleTransitionEnd);
        resolve();
      };
      const handleTransitionEnd = (event) => {
        if (event.target === panel && event.propertyName === "grid-template-rows") finish();
      };
      const fallbackTimer = setTimeout(finish, 360);
      panel.addEventListener("transitionend", handleTransitionEnd);
    });
  } finally {
    attachmentPanelTransitioning = false;
    panel.remove();
  }
}

async function togglePolicyAttachments(policyId) {
  if (attachmentPanelTransitioning) return;
  const previouslyExpandedPolicyId = expandedPolicyId;
  if (previouslyExpandedPolicyId) {
    await closePolicyAttachments(previouslyExpandedPolicyId);
    if (previouslyExpandedPolicyId === policyId) return;
  }

  expandedPolicyId = policyId;
  if (!expandPolicyAttachmentsInPlace(policyId)) render();
  void loadAttachmentPreviews(policyId);
  const canScanFolders = typeof globalThis.showDirectoryPicker === "function"
    || Boolean(attachmentsBaseDirectoryHandle || rememberedAttachmentsBaseDirectoryHandle);
  if (!canScanFolders || attachmentOperationActive) return;

  let runFullReconcileAfterOperation = false;
  startAttachmentOperation(1, "Sprawdzanie folderu polisy");
  try {
    if (!(await ensureWritableDataFile({ deferFreshnessCheck: true }))) return;
    const policy = policies.find((item) => item.id === policyId);
    if (!policy) return;
    const baseDirectory = await ensureAttachmentsBaseDirectory();
    updateAttachmentOperation(
      "Sprawdzanie folderu polisy",
      1,
      1,
      policy.policyNumber || policy.clientName || "Rekord bez nazwy",
    );
    let activeScannedPolicy = policy;
    let previousAttachments = policy.attachments;
    let previousUpdatedAt = policy.updatedAt;
    let result = await syncPolicyAttachmentsFromFolder(policy, baseDirectory);
    if (result.changed) {
      const reapplyFolderScan = async () => {
        const currentPolicy = policies.find((item) => item.id === policyId);
        if (!currentPolicy) return false;
        if (currentPolicy !== activeScannedPolicy) {
          activeScannedPolicy = currentPolicy;
          previousAttachments = currentPolicy.attachments;
          previousUpdatedAt = currentPolicy.updatedAt;
        }
        result = await syncPolicyAttachmentsFromFolder(currentPolicy, baseDirectory);
        return true;
      };
      if (!(await persistPolicies({
        reapplyAfterConflict: reapplyFolderScan,
        reapplyFailureMessage: "Rekord został usunięty w nowszej wersji bazy. Skan folderu nie został zapisany.",
      }))) {
        if (policies.includes(activeScannedPolicy)) {
          activeScannedPolicy.attachments = previousAttachments;
          activeScannedPolicy.updatedAt = previousUpdatedAt;
          markPoliciesRolledBack();
        }
        render();
        return;
      }
      render();
    }
    const folderScanReport = [];
    if (result.discoveredCount > 0) {
      folderScanReport.push(`${pluralizeAttachments(result.discoveredCount)} znaleziono w folderze polisy`);
    }
    if (result.removedCount > 0) {
      folderScanReport.push(
        result.removedCount === 1
          ? "usunięto 1 nieaktualne odwołanie do brakującego załącznika"
          : `usunięto ${result.removedCount} nieaktualnych odwołań do brakujących załączników`,
      );
    }
    if (folderScanReport.length > 0) showToast(folderScanReport.join(". "));
    await loadAttachmentPreviews(policyId);
    runFullReconcileAfterOperation = true;
  } catch (error) {
    if (error?.name !== "AbortError") {
      showToast(error?.message || "Nie udało się sprawdzić folderu załączników");
    }
  } finally {
    if (attachmentOperationActive) finishAttachmentOperation();
    if (runFullReconcileAfterOperation) void reconcileAttachmentsFromFolder();
  }
}

function attachmentDataUrlToBlob(attachment) {
  const separatorIndex = attachment.dataUrl.indexOf(",");
  if (separatorIndex < 0) throw new Error("Nieprawidłowe dane załącznika.");
  const binary = globalThis.atob(attachment.dataUrl.slice(separatorIndex + 1));
  const bytes = new Uint8Array(binary.length);
  for (let index = 0; index < binary.length; index += 1) bytes[index] = binary.charCodeAt(index);
  return new Blob([bytes], { type: attachment.type });
}

async function getPolicyAttachmentBlob(attachment) {
  return isExternalAttachment(attachment)
    ? (await getExternalAttachmentFileHandle(attachment)).getFile()
    : attachmentDataUrlToBlob(attachment);
}

function getZipCrc32Table() {
  if (zipCrc32Table) return zipCrc32Table;
  zipCrc32Table = new Uint32Array(256);
  for (let value = 0; value < 256; value += 1) {
    let crc = value;
    for (let bit = 0; bit < 8; bit += 1) {
      crc = (crc & 1) ? (0xedb88320 ^ (crc >>> 1)) : (crc >>> 1);
    }
    zipCrc32Table[value] = crc >>> 0;
  }
  return zipCrc32Table;
}

function calculateZipCrc32(bytes) {
  const table = getZipCrc32Table();
  let crc = 0xffffffff;
  for (const byte of bytes) crc = table[(crc ^ byte) & 0xff] ^ (crc >>> 8);
  return (crc ^ 0xffffffff) >>> 0;
}

function getZipDosDateTime(timestamp) {
  let date = new Date(timestamp);
  if (Number.isNaN(date.getTime())) date = new Date();
  const year = Math.min(2107, Math.max(1980, date.getFullYear()));
  return {
    date: ((year - 1980) << 9) | ((date.getMonth() + 1) << 5) | date.getDate(),
    time: (date.getHours() << 11) | (date.getMinutes() << 5) | Math.floor(date.getSeconds() / 2),
  };
}

function getUniqueZipEntryName(name, usedNames) {
  const safeName = sanitizePathPart(name, "zalacznik", 170);
  const dotIndex = safeName.lastIndexOf(".");
  const baseName = dotIndex > 0 ? safeName.slice(0, dotIndex) : safeName;
  const extension = dotIndex > 0 ? safeName.slice(dotIndex) : "";
  let candidate = safeName;
  let suffix = 2;
  while (usedNames.has(candidate.toLocaleLowerCase("pl"))) {
    candidate = `${baseName} (${suffix})${extension}`;
    suffix += 1;
  }
  usedNames.add(candidate.toLocaleLowerCase("pl"));
  return candidate;
}

function createZipLocalHeader(entry) {
  const header = new Uint8Array(30 + entry.nameBytes.length);
  const view = new DataView(header.buffer);
  view.setUint32(0, 0x04034b50, true);
  view.setUint16(4, 20, true);
  view.setUint16(6, 0x0800, true);
  view.setUint16(8, 0, true);
  view.setUint16(10, entry.time, true);
  view.setUint16(12, entry.date, true);
  view.setUint32(14, entry.crc32, true);
  view.setUint32(18, entry.size, true);
  view.setUint32(22, entry.size, true);
  view.setUint16(26, entry.nameBytes.length, true);
  view.setUint16(28, 0, true);
  header.set(entry.nameBytes, 30);
  return header;
}

function createZipCentralHeader(entry) {
  const header = new Uint8Array(46 + entry.nameBytes.length);
  const view = new DataView(header.buffer);
  view.setUint32(0, 0x02014b50, true);
  view.setUint16(4, 20, true);
  view.setUint16(6, 20, true);
  view.setUint16(8, 0x0800, true);
  view.setUint16(10, 0, true);
  view.setUint16(12, entry.time, true);
  view.setUint16(14, entry.date, true);
  view.setUint32(16, entry.crc32, true);
  view.setUint32(20, entry.size, true);
  view.setUint32(24, entry.size, true);
  view.setUint16(28, entry.nameBytes.length, true);
  view.setUint16(30, 0, true);
  view.setUint16(32, 0, true);
  view.setUint16(34, 0, true);
  view.setUint16(36, 0, true);
  view.setUint32(38, 0, true);
  view.setUint32(42, entry.localOffset, true);
  header.set(entry.nameBytes, 46);
  return header;
}

async function createAttachmentsZip(attachments) {
  const encoder = new TextEncoder();
  const usedNames = new Set();
  const entries = [];
  const localParts = [];
  let localOffset = 0;

  for (let index = 0; index < attachments.length; index += 1) {
    const attachment = attachments[index];
    updateAttachmentOperation("Pakowanie załączników", index + 1, attachments.length, attachment.name);
    const attachmentBlob = await getPolicyAttachmentBlob(attachment);
    const bytes = new Uint8Array(await attachmentBlob.arrayBuffer());
    const fileName = getUniqueZipEntryName(attachment.name, usedNames);
    const dosDateTime = getZipDosDateTime(attachment.createdAt || attachmentBlob.lastModified);
    const entry = {
      nameBytes: encoder.encode(fileName),
      size: bytes.byteLength,
      crc32: calculateZipCrc32(bytes),
      date: dosDateTime.date,
      time: dosDateTime.time,
      localOffset,
    };
    const localHeader = createZipLocalHeader(entry);
    localParts.push(localHeader, bytes);
    localOffset += localHeader.byteLength + bytes.byteLength;
    entries.push(entry);
  }

  const centralParts = entries.map(createZipCentralHeader);
  const centralSize = centralParts.reduce((sum, part) => sum + part.byteLength, 0);
  const endHeader = new Uint8Array(22);
  const endView = new DataView(endHeader.buffer);
  endView.setUint32(0, 0x06054b50, true);
  endView.setUint16(4, 0, true);
  endView.setUint16(6, 0, true);
  endView.setUint16(8, entries.length, true);
  endView.setUint16(10, entries.length, true);
  endView.setUint32(12, centralSize, true);
  endView.setUint32(16, localOffset, true);
  endView.setUint16(20, 0, true);
  return new Blob([...localParts, ...centralParts, endHeader], { type: "application/zip" });
}

async function downloadPolicyAttachments(policyId) {
  const policy = policies.find((item) => item.id === policyId);
  const attachments = normalizePolicyAttachments(policy?.attachments);
  if (!policy || attachments.length === 0 || attachmentOperationActive) return;
  startAttachmentOperation(attachments.length, "Pakowanie załączników");

  try {
    const archive = await createAttachmentsZip(attachments);
    const archiveBaseName = [policy.clientName, policy.policyNumber].filter(Boolean).join(" - ");
    const archiveName = `${sanitizePathPart(archiveBaseName, "Zalaczniki", 160)}.zip`;
    const archiveUrl = URL.createObjectURL(archive);
    const link = document.createElement("a");
    link.href = archiveUrl;
    link.download = archiveName;
    link.hidden = true;
    document.body.append(link);
    link.click();
    link.remove();
    globalThis.setTimeout(() => URL.revokeObjectURL(archiveUrl), 60_000);
    showToast(`Pobrano ${pluralizeAttachments(attachments.length)} w archiwum ZIP`);
  } catch (error) {
    showToast(error?.name === "AbortError" ? "Nie wybrano folderu Baza Polis" : (error?.message || "Nie udało się pobrać załączników"));
  } finally {
    finishAttachmentOperation();
  }
}

async function openPolicyAttachment(policyId, attachmentId) {
  const policy = policies.find((item) => item.id === policyId);
  const attachment = policy?.attachments?.find((item) => item.id === attachmentId);
  if (!attachment) return;
  const previewWindow = isExternalAttachment(attachment) ? globalThis.open("", "_blank") : null;

  try {
    const attachmentBlob = await getPolicyAttachmentBlob(attachment);
    const url = URL.createObjectURL(attachmentBlob);
    if (previewWindow && !previewWindow.closed) {
      previewWindow.location.replace(url);
    } else {
      const link = document.createElement("a");
      link.href = url;
      link.target = "_blank";
      link.rel = "noopener noreferrer";
      link.click();
    }
    globalThis.setTimeout(() => URL.revokeObjectURL(url), 60_000);
  } catch (error) {
    if (previewWindow && !previewWindow.closed) previewWindow.close();
    showToast(error?.message || "Nie udało się otworzyć załącznika");
  }
}

async function removePolicyAttachment(policyId, attachmentId) {
  const initialPolicy = policies.find((item) => item.id === policyId);
  const initialAttachment = initialPolicy?.attachments?.find((item) => item.id === attachmentId);
  if (!initialPolicy || !initialAttachment) return;
  const confirmed = typeof globalThis.confirm === "function"
    ? globalThis.confirm(`Usunąć załącznik „${initialAttachment.name}”?`)
    : true;
  if (!confirmed) return;
  if (!(await ensureWritableDataFile({ deferFreshnessCheck: true }))) return;
  const policy = policies.find((item) => item.id === policyId);
  const attachment = policy?.attachments?.find((item) => item.id === attachmentId);
  if (!policy || !attachment) {
    showToast("Załącznika nie ma już w aktualnej wersji bazy");
    return;
  }
  let attachmentToDelete = attachment;
  if (isExternalAttachment(attachmentToDelete)) {
    try {
      await ensureAttachmentsBaseDirectory();
    } catch (error) {
      showToast(error?.name === "AbortError" ? "Nie wybrano folderu Baza Polis" : (error?.message || "Brak dostępu do folderu załączników"));
      return;
    }
  }
  const previousAttachments = policy.attachments;
  const previousUpdatedAt = policy.updatedAt;
  let activePolicy = policy;
  let rollbackAttachments = previousAttachments;
  let rollbackUpdatedAt = previousUpdatedAt;
  const reapplyAttachmentRemoval = () => {
    const currentPolicy = policies.find((item) => item.id === policyId);
    if (!currentPolicy) return false;
    if (currentPolicy !== activePolicy) {
      activePolicy = currentPolicy;
      rollbackAttachments = currentPolicy.attachments;
      rollbackUpdatedAt = currentPolicy.updatedAt;
    }
    const currentAttachments = normalizePolicyAttachments(currentPolicy.attachments);
    attachmentToDelete = currentAttachments.find((item) => item.id === attachmentId) || attachmentToDelete;
    currentPolicy.attachments = currentAttachments.filter((item) => item.id !== attachmentId);
    currentPolicy.updatedAt = Date.now();
    return true;
  };
  reapplyAttachmentRemoval();
  if (!(await persistPolicies({
    reapplyAfterConflict: reapplyAttachmentRemoval,
    reapplyFailureMessage: "Rekord został usunięty w nowszej wersji bazy. Załącznik nie został usunięty.",
  }))) {
    if (policies.includes(activePolicy)) {
      activePolicy.attachments = rollbackAttachments;
      activePolicy.updatedAt = rollbackUpdatedAt;
      markPoliciesRolledBack();
    }
    render();
    return;
  }
  let removedFromFolder = true;
  if (isExternalAttachment(attachmentToDelete)) {
    
    
    const filesToDelete = getUnsharedAttachmentsForDeletion([attachmentToDelete]);
    removedFromFolder = filesToDelete.length > 0
      ? await deleteExternalAttachmentFiles(filesToDelete)
      : false;
  }
  expandedPolicyId = policyId;
  render();
  showToast(
    removedFromFolder
      ? "Załącznik został usunięty"
      : "Usunięto z rekordu, ale plik pozostał w folderze",
    removedFromFolder ? "success" : "warning",
  );
}

async function addPendingAttachmentFiles(fileList) {
  const selectedFiles = [...(fileList ?? [])];
  if (selectedFiles.length === 0 || attachmentOperationActive) return;
  startAttachmentOperation(selectedFiles.length);
  try {
    await ensureAttachmentsBaseDirectory();
    const newAttachments = await createAttachmentsFromFiles(
      selectedFiles,
      pendingAttachments,
      updateAttachmentOperation,
    );
    if (newAttachments.length === 0) return;
    pendingAttachments = [...pendingAttachments, ...newAttachments];
    renderPendingAttachments();
    showToast(`${pluralizeAttachments(newAttachments.length)} przygotowano do zapisu w folderze`);
  } catch (error) {
    showToast(error?.name === "AbortError" ? "Nie wybrano folderu Baza Polis" : (error?.message || "Nie udało się dodać załącznika"));
  } finally {
    elements.policyAttachmentInput.value = "";
    finishAttachmentOperation();
  }
}

function getPolicyImportErrorMessage(error) {
  if (error?.name === "PasswordException") return "Polisa jest zabezpieczona hasłem. Zapisz niezabezpieczoną kopię PDF i spróbuj ponownie.";
  if (error?.code === "PDF_TEXT_MISSING") return error.message;
  if (error?.code === "POLICY_OFFER") return error.message;
  if (error?.code === "UNSUPPORTED_POLICY") return error.message;
  if (error?.code === "POLICY_FIELDS_MISSING") return `${error.message} To może być inny wzór dokumentu ${error.insurer || "ubezpieczyciela"}.`;
  if (error?.code === "PDF_ENGINE_MISSING") return error.message;
  if (/invalid pdf|missing pdf|format error/i.test(String(error?.message ?? ""))) {
    return "Nie udało się otworzyć tego PDF-u. Plik może być uszkodzony albo nie być prawidłowym dokumentem PDF.";
  }
  return error?.message || "Nie udało się odczytać polisy.";
}














const POLICY_ATTACHMENT_ENRICHMENT_VERSION = "pdf-risk-v8";

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

function normalizeImportedPolicyFieldValue(fieldName, value) {
  if (fieldName === "registration") return normalizeRegistration(value);
  if (fieldName === "vehicleMake" || fieldName === "vehicleModel" || fieldName === "vehicleType") {
    return normalizeVehicleDetail(value);
  }
  if (fieldName === "productionYear" || fieldName === "fuelType" || fieldName === "seats" || fieldName === "grossWeight") {
    return normalizeVehicleDetail(value);
  }
  if (fieldName === "engineCapacity" || fieldName === "enginePower" || fieldName === "mileage") {
    return normalizeVehicleDetail(value);
  }
  if (fieldName === "vin") return normalizeVehicleIdentifier(value);
  if (fieldName === "firstRegistrationDate") return normalizeFirstRegistrationDate(value);
  if (fieldName === "issueDate") return normalizeFirstRegistrationDate(value);
  if (fieldName === "driverLicenseDate") return normalizeDriverLicenseDate(value);
  if (fieldName === "clientAddress") return normalizeClientAddress(value);
  if (fieldName === "clientPostalCode") return extractClientPostalCode(value) || normalizeClientPostalCode(value);
  return String(value ?? "").trim();
}

function getImportedPolicySourceValue(importedPolicy, fieldName) {
  return fieldName === "clientPostalCode"
    ? importedPolicy?.clientPostalCode || importedPolicy?.clientAddress
    : importedPolicy?.[fieldName];
}

function normalizeImportedPolicyFieldSnapshot(snapshot) {
  if (!snapshot || typeof snapshot !== "object" || Array.isArray(snapshot)) return {};
  return Object.fromEntries(IMPORTED_POLICY_FILLABLE_FIELDS.flatMap((fieldName) => {
    if (!Object.prototype.hasOwnProperty.call(snapshot, fieldName)) return [];
    const value = normalizeImportedPolicyFieldValue(fieldName, snapshot[fieldName]);
    return isImportedPolicyFieldMissing(value) ? [] : [[fieldName, value]];
  }));
}

function canonicalPolicyDate(value) {
  const parsedDate = parseLocalDate(value);
  return parsedDate ? formatDateForInput(parsedDate) : "";
}

function getAutomaticallyCalculatedValidFrom(policy) {
  const validUntil = canonicalPolicyDate(policy?.validUntil);
  if (!validUntil) return "";
  return formatDateForInput(
    isTravelPolicy(policy)
      ? calculateTravelStartDate(validUntil)
      : calculateStartDate(validUntil),
  );
}

function shouldClearLegacyValidFromFlag(policy) {
  if (policy?.validFromManuallyEdited !== true) return false;
  if (
    Array.isArray(policy.manuallyEditedImportedFields)
    && policy.manuallyEditedImportedFields.includes("validFrom")
  ) return false;
  const actualValidFrom = canonicalPolicyDate(policy.validFrom);
  const calculatedValidFrom = getAutomaticallyCalculatedValidFrom(policy);
  return Boolean(
    actualValidFrom
    && calculatedValidFrom
    && actualValidFrom === calculatedValidFrom
  );
}

function getManuallyEditedImportedPolicyFields(policy) {
  const configuredFields = Array.isArray(policy?.manuallyEditedImportedFields)
    ? policy.manuallyEditedImportedFields
    : [];
  const fields = new Set(configuredFields.filter((fieldName) => (
    IMPORTED_POLICY_FILLABLE_FIELDS.includes(fieldName)
  )));
  Object.entries(IMPORTED_POLICY_LEGACY_MANUAL_FLAGS).forEach(([fieldName, flagName]) => {
    if (fieldName === "validFrom" && shouldClearLegacyValidFromFlag(policy)) return;
    if (policy?.[flagName] === true) fields.add(fieldName);
  });
  return IMPORTED_POLICY_FILLABLE_FIELDS.filter((fieldName) => fields.has(fieldName));
}

function normalizeImportedPolicyTracking(policy) {
  const lastImportedFieldValues = normalizeImportedPolicyFieldSnapshot(policy?.lastImportedFieldValues);
  const manuallyEditedImportedFields = getManuallyEditedImportedPolicyFields(policy);
  return {
    lastImportedFieldValues: Object.keys(lastImportedFieldValues).length > 0
      ? lastImportedFieldValues
      : undefined,
    manuallyEditedImportedFields: manuallyEditedImportedFields.length > 0
      ? manuallyEditedImportedFields
      : undefined,
  };
}

function createImportedPolicyFieldSnapshot(importedPolicy) {
  return normalizeImportedPolicyFieldSnapshot(Object.fromEntries(
    IMPORTED_POLICY_FILLABLE_FIELDS.map((fieldName) => [
      fieldName,
      getImportedPolicySourceValue(importedPolicy, fieldName),
    ]),
  ));
}

function areImportedPolicyFieldValuesEqual(fieldName, firstValue, secondValue) {
  return normalizeImportedPolicyFieldValue(fieldName, firstValue)
    === normalizeImportedPolicyFieldValue(fieldName, secondValue);
}

function isImportedPolicyFieldManuallyProtected(policy, fieldName) {
  return getManuallyEditedImportedPolicyFields(policy).includes(fieldName);
}

function setPolicyImportedFieldsManuallyEdited(policy, fieldNames) {
  if (!policy || !Array.isArray(fieldNames) || fieldNames.length === 0) return [];
  const previousFields = new Set(getManuallyEditedImportedPolicyFields(policy));
  const addedFields = [];
  fieldNames.forEach((fieldName) => {
    if (!IMPORTED_POLICY_FILLABLE_FIELDS.includes(fieldName) || previousFields.has(fieldName)) return;
    previousFields.add(fieldName);
    addedFields.push(fieldName);
  });
  policy.manuallyEditedImportedFields = IMPORTED_POLICY_FILLABLE_FIELDS.filter((fieldName) => (
    previousFields.has(fieldName)
  ));
  Object.entries(IMPORTED_POLICY_LEGACY_MANUAL_FLAGS).forEach(([fieldName, flagName]) => {
    if (previousFields.has(fieldName)) policy[flagName] = true;
  });
  return addedFields;
}

function markImportedPolicyFieldsManuallyEdited(policy, nextValues, { markNonEmpty = false } = {}) {
  if (!policy || !nextValues || typeof nextValues !== "object") return [];
  const changedFields = IMPORTED_POLICY_FILLABLE_FIELDS.filter((fieldName) => {
    if (!Object.prototype.hasOwnProperty.call(nextValues, fieldName)) return false;
    const nextValue = normalizeImportedPolicyFieldValue(fieldName, nextValues[fieldName]);
    return markNonEmpty
      ? !isImportedPolicyFieldMissing(nextValue)
      : !areImportedPolicyFieldValuesEqual(fieldName, policy[fieldName], nextValue);
  });
  return setPolicyImportedFieldsManuallyEdited(policy, changedFields);
}

function getImportedPolicyFieldSyncPlan(existingPolicy, importedPolicy) {
  const previousSnapshot = normalizeImportedPolicyFieldSnapshot(existingPolicy?.lastImportedFieldValues);
  const nextSnapshot = { ...previousSnapshot };
  const values = {};
  const changedFieldNames = new Set();

  IMPORTED_POLICY_FILLABLE_FIELDS.forEach((fieldName) => {
    const importedValue = normalizeImportedPolicyFieldValue(
      fieldName,
      getImportedPolicySourceValue(importedPolicy, fieldName),
    );
    if (isImportedPolicyFieldMissing(importedValue)) return;

    const currentValue = normalizeImportedPolicyFieldValue(fieldName, existingPolicy?.[fieldName]);
    const hasPreviousImportedValue = Object.prototype.hasOwnProperty.call(previousSnapshot, fieldName);
    if (!hasPreviousImportedValue && !isImportedPolicyFieldMissing(currentValue)) {
      
      
      nextSnapshot[fieldName] = currentValue;
      changedFieldNames.add(fieldName);
      return;
    }

    const previousImportedValue = hasPreviousImportedValue ? previousSnapshot[fieldName] : "";
    if (!hasPreviousImportedValue || previousImportedValue !== importedValue) {
      nextSnapshot[fieldName] = importedValue;
      changedFieldNames.add(fieldName);
    }

    if (isImportedPolicyFieldMissing(currentValue)) {
      
      
      if (isImportedPolicyFieldManuallyProtected(existingPolicy, fieldName)) return;
      values[fieldName] = importedValue;
      changedFieldNames.add(fieldName);
      return;
    }
    if (
      !isImportedPolicyFieldManuallyProtected(existingPolicy, fieldName)
      && hasPreviousImportedValue
      && areImportedPolicyFieldValuesEqual(fieldName, currentValue, previousImportedValue)
      && !areImportedPolicyFieldValuesEqual(fieldName, currentValue, importedValue)
    ) {
      values[fieldName] = importedValue;
      changedFieldNames.add(fieldName);
    }
  });

  return {
    values,
    nextSnapshot,
    snapshotChanged: JSON.stringify(previousSnapshot) !== JSON.stringify(nextSnapshot),
    changedFieldNames: [...changedFieldNames],
  };
}

function getMissingImportedPolicyFieldValues(existingPolicy, importedPolicy) {
  return getImportedPolicyFieldSyncPlan(existingPolicy, importedPolicy).values;
}

function getAttachmentImportedPolicyFieldValues(existingPolicy, importedPolicy) {
  return getImportedPolicyFieldSyncPlan(existingPolicy, importedPolicy).values;
}

function applyImportedPolicyFieldSync(existingPolicy, importedPolicy) {
  const plan = getImportedPolicyFieldSyncPlan(existingPolicy, importedPolicy);
  Object.assign(existingPolicy, plan.values);
  if (plan.snapshotChanged) existingPolicy.lastImportedFieldValues = plan.nextSnapshot;
  return plan.changedFieldNames;
}

function applyAttachmentImportedPolicyFields(existingPolicy, importedPolicy) {
  return applyImportedPolicyFieldSync(existingPolicy, importedPolicy);
}

function applyMissingImportedPolicyFields(existingPolicy, importedPolicy) {
  return applyImportedPolicyFieldSync(existingPolicy, importedPolicy);
}





const POLICY_BUYER_TRANSFER_CLIENT_FIELDS = Object.freeze([
  "clientName",
  "identityNumber",
  "secondaryIdentityNumber",
  "contact",
  "clientPhone",
  "clientEmail",
  "clientAddress",
  "clientPostalCode",
  "driverLicenseDate",
  "premium",
]);
const POLICY_BUYER_TRANSFER_TARGET_STATE_FIELDS = Object.freeze([
  ...POLICY_BUYER_TRANSFER_CLIENT_FIELDS,
  "renewalStatus",
  "previousPolicyId",
  "transferredToBuyer",
  "buyerName",
  "buyerIdentityNumber",
  "buyerSnapshot",
  "transferDetectedAt",
  "updatedAt",
]);
const POLICY_BUYER_TRANSFER_RELATED_STATE_FIELDS = Object.freeze([
  "renewalStatus",
  "previousPolicyId",
  "updatedAt",
]);
const POLICY_BUYER_SNAPSHOT_FIELDS = Object.freeze([
  ...POLICY_BUYER_TRANSFER_CLIENT_FIELDS,
  "premiumManuallyEdited",
  "renewalStatus",
  "previousPolicyId",
]);
const CLIENT_NAME_UNCERTAIN_TOKENS = new Set([
  "agent", "agencja", "biuro", "firma", "group", "grupa", "handel", "ltd",
  "polska", "przedsiebiorstwo", "service", "spolka", "uslugi", "ubezpieczenia",
  "adam", "adrian", "agnieszka", "aleksandra", "anna", "barbara", "beata",
  "daniel", "dariusz", "dorota", "ewa", "grzegorz", "jan", "joanna",
  "jolanta", "kamil", "karolina", "katarzyna", "krzysztof", "lukasz",
  "magdalena", "malgorzata", "marcin", "marek", "mariusz", "marta",
  "mateusz", "michal", "monika", "natalia", "pawel", "piotr", "rafal",
  "robert", "tomasz", "wojciech", "zbigniew",
]);
const CLIENT_NAME_ORGANIZATION_TOKENS = new Set([
  "agencja", "biuro", "firma", "group", "grupa", "handel", "pracownia",
  "ltd", "przedsiebiorstwo", "service", "spolka", "uslugi", "ubezpieczenia",
]);

function createPolicyBuyerTransferFeatureDisabledError() {
  const error = new Error("Funkcja „pojazd zbyty” jest wyłączona.");
  error.code = "FEATURE_DISABLED";
  return error;
}

function normalizeClientNameTokens(value) {
  return String(value ?? "")
    .toLocaleLowerCase("pl")
    .replace(/ł/g, "l")
    .normalize("NFD")
    .replace(/[̀-ͯ]/g, "")
    .split(/[^a-z0-9]+/)
    .filter((token) => token.length >= 3 && !/^\d+$/.test(token));
}

function clientNameLooksOrganizational(value, tokens = normalizeClientNameTokens(value)) {
  const normalizedValue = String(value ?? "").toLocaleLowerCase("pl");
  return tokens.some((token) => CLIENT_NAME_ORGANIZATION_TOKENS.has(token))
    || /\b(?:sp\.?\s*z\s*o\.?\s*o\.?|s\.?\s*c\.?|s\.?\s*a\.?|fundacja|stowarzyszenie)\b/i.test(normalizedValue);
}

function getClientNameRelationship(firstName, secondName) {
  const firstTokens = normalizeClientNameTokens(firstName);
  const secondTokens = normalizeClientNameTokens(secondName);
  if (firstTokens.length === 0 || secondTokens.length === 0) return "uncertain";
  const firstSet = new Set(firstTokens);
  const secondSet = new Set(secondTokens);
  if (
    firstSet.size === secondSet.size
    && [...firstSet].every((token) => secondSet.has(token))
  ) return "same";

  const firstDistinctive = firstTokens.filter((token) => !CLIENT_NAME_UNCERTAIN_TOKENS.has(token));
  const secondDistinctive = secondTokens.filter((token) => !CLIENT_NAME_UNCERTAIN_TOKENS.has(token));
  if (firstDistinctive.length === 0 || secondDistinctive.length === 0) return "uncertain";
  if (firstDistinctive.some((token) => secondDistinctive.includes(token))) return "same";
  if (firstTokens.length < 2 || secondTokens.length < 2) return "uncertain";
  if (
    clientNameLooksOrganizational(firstName, firstTokens)
    || clientNameLooksOrganizational(secondName, secondTokens)
  ) return "uncertain";

  
  
  return "different";
}

function clientNamesLookRelated(firstName, secondName) {
  return getClientNameRelationship(firstName, secondName) !== "different";
}

function getPolicyTransferIdentityValues(policy) {
  const values = [policy?.identityNumber, policy?.secondaryIdentityNumber]
    .map((value) => String(value ?? "").replace(/\D/g, ""))
    .filter((value) => value.length >= 9 && value.length <= 14);
  return [...new Set(values)];
}

function capturePolicyFields(policy, fieldNames) {
  return fieldNames.map((fieldName) => ({
    fieldName,
    exists: Object.prototype.hasOwnProperty.call(policy, fieldName),
    value: policy[fieldName],
  }));
}

function restorePolicyFields(policy, fieldStates) {
  (fieldStates || []).forEach((fieldState) => {
    if (!fieldState) return;
    if (fieldState.exists) policy[fieldState.fieldName] = fieldState.value;
    else delete policy[fieldState.fieldName];
  });
}

function getPolicyBuyerTransferPrecondition(policy) {
  return JSON.stringify({
    client: POLICY_BUYER_TRANSFER_CLIENT_FIELDS.map((fieldName) => [
      fieldName,
      Object.prototype.hasOwnProperty.call(policy || {}, fieldName),
      policy?.[fieldName],
    ]),
    premiumManuallyEdited: policy?.premiumManuallyEdited === true,
    renewalStatus: policy?.renewalStatus ?? null,
    previousPolicyId: policy?.previousPolicyId ?? null,
  });
}

function getPolicyBuyerTransferUndoPrecondition(policy) {
  return JSON.stringify(POLICY_BUYER_TRANSFER_TARGET_STATE_FIELDS
    .filter((fieldName) => fieldName !== "updatedAt")
    .map((fieldName) => [
      fieldName,
      Object.prototype.hasOwnProperty.call(policy || {}, fieldName),
      policy?.[fieldName],
    ]));
}

function createPolicyBuyerSnapshot(policy) {
  return {
    version: 1,
    fields: capturePolicyFields(policy, POLICY_BUYER_SNAPSHOT_FIELDS),
  };
}

function isValidPolicyBuyerSnapshot(snapshot) {
  if (snapshot?.version !== 1 || !Array.isArray(snapshot.fields)) return false;
  if (snapshot.fields.length !== POLICY_BUYER_SNAPSHOT_FIELDS.length) return false;
  const statesByName = new Map();
  for (const state of snapshot.fields) {
    if (
      !state
      || !POLICY_BUYER_SNAPSHOT_FIELDS.includes(state.fieldName)
      || typeof state.exists !== "boolean"
      || statesByName.has(state.fieldName)
    ) return false;
    if (state.exists) {
      const validValue = state.fieldName === "premiumManuallyEdited"
        ? typeof state.value === "boolean"
        : (
            state.value === null
            || state.value === undefined
            || typeof state.value === "string"
            || typeof state.value === "number"
          );
      if (!validValue) return false;
    }
    statesByName.set(state.fieldName, state);
  }
  return POLICY_BUYER_SNAPSHOT_FIELDS.every((fieldName) => statesByName.has(fieldName));
}

function getPolicyBuyerSnapshotValue(snapshot, fieldName) {
  const state = isValidPolicyBuyerSnapshot(snapshot)
    ? snapshot.fields.find((item) => item?.fieldName === fieldName)
    : null;
  return state?.exists ? state.value : "";
}

function restorePolicyBuyerSnapshot(policy) {
  if (!POLICY_BUYER_TRANSFER_FEATURE_ENABLED) {
    throw createPolicyBuyerTransferFeatureDisabledError();
  }
  if (!policy || !isValidPolicyBuyerSnapshot(policy.buyerSnapshot)) return false;
  const snapshot = policy.buyerSnapshot;
  restorePolicyFields(policy, snapshot.fields);
  delete policy.transferredToBuyer;
  delete policy.buyerName;
  delete policy.buyerIdentityNumber;
  delete policy.buyerSnapshot;
  delete policy.transferDetectedAt;
  return true;
}

function detectPolicyBuyerTransfer(existingPolicy, parsedPolicy) {
  if (!POLICY_BUYER_TRANSFER_FEATURE_ENABLED) return null;
  if (existingPolicy?.transferredToBuyer === true) return null;
  const recordIdentities = getPolicyTransferIdentityValues(existingPolicy);
  const parsedIdentities = getPolicyTransferIdentityValues(parsedPolicy);
  if (recordIdentities.length === 0 || parsedIdentities.length === 0) return null;
  if (recordIdentities.some((identity) => parsedIdentities.includes(identity))) return null;
  const recordName = String(existingPolicy?.clientName ?? "").trim();
  const parsedName = String(parsedPolicy?.clientName ?? "").trim();
  if (!recordName || !parsedName) return null;
  if (getClientNameRelationship(recordName, parsedName) !== "different") return null;
  const parsedPremium = String(parsedPolicy?.premium ?? "").trim();
  if (
    existingPolicy?.premiumManuallyEdited === true
    && parsedPremium !== String(existingPolicy?.premium ?? "").trim()
  ) return null;

  const ownerValues = Object.fromEntries(POLICY_BUYER_TRANSFER_CLIENT_FIELDS.map((fieldName) => [
    fieldName,
    String(parsedPolicy?.[fieldName] ?? "").trim(),
  ]));
  return {
    buyerName: recordName,
    buyerIdentityNumber: String(existingPolicy.identityNumber ?? "").trim(),
    buyerSnapshot: createPolicyBuyerSnapshot(existingPolicy),
    ownerValues,
    expectedBuyerState: getPolicyBuyerTransferPrecondition(existingPolicy),
  };
}

function normalizeTransferredPolicyRenewals(policy, allPolicies = []) {
  if (!POLICY_BUYER_TRANSFER_FEATURE_ENABLED) {
    throw createPolicyBuyerTransferFeatureDisabledError();
  }
  const relatedPolicies = Array.isArray(allPolicies) ? allPolicies : [];
  const previousPolicy = relatedPolicies.find((item) => (
    item !== policy && item?.id === policy?.previousPolicyId
  ));
  relatedPolicies
    .filter((item) => item !== policy && item?.previousPolicyId === policy?.id)
    .forEach((successor) => {
      delete successor.previousPolicyId;
      successor.updatedAt = Date.now();
    });
  delete policy.previousPolicyId;
  policy.renewalStatus = null;
  if (
    previousPolicy?.renewalStatus === "renewed"
    && !relatedPolicies.some((item) => item !== policy && item?.previousPolicyId === previousPolicy.id)
  ) {
    previousPolicy.renewalStatus = null;
    previousPolicy.updatedAt = Date.now();
  }
}

function applyPolicyBuyerTransfer(policy, transfer, allPolicies = []) {
  if (!POLICY_BUYER_TRANSFER_FEATURE_ENABLED) {
    throw createPolicyBuyerTransferFeatureDisabledError();
  }
  if (!policy || !transfer) return false;
  if (policy.transferredToBuyer === true) return false;
  if (!isValidPolicyBuyerSnapshot(transfer.buyerSnapshot)) return false;
  if (
    !String(transfer.ownerValues?.clientName || "").trim()
    || getPolicyTransferIdentityValues(transfer.ownerValues).length === 0
  ) return false;
  
  
  if (getPolicyBuyerTransferPrecondition(policy) !== transfer.expectedBuyerState) return false;
  policy.transferredToBuyer = true;
  policy.buyerName = transfer.buyerName;
  policy.buyerIdentityNumber = transfer.buyerIdentityNumber;
  policy.buyerSnapshot = transfer.buyerSnapshot;
  policy.transferDetectedAt = Date.now();
  POLICY_BUYER_TRANSFER_CLIENT_FIELDS.forEach((fieldName) => {
    const value = String(transfer.ownerValues?.[fieldName] ?? "").trim();
    if (value) policy[fieldName] = value;
    else delete policy[fieldName];
  });
  normalizeTransferredPolicyRenewals(policy, allPolicies);
  return true;
}

function captureBuyerTransferRollbackState(policy, allPolicies = []) {
  const relatedPolicies = (Array.isArray(allPolicies) ? allPolicies : [])
    .filter((item) => (
      item
      && item !== policy
      && (item.id === policy?.previousPolicyId || item.previousPolicyId === policy?.id)
    ));
  return {
    target: capturePolicyFields(policy, POLICY_BUYER_TRANSFER_TARGET_STATE_FIELDS),
    related: relatedPolicies.map((item) => ({
      policy: item,
      fields: capturePolicyFields(item, POLICY_BUYER_TRANSFER_RELATED_STATE_FIELDS),
    })),
  };
}

function restoreBuyerTransferRollbackState(policy, rollbackState) {
  if (!POLICY_BUYER_TRANSFER_FEATURE_ENABLED) {
    throw createPolicyBuyerTransferFeatureDisabledError();
  }
  restorePolicyFields(policy, rollbackState?.target);
  (rollbackState?.related || []).forEach((state) => restorePolicyFields(state.policy, state.fields));
}

const IMPORTED_POLICY_TRACKING_STATE_FIELDS = Object.freeze([
  "lastImportedFieldValues",
  "manuallyEditedImportedFields",
  "registrationManuallyEdited",
  "riskSummaryManuallyEdited",
  "premiumManuallyEdited",
  "validFromManuallyEdited",
]);

function captureImportedPolicyTrackingRollbackState(policy) {
  return Object.fromEntries(IMPORTED_POLICY_TRACKING_STATE_FIELDS.map((fieldName) => [
    fieldName,
    {
      exists: Object.prototype.hasOwnProperty.call(policy, fieldName),
      value: policy[fieldName],
    },
  ]));
}

function restoreImportedPolicyTrackingRollbackState(policy, rollbackState) {
  IMPORTED_POLICY_TRACKING_STATE_FIELDS.forEach((fieldName) => {
    const fieldState = rollbackState?.[fieldName];
    if (fieldState?.exists) policy[fieldName] = fieldState.value;
    else delete policy[fieldName];
  });
}

function captureImportedPolicyFieldRollbackState(policy) {
  return {
    ...Object.fromEntries(IMPORTED_POLICY_FILLABLE_FIELDS.map((fieldName) => [
      fieldName,
      {
        exists: Object.prototype.hasOwnProperty.call(policy, fieldName),
        value: policy[fieldName],
      },
    ])),
    tracking: captureImportedPolicyTrackingRollbackState(policy),
  };
}

function restoreImportedPolicyFieldRollbackState(policy, rollbackState) {
  IMPORTED_POLICY_FILLABLE_FIELDS.forEach((fieldName) => {
    const fieldState = rollbackState?.[fieldName];
    if (fieldState?.exists) policy[fieldName] = fieldState.value;
    else delete policy[fieldName];
  });
  restoreImportedPolicyTrackingRollbackState(policy, rollbackState?.tracking);
}





function getPolicyAttachmentEnrichmentKey(policy) {
  const pdfAttachments = normalizePolicyAttachments(policy?.attachments)
    .filter((attachment) => isExternalAttachment(attachment) && attachment.type === "application/pdf");
  if (pdfAttachments.length === 0) return "";
  const attachmentKey = pdfAttachments
    .map((attachment) => normalizeAttachmentRelativePath(attachment.relativePath)?.join("/") || attachment.id)
    .sort((left, right) => left.localeCompare(right, "pl"))
    .join("|");
  return `${POLICY_ATTACHMENT_ENRICHMENT_VERSION}:${attachmentKey}`;
}

function policyHasMissingImportedFields(policy) {
  return IMPORTED_POLICY_FILLABLE_FIELDS.some((fieldName) => isImportedPolicyFieldMissing(policy?.[fieldName]));
}








let policyPdfServerReadingAvailable = true;

function getAttachmentServerPath(attachment) {
  return normalizeAttachmentRelativePath(attachment?.relativePath)?.join("/") || "";
}

async function readPolicyAttachmentPdfsOnServer(attachments) {
  if (!policyPdfServerReadingAvailable) return new Map();
  const files = attachments.map(getAttachmentServerPath).filter(Boolean);
  if (files.length === 0) return new Map();
  try {
    
    
    
    const response = await apiFetch("/api/zalaczniki/pdf", {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({ files }),
    });
    if (!response.ok) {
      
      
      if (response.status === 404) policyPdfServerReadingAvailable = false;
      return new Map();
    }
    const payload = await response.json();
    const results = Array.isArray(payload?.results) ? payload.results : [];
    return new Map(results.filter((result) => result?.path).map((result) => [String(result.path), result]));
  } catch {
    return new Map();
  }
}







const PERMANENTLY_UNREADABLE_PDF_CODES = new Set(["PDF_TEXT_MISSING", "POLICY_OFFER"]);

async function parsePolicyAttachmentPdfFields(policy) {
  if (!globalThis.PolicyPdfImporter?.importPolicyPdf) return { status: "unavailable" };
  const pdfAttachments = normalizePolicyAttachments(policy?.attachments)
    .filter((attachment) => isExternalAttachment(attachment) && attachment.type === "application/pdf");
  if (pdfAttachments.length === 0) return { status: "checked" };
  const policyNumberKey = getPolicyNumberKey(policy);
  const serverResults = await readPolicyAttachmentPdfsOnServer(pdfAttachments);
  let readFailed = false;
  let insurerConflict = false;
  for (const attachment of pdfAttachments) {
    const serverResult = serverResults.get(getAttachmentServerPath(attachment));
    if (
      serverResult?.status === "unreadable"
      && PERMANENTLY_UNREADABLE_PDF_CODES.has(String(serverResult.code || ""))
    ) continue;
    let blob = null;
    if (!serverResult || serverResult.status !== "parsed") {
      try {
        blob = await getPolicyAttachmentBlob(attachment);
      } catch {
        readFailed = true;
        continue;
      }
    }
    try {
      const parsed = serverResult?.status === "parsed"
        ? serverResult.parsed
        : await globalThis.PolicyPdfImporter.importPolicyPdf(blob);
      const parsedNumberKey = getPolicyNumberKey(parsed?.policy);
      
      
      if (!policyNumberKey || !parsedNumberKey || parsedNumberKey !== policyNumberKey) continue;
      if (!arePolicyInsurersCompatibleForEnrichment(policy, parsed.policy)) {
        insurerConflict = true;
        continue;
      }
      
      
      if (policyPeriodsAreDisjoint(policy, parsed.policy)) continue;
      return {
        status: "parsed",
        fields: getAttachmentImportedPolicyFieldValues(policy, parsed.policy),
        importedPolicy: parsed.policy,
        buyerTransfer: detectPolicyBuyerTransfer(policy, parsed.policy),
      };
    } catch {
      
      continue;
    }
  }
  if (insurerConflict) return { status: "conflict" };
  return readFailed ? { status: "unavailable" } : { status: "checked" };
}

function createImportedPolicyRecord(importedPolicy, attachments, createdAt = Date.now()) {
  const registration = normalizeRegistration(importedPolicy.registration || "Inne");
  const validUntil = String(importedPolicy.validUntil || "").trim();
  const importedValidFrom = String(importedPolicy.validFrom || "").trim();
  const calculatedValidFrom = formatDateForInput(
    normalize(registration) === normalize("Podróż")
      ? calculateTravelStartDate(validUntil)
      : calculateStartDate(validUntil),
  );
  const record = {
    id: globalThis.crypto?.randomUUID?.() ?? `${createdAt}-${Math.random()}`,
    
    
    ownerId: normalizePolicyOwnerId(importedPolicy.ownerId) || currentAccount?.id || "",
    clientName: String(importedPolicy.clientName || "").trim(),
    identityNumber: String(importedPolicy.identityNumber || "").trim(),
    contact: String(importedPolicy.contact || "").trim(),
    insurer: String(importedPolicy.insurer || "").trim(),
    policyNumber: String(importedPolicy.policyNumber || "").trim(),
    registration,
    vehicleMake: normalizeVehicleDetail(importedPolicy.vehicleMake),
    vehicleModel: normalizeVehicleDetail(importedPolicy.vehicleModel),
    vehicleType: normalizeVehicleDetail(importedPolicy.vehicleType),
    productionYear: normalizeVehicleDetail(importedPolicy.productionYear),
    fuelType: normalizeVehicleDetail(importedPolicy.fuelType),
    seats: normalizeVehicleDetail(importedPolicy.seats),
    grossWeight: normalizeVehicleDetail(importedPolicy.grossWeight),
    vin: normalizeVehicleIdentifier(importedPolicy.vin),
    firstRegistrationDate: normalizeFirstRegistrationDate(importedPolicy.firstRegistrationDate),
    engineCapacity: normalizeVehicleDetail(importedPolicy.engineCapacity),
    enginePower: normalizeVehicleDetail(importedPolicy.enginePower),
    mileage: normalizeVehicleDetail(importedPolicy.mileage),
    driverLicenseDate: normalizeDriverLicenseDate(importedPolicy.driverLicenseDate),
    clientAddress: normalizeClientAddress(importedPolicy.clientAddress),
    clientPostalCode: normalizeClientPostalCode(importedPolicy.clientPostalCode)
      || extractClientPostalCode(importedPolicy.clientAddress),
    
    
    issueDate: normalizeFirstRegistrationDate(importedPolicy.issueDate),
    validFrom: importedValidFrom || calculatedValidFrom,
    
    
    validFromManuallyEdited: false,
    validUntil,
    premium: String(importedPolicy.premium || "").trim(),
    riskSummary: String(importedPolicy.riskSummary || "").trim(),
    renewalStatus: null,
    attachments: normalizePolicyAttachments(attachments),
    createdAt,
  };
  record.lastImportedFieldValues = createImportedPolicyFieldSnapshot(record);
  return record;
}

function getPolicyBatchResultMessage(
  addedCount,
  duplicateCount,
  failures,
  incompleteCount = 0,
  attachmentUpdatedCount = 0,
  enrichedPolicyCount = 0,
) {
  const failureCount = failures.length;
  if (
    addedCount === 0
    && attachmentUpdatedCount === 0
    && enrichedPolicyCount === 0
    && duplicateCount > 0
    && failureCount === 0
  ) {
    return "Nie dodano rekordów - wszystkie wybrane polisy są już w bazie.";
  }
  if (
    addedCount === 0
    && attachmentUpdatedCount === 0
    && enrichedPolicyCount === 0
    && duplicateCount === 0
    && failureCount === 1
  ) {
    return `${failures[0].fileName}: ${failures[0].message}`;
  }
  const addedLabel = addedCount === 1 ? "1 rekord" : `${addedCount} rekordy`;
  const normalizedAddedLabel = addedCount >= 5 || addedCount === 0 ? `${addedCount} rekordów` : addedLabel;
  const completedMessages = [];
  if (addedCount > 0) completedMessages.push(`Dodano ${normalizedAddedLabel} polis wraz z PDF-ami.`);
  if (attachmentUpdatedCount > 0) {
    completedMessages.push(
      attachmentUpdatedCount === 1
        ? "Przypisano PDF do 1 istniejącej polisy."
        : `Przypisano PDF-y do ${attachmentUpdatedCount} istniejących polis.`,
    );
  }
  if (enrichedPolicyCount > 0) {
    completedMessages.push(
      enrichedPolicyCount === 1
        ? "Uzupełniono brakujące dane w 1 istniejącej polisie."
        : `Uzupełniono brakujące dane w ${enrichedPolicyCount} istniejących polisach.`,
    );
  }
  const skippedParts = [];
  if (duplicateCount > 0) skippedParts.push(`duplikaty: ${duplicateCount}`);
  if (failureCount > 0) skippedParts.push(`błędy: ${failureCount}`);
  const completedMessage = completedMessages.join(" ") || "Nie dodano rekordów.";
  const skippedMessage = skippedParts.length > 0 ? ` Pominięto - ${skippedParts.join(", ")}.` : "";
  const incompleteMessage = incompleteCount > 0 ? ` Do sprawdzenia: ${incompleteCount} z niepełnymi danymi.` : "";
  return `${completedMessage}${skippedMessage}${incompleteMessage}`;
}

async function getPolicyImportDirectoryEntries(directoryHandle) {
  const entries = [];
  if (typeof directoryHandle.values === "function") {
    for await (const entry of directoryHandle.values()) entries.push(entry);
    return entries;
  }
  if (typeof directoryHandle.entries === "function") {
    for await (const [, entry] of directoryHandle.entries()) entries.push(entry);
  }
  return entries;
}




const POLICY_IMPORT_FILE_NAME_PATTERN = /\.(pdf|jpe?g|png|webp)$/i;

async function collectPolicyImportFilesFromDirectory(rootDirectoryHandle) {
  const files = [];
  const directoriesToVisit = [rootDirectoryHandle];
  while (directoriesToVisit.length > 0) {
    const directoryHandle = directoriesToVisit.shift();
    const entries = await getPolicyImportDirectoryEntries(directoryHandle);
    for (const entry of entries) {
      if (entry.kind === "directory") {
        directoriesToVisit.push(entry);
      } else if (entry.kind === "file" && POLICY_IMPORT_FILE_NAME_PATTERN.test(entry.name)) {
        files.push(await entry.getFile());
      }
    }
  }
  return files.sort((first, second) => first.name.localeCompare(second.name, "pl", { sensitivity: "base" }));
}

function getFileFromDroppedEntry(entry) {
  return new Promise((resolve, reject) => entry.file(resolve, reject));
}

async function getDroppedDirectoryEntries(directoryEntry) {
  const reader = directoryEntry.createReader();
  const entries = [];
  while (true) {
    const batch = await new Promise((resolve, reject) => reader.readEntries(resolve, reject));
    if (batch.length === 0) return entries;
    entries.push(...batch);
  }
}

async function collectPolicyImportFilesFromDroppedEntry(rootEntry) {
  const files = [];
  const entriesToVisit = [rootEntry];
  while (entriesToVisit.length > 0) {
    const entry = entriesToVisit.shift();
    if (entry.isDirectory) {
      entriesToVisit.push(...(await getDroppedDirectoryEntries(entry)));
    } else if (entry.isFile && POLICY_IMPORT_FILE_NAME_PATTERN.test(entry.name)) {
      files.push(await getFileFromDroppedEntry(entry));
    }
  }
  return files;
}

function capturePolicyImportDropSources(dataTransfer) {
  const items = [...(dataTransfer?.items ?? [])].filter((item) => item.kind === "file");
  if (items.length === 0) {
    return [...(dataTransfer?.files ?? [])].map((file) => ({ file }));
  }
  return items.map((item) => {
    let handlePromise = null;
    try {
      handlePromise = typeof item.getAsFileSystemHandle === "function"
        ? item.getAsFileSystemHandle()
        : null;
    } catch {
    }
    return {
      handlePromise,
      legacyEntry: typeof item.webkitGetAsEntry === "function" ? item.webkitGetAsEntry() : null,
      file: item.getAsFile(),
    };
  });
}

async function collectPolicyImportFilesFromDropSources(sources) {
  const files = [];
  for (const source of sources) {
    let handle = null;
    try {
      handle = source.handlePromise ? await source.handlePromise : null;
    } catch {
    }
    if (handle?.kind === "directory") {
      files.push(...(await collectPolicyImportFilesFromDirectory(handle)));
    } else if (handle?.kind === "file" && POLICY_IMPORT_FILE_NAME_PATTERN.test(handle.name)) {
      files.push(await handle.getFile());
    } else if (source.legacyEntry) {
      files.push(...(await collectPolicyImportFilesFromDroppedEntry(source.legacyEntry)));
    } else if (source.file && POLICY_IMPORT_FILE_NAME_PATTERN.test(source.file.name)) {
      files.push(source.file);
    }
  }
  return files.sort((first, second) => first.name.localeCompare(second.name, "pl", { sensitivity: "base" }));
}

function setPolicyImportDropTargetActive(active) {
  elements.importPolicies.classList.toggle("import-policies-button--dragover", active);
  elements.importPoliciesLabel.textContent = active ? "Upuść, aby wczytać" : "Wczytaj polisy";
  elements.importPolicies.setAttribute(
    "aria-label",
    active ? "Upuść pliki lub foldery, aby wczytać polisy" : "Wczytaj polisy PDF lub obrazy załączników",
  );
}

async function importDroppedPolicyFiles(event) {
  event.preventDefault();
  event.stopPropagation();
  setPolicyImportDropTargetActive(false);
  if (attachmentOperationActive) {
    showToast("Poczekaj na zakończenie bieżącej operacji", "warning");
    return;
  }

  const sources = capturePolicyImportDropSources(event.dataTransfer);
  let files = [];
  startAttachmentOperation(1, "Przeglądanie plików i folderów");
  try {
    files = await collectPolicyImportFilesFromDropSources(sources);
  } catch (error) {
    showToast(error?.message || "Nie udało się odczytać upuszczonych plików i folderów", "error");
    return;
  } finally {
    finishAttachmentOperation();
  }

  if (files.length === 0) {
    showToast("W upuszczonych plikach i folderach nie znaleziono polis PDF ani obrazów (JPG, PNG, WEBP)", "warning");
    return;
  }
  await importPolicyFiles(files);
}

function isImageAttachmentFile(file) {
  return getAttachmentMimeType(file).startsWith("image/");
}




async function importPolicyFiles(fileList) {
  const allFiles = [...(fileList ?? [])];
  if (allFiles.length === 0 || attachmentOperationActive) return;
  const imageFiles = allFiles.filter(isImageAttachmentFile);
  const pdfFiles = allFiles.filter((file) => !isImageAttachmentFile(file));
  try {
    if (pdfFiles.length > 0) await importPolicyPdfFiles(pdfFiles);
    if (imageFiles.length > 0) await attachImageFilesToChosenPolicy(imageFiles);
  } finally {
    elements.policyImportInput.value = "";
  }
}

async function importPolicyPdfFiles(fileList) {
  const selectedFiles = [...(fileList ?? [])];
  if (selectedFiles.length === 0 || attachmentOperationActive) return;
  if (!globalThis.PolicyPdfImporter?.importPolicyPdf) {
    showToast("Brakuje lokalnego modułu importu polis PDF.", "error");
    return;
  }

  const importedPolicies = [];
  const existingPolicyAttachmentUpdates = [];
  const existingPolicyAttachmentUpdateKeys = new Set();
  const detectedImportedInsurers = [];
  const attachmentsToRollback = [];
  const failures = [];
  const incompletePolicyIds = new Set();
  const conflictSkippedPolicyIds = new Set();
  const reapplyIdentityConflictKeys = new Set();
  let renewalMutationStates = new Map();
  let duplicateCount = 0;
  let insurerConflictCount = 0;
  let committed = false;
  startAttachmentOperation(selectedFiles.length, "Importowanie polis");
  try {
    if (!(await ensureWritableDataFile({ deferFreshnessCheck: true }))) return;
    await ensureAttachmentsBaseDirectory();
    const policiesByMergeKey = buildPortfolioMergeKeyIndex();

    for (let index = 0; index < selectedFiles.length; index += 1) {
      const file = selectedFiles[index];
      try {
        if (getAttachmentMimeType(file) !== "application/pdf") {
          throw new Error("Plik nie jest dokumentem PDF.");
        }
        updateAttachmentOperation("Odczytywanie polis", index, selectedFiles.length, file.name);
        const importResult = await globalThis.PolicyPdfImporter.importPolicyPdf(file);
        const policyIdentityKey = getPolicyIdentityKey(importResult.policy);
        const resolution = resolvePortfolioMergeTarget(policiesByMergeKey, importResult.policy);
        if (resolution.status === "ambiguous") {
          insurerConflictCount += 1;
          throw new Error("W bazie jest kilka polis tego samego TU z tym numerem. Plik pominięto, aby nie podpiąć go do niewłaściwego rekordu.");
        }
        if (resolution.status === "cross-insurer") {
          insurerConflictCount += 1;
          reapplyIdentityConflictKeys.add(`cross:${policyIdentityKey}`);
        }
        const existingPolicy = resolution.status === "match" ? resolution.policy : null;
        if (existingPolicy) {
          detectedImportedInsurers.push(importResult.policy);
          
          
          const existingUpdateQueued = existingPolicyAttachmentUpdateKeys.has(existingPolicy.id);
          const fieldSyncPlan = existingPolicy
            ? getImportedPolicyFieldSyncPlan(existingPolicy, importResult.policy)
            : { changedFieldNames: [] };
          const canFillMissingFields = existingPolicy
            && fieldSyncPlan.changedFieldNames.length > 0
            && !existingUpdateQueued;
          const canAttachPdf = existingPolicy
            && normalizePolicyAttachments(existingPolicy.attachments).length === 0
            && !existingUpdateQueued;
          if (canAttachPdf || canFillMissingFields) {
            let storedAttachments = [];
            if (canAttachPdf) {
              const preparedAttachments = await createAttachmentsFromFiles([file], [], null, true);
              updateAttachmentOperation("Przypisywanie PDF-u do istniejącej polisy", index + 1, selectedFiles.length, file.name);
              storedAttachments = await writeAttachmentsToFolder(
                existingPolicy.clientName,
                existingPolicy.policyNumber,
                preparedAttachments,
                () => updateAttachmentOperation(
                  "Przypisywanie PDF-u do istniejącej polisy",
                  index + 1,
                  selectedFiles.length,
                  file.name,
                ),
              );
            }
            attachmentsToRollback.push(...storedAttachments);
            existingPolicyAttachmentUpdates.push({
              policyId: existingPolicy.id,
              importedPolicy: importResult.policy,
              storedAttachments,
              activePolicy: null,
              rollbackAttachments: null,
              rollbackFieldValues: null,
              rollbackUpdatedAt: null,
              appliedFieldNames: [],
              attachmentSkipped: false,
              applied: false,
              alreadyPresent: false,
              skipped: false,
            });
            existingPolicyAttachmentUpdateKeys.add(existingPolicy.id);
            continue;
          }
          duplicateCount += 1;
          updateAttachmentOperation("Pomijanie duplikatu", index + 1, selectedFiles.length, file.name);
          continue;
        }

        const preparedAttachments = await createAttachmentsFromFiles([file], [], null, true);
        updateAttachmentOperation("Zapisywanie PDF-u polisy", index + 1, selectedFiles.length, file.name);
        const storedAttachments = await writeAttachmentsToFolder(
          importResult.policy.clientName,
          importResult.policy.policyNumber,
          preparedAttachments,
          () => updateAttachmentOperation("Zapisywanie PDF-u polisy", index + 1, selectedFiles.length, file.name),
        );
        attachmentsToRollback.push(...storedAttachments);
        const importedPolicy = createImportedPolicyRecord(
          importResult.policy,
          storedAttachments,
          Date.now() + index,
        );
        importedPolicies.push(importedPolicy);
        detectedImportedInsurers.push(importedPolicy);
        if (importResult.missingOptionalFields.length > 0) incompletePolicyIds.add(importedPolicy.id);
        addPolicyToPortfolioMergeIndex(policiesByMergeKey, importedPolicy);
      } catch (error) {
        failures.push({
          fileName: String(file?.name || "Nieznany plik"),
          message: getPolicyImportErrorMessage(error),
        });
        updateAttachmentOperation("Pominięto plik z błędem", index + 1, selectedFiles.length, file?.name || "");
      }
    }

    if (importedPolicies.length === 0 && existingPolicyAttachmentUpdates.length === 0) {
      const insurerSettingsResult = await syncImportedInsurersToSettings(detectedImportedInsurers);
      reportDiagnosticsEvent("import-reczny-pdf", {
        plikow: selectedFiles.length,
        dodano: 0,
        duplikaty: duplicateCount,
        konfliktyTu: insurerConflictCount,
        bledy: failures.length,
      });
      showToast(
        `${getPolicyBatchResultMessage(0, duplicateCount, failures)}${getImportedInsurersResultMessage(insurerSettingsResult)}`,
        failures.length > 0 && duplicateCount === 0 ? "error" : "warning",
      );
      return;
    }

    const importedPolicyIds = new Set(importedPolicies.map((policy) => policy.id));
    const reapplyImportedPolicyChanges = () => {
      const activePoliciesByMergeKey = buildPortfolioMergeKeyIndex();
      const recordReapplyIdentityConflict = (key) => {
        const normalizedKey = String(key || "");
        if (reapplyIdentityConflictKeys.has(normalizedKey)) return;
        reapplyIdentityConflictKeys.add(normalizedKey);
        insurerConflictCount += 1;
      };
      importedPolicies.forEach((policy) => {
        const existingById = policies.find((item) => item.id === policy.id);
        if (existingById) {
          if (policiesHaveCompatibleIdentity(existingById, policy)) {
            conflictSkippedPolicyIds.delete(policy.id);
          } else {
            conflictSkippedPolicyIds.add(policy.id);
            recordReapplyIdentityConflict(`imported:${policy.id}`);
          }
          return;
        }
        const resolution = resolvePortfolioMergeTarget(activePoliciesByMergeKey, policy);
        if (resolution.status === "match" || resolution.status === "ambiguous") {
          conflictSkippedPolicyIds.add(policy.id);
          if (resolution.status === "ambiguous") recordReapplyIdentityConflict(`ambiguous:${policy.id}`);
          return;
        }
        if (resolution.status === "cross-insurer") {
          recordReapplyIdentityConflict(`cross:${getPolicyIdentityKey(policy)}`);
        }
        conflictSkippedPolicyIds.delete(policy.id);
        policies.push(policy);
        addPolicyToPortfolioMergeIndex(activePoliciesByMergeKey, policy);
      });
      existingPolicyAttachmentUpdates.forEach((update) => {
        update.applied = false;
        update.appliedFieldNames = [];
        update.attachmentSkipped = false;
        update.alreadyPresent = false;
        update.skipped = false;
        const fallbackResolution = resolvePortfolioMergeTarget(activePoliciesByMergeKey, update.importedPolicy);
        const policyById = policies.find((policy) => policy.id === update.policyId);
        if (policyById && !policiesHaveCompatibleIdentity(policyById, update.importedPolicy)) {
          recordReapplyIdentityConflict(`attachment:${update.policyId}`);
          update.skipped = true;
          return;
        }
        const currentPolicy = policyById
          || (fallbackResolution.status === "match" ? fallbackResolution.policy : null);
        if (!currentPolicy) {
          if (fallbackResolution.status === "ambiguous" || fallbackResolution.status === "cross-insurer") {
            recordReapplyIdentityConflict(`attachment:${getPolicyIdentityKey(update.importedPolicy)}`);
          }
          update.skipped = true;
          return;
        }

        if (currentPolicy !== update.activePolicy) {
          update.activePolicy = currentPolicy;
          update.rollbackAttachments = currentPolicy.attachments;
          update.rollbackFieldValues = captureImportedPolicyFieldRollbackState(currentPolicy);
          update.rollbackUpdatedAt = currentPolicy.updatedAt;
        }

        const currentAttachments = normalizePolicyAttachments(currentPolicy.attachments);
        let attachmentApplied = false;
        if (update.storedAttachments.length > 0) {
          const currentAttachmentIds = new Set(currentAttachments.map((attachment) => attachment.id));
          const currentAttachmentPaths = new Set(
            currentAttachments
              .filter(isExternalAttachment)
              .map((attachment) => getAttachmentPathKey(attachment.relativePath)),
          );
          const storedAttachmentsArePresent = update.storedAttachments.every((attachment) => (
            currentAttachmentIds.has(attachment.id)
            || (isExternalAttachment(attachment) && currentAttachmentPaths.has(getAttachmentPathKey(attachment.relativePath)))
          ));
          if (storedAttachmentsArePresent) {
            update.alreadyPresent = true;
          } else if (currentAttachments.length > 0) {
            update.attachmentSkipped = true;
          } else {
            currentPolicy.attachments = [...update.storedAttachments];
            attachmentApplied = true;
          }
        }

        update.appliedFieldNames = applyMissingImportedPolicyFields(currentPolicy, update.importedPolicy);
        if (attachmentApplied || update.appliedFieldNames.length > 0) {
          currentPolicy.updatedAt = Date.now();
          update.applied = true;
        }
      });
      renewalMutationStates = new Map();
      const renewalLinkContext = createRenewalLinkContext();
      importedPolicies
        .filter((policy) => policies.some((item) => item.id === policy.id))
        .sort((first, second) => {
          const firstDate = parseLocalDate(first.validUntil)?.getTime() || 0;
          const secondDate = parseLocalDate(second.validUntil)?.getTime() || 0;
          return firstDate - secondDate;
        })
        .forEach((policy) => {
          linkPolicyToBestRenewalPredecessor(policy, renewalMutationStates, renewalLinkContext);
          
          
          
          const successor = linkRenewalSuccessor(policy, renewalMutationStates);
          if (successor && policy.renewalStatus !== "renewed") {
            capturePolicyMutationState(renewalMutationStates, policy);
            setPolicyRenewalStatusValue(policy, "renewed", false);
            policy.updatedAt = Date.now();
          }
        });
      return true;
    };
    reapplyImportedPolicyChanges();
    updateAttachmentOperation(
      "Zapisywanie rekordów w bazie",
      selectedFiles.length,
      selectedFiles.length,
    );
    if (importedPolicies.length > 0) {
      saveStatusPopupSuccessText = importedPolicies.length === 1
        ? "Polisa dodana do bazy"
        : `${importedPolicies.length} polis dodano do bazy`;
    } else {
      saveStatusPopupSuccessText = existingPolicyAttachmentUpdates.length === 1
        ? "Zaktualizowano istniejącą polisę"
        : `Zaktualizowano ${existingPolicyAttachmentUpdates.length} istniejących polis`;
    }
    if (!(await persistPolicies({ reapplyAfterConflict: reapplyImportedPolicyChanges }))) {
      restorePolicyMutationStates(renewalMutationStates);
      policies = policies.filter((policy) => !importedPolicyIds.has(policy.id));
      existingPolicyAttachmentUpdates.forEach((update) => {
        if (!update.applied || !policies.includes(update.activePolicy)) return;
        update.activePolicy.attachments = update.rollbackAttachments;
        restoreImportedPolicyFieldRollbackState(update.activePolicy, update.rollbackFieldValues);
        update.activePolicy.updatedAt = update.rollbackUpdatedAt;
      });
      const protectedAttachmentPaths = new Set(
        existingPolicyAttachmentUpdates
          .filter((update) => update.alreadyPresent)
          .flatMap((update) => update.storedAttachments)
          .filter(isExternalAttachment)
          .map((attachment) => getAttachmentPathKey(attachment.relativePath)),
      );
      await deleteExternalAttachmentFiles(attachmentsToRollback.filter((attachment) => (
        !protectedAttachmentPaths.has(getAttachmentPathKey(attachment.relativePath))
      )));
      markPoliciesRolledBack();
      render();
      return;
    }
    const conflictSkippedPolicies = importedPolicies.filter((policy) => conflictSkippedPolicyIds.has(policy.id));
    if (conflictSkippedPolicies.length > 0) {
      await deleteExternalAttachmentFiles(conflictSkippedPolicies.flatMap((policy) => policy.attachments));
      duplicateCount += conflictSkippedPolicies.length;
    }
    const discardedAttachmentUpdates = existingPolicyAttachmentUpdates
      .filter((update) => update.skipped || update.attachmentSkipped);
    if (discardedAttachmentUpdates.length > 0) {
      await deleteExternalAttachmentFiles(discardedAttachmentUpdates.flatMap((update) => update.storedAttachments));
    }
    const unchangedExistingUpdates = existingPolicyAttachmentUpdates.filter((update) => (
      update.skipped || (!update.applied && !update.alreadyPresent)
    ));
    duplicateCount += unchangedExistingUpdates.length;
    const committedImportedPolicies = importedPolicies.filter((policy) => !conflictSkippedPolicyIds.has(policy.id));
    const committedAttachmentUpdates = existingPolicyAttachmentUpdates.filter((update) => (
      !update.skipped
      && !update.attachmentSkipped
      && update.storedAttachments.length > 0
      && (update.applied || update.alreadyPresent)
    ));
    const enrichedPolicyUpdates = existingPolicyAttachmentUpdates
      .filter((update) => update.appliedFieldNames.length > 0);
    const incompleteCount = committedImportedPolicies
      .filter((policy) => incompletePolicyIds.has(policy.id))
      .length;
    committed = true;
    const insurerSettingsResult = await syncImportedInsurersToSettings(detectedImportedInsurers);
    currentPage = 1;
    pageJumpOpen = false;
    render();
    if (committedImportedPolicies.length > 0) flashRecordCounterPlusOne(committedImportedPolicies.length);
    reportDiagnosticsEvent("import-reczny-pdf", {
      plikow: selectedFiles.length,
      dodano: committedImportedPolicies.length,
      podpietoPdf: committedAttachmentUpdates.length,
      uzupelniono: enrichedPolicyUpdates.length,
      duplikaty: duplicateCount,
      konfliktyTu: insurerConflictCount,
      bledy: failures.length,
    });
    showToast(
      `${getPolicyBatchResultMessage(
        committedImportedPolicies.length,
        duplicateCount,
        failures,
        incompleteCount,
        committedAttachmentUpdates.length,
        enrichedPolicyUpdates.length,
      )}${getImportedInsurersResultMessage(insurerSettingsResult)}${
        insurerConflictCount > 0
          ? ` Uwaga: ${insurerConflictCount} numerów występuje także w innym TU; rekordy rozdzielono lub pominięto jako niejednoznaczne.`
          : ""
      }`,
      duplicateCount > 0 || failures.length > 0 || incompleteCount > 0
        || insurerConflictCount > 0 || !insurerSettingsResult.saved
        ? "warning"
        : "success",
    );
  } catch (error) {
    if (!committed && (importedPolicies.length > 0 || existingPolicyAttachmentUpdates.length > 0)) {
      const importedPolicyIds = new Set(importedPolicies.map((policy) => policy.id));
      const recordsWereAdded = policies.some((policy) => importedPolicyIds.has(policy.id));
      if (recordsWereAdded) {
        restorePolicyMutationStates(renewalMutationStates);
        policies = policies.filter((policy) => !importedPolicyIds.has(policy.id));
      }
      existingPolicyAttachmentUpdates.forEach((update) => {
        if (!update.applied || !policies.includes(update.activePolicy)) return;
        update.activePolicy.attachments = update.rollbackAttachments;
        restoreImportedPolicyFieldRollbackState(update.activePolicy, update.rollbackFieldValues);
        update.activePolicy.updatedAt = update.rollbackUpdatedAt;
      });
      markPoliciesRolledBack();
      render();
    }
    if (!committed && attachmentsToRollback.length > 0) {
      const protectedAttachmentPaths = new Set(
        existingPolicyAttachmentUpdates
          .filter((update) => update.alreadyPresent)
          .flatMap((update) => update.storedAttachments)
          .filter(isExternalAttachment)
          .map((attachment) => getAttachmentPathKey(attachment.relativePath)),
      );
      await deleteExternalAttachmentFiles(attachmentsToRollback.filter((attachment) => (
        !protectedAttachmentPaths.has(getAttachmentPathKey(attachment.relativePath))
      )));
    }
    showToast(
      error?.name === "AbortError" ? "Import polis został anulowany." : getPolicyImportErrorMessage(error),
      error?.name === "AbortError" ? "warning" : "error",
    );
  } finally {
    elements.policyImportInput.value = "";
    finishAttachmentOperation();
  }
}

async function addAttachmentsToPolicy(policyId, fileList, category = "") {
  const selectedFiles = [...(fileList ?? [])];
  if (selectedFiles.length === 0 || attachmentOperationActive) return;
  startAttachmentOperation(selectedFiles.length);

  try {
    if (!(await ensureWritableDataFile({ deferFreshnessCheck: true }))) return;
    const policy = policies.find((item) => item.id === policyId);
    if (!policy) return;
    await ensureAttachmentsBaseDirectory();
    const currentAttachments = normalizePolicyAttachments(policy.attachments);
    const newAttachments = await createAttachmentsFromFiles(
      selectedFiles,
      currentAttachments,
      updateAttachmentOperation,
      true,
      category,
    );
    if (newAttachments.length === 0) return;
    const storedAttachments = await writeAttachmentsToFolder(
      policy.clientName,
      policy.policyNumber,
      newAttachments,
      updateAttachmentOperation,
    );
    const previousAttachments = policy.attachments;
    const previousUpdatedAt = policy.updatedAt;
    let activePolicy = policy;
    let rollbackAttachments = previousAttachments;
    let rollbackUpdatedAt = previousUpdatedAt;
    const reapplyAttachmentAddition = () => {
      const currentPolicy = policies.find((item) => item.id === policyId);
      if (!currentPolicy) return false;
      if (currentPolicy !== activePolicy) {
        activePolicy = currentPolicy;
        rollbackAttachments = currentPolicy.attachments;
        rollbackUpdatedAt = currentPolicy.updatedAt;
      }
      const existingAttachments = normalizePolicyAttachments(currentPolicy.attachments);
      const existingIds = new Set(existingAttachments.map((attachment) => attachment.id));
      currentPolicy.attachments = [
        ...existingAttachments,
        ...storedAttachments.filter((attachment) => !existingIds.has(attachment.id)),
      ];
      currentPolicy.updatedAt = Date.now();
      return true;
    };
    reapplyAttachmentAddition();
    updateAttachmentOperation("Zapisywanie zmian w bazie", selectedFiles.length, selectedFiles.length);
    if (!(await persistPolicies({
      reapplyAfterConflict: reapplyAttachmentAddition,
      reapplyFailureMessage: "Rekord został usunięty w nowszej wersji bazy. Załączniki nie zostały dodane.",
    }))) {
      if (policies.includes(activePolicy)) {
        activePolicy.attachments = rollbackAttachments;
        activePolicy.updatedAt = rollbackUpdatedAt;
      }
      await deleteExternalAttachmentFiles(storedAttachments);
      markPoliciesRolledBack();
      render();
      return;
    }
    expandedPolicyId = policyId;
    render();
    showToast(`${pluralizeAttachments(storedAttachments.length)} zapisano w folderze klienta`);
  } catch (error) {
    showToast(error?.name === "AbortError" ? "Nie wybrano folderu Baza Polis" : (error?.message || "Nie udało się dodać załącznika"));
  } finally {
    elements.recordAttachmentInput.value = "";
    recordAttachmentPolicyId = null;
    finishAttachmentOperation();
  }
}






function describeAttachmentSelection(files) {
  const names = [...files].map((file) => String(file?.name ?? "")).filter(Boolean);
  const shownNames = names.slice(0, 3).join(", ");
  const suffix = names.length > 3 ? ` i ${names.length - 3} więcej` : "";
  return `${pluralizeAttachments(names.length)}: ${shownNames}${suffix}`;
}

function createAttachmentCategoryPicker(optionsElement, customInput) {
  const state = { selected: DEFAULT_ATTACHMENT_CATEGORY };
  const rerender = () => {
    optionsElement.innerHTML = ATTACHMENT_CATEGORY_PRESETS.map((name) => `
      <button
        type="button"
        class="attachment-category-chip${name === state.selected ? " attachment-category-chip--selected" : ""}"
        role="radio"
        aria-checked="${name === state.selected}"
        data-category="${escapeHtml(name)}"
      >${escapeHtml(name)}</button>
    `).join("");
  };
  optionsElement.addEventListener("click", (event) => {
    const chip = event.target.closest?.("[data-category]");
    if (!chip) return;
    state.selected = chip.dataset.category;
    customInput.value = "";
    rerender();
  });
  customInput.addEventListener("input", () => {
    state.selected = customInput.value.trim() ? "" : DEFAULT_ATTACHMENT_CATEGORY;
    rerender();
  });
  return {
    reset() {
      state.selected = DEFAULT_ATTACHMENT_CATEGORY;
      customInput.value = "";
      rerender();
    },
    getValue() {
      return customInput.value.trim() || state.selected || DEFAULT_ATTACHMENT_CATEGORY;
    },
  };
}

const attachmentCategoryPicker = elements.attachmentCategoryOptions && elements.attachmentCategoryCustom
  ? createAttachmentCategoryPicker(elements.attachmentCategoryOptions, elements.attachmentCategoryCustom)
  : null;
const attachmentTargetCategoryPicker = elements.attachmentTargetCategoryOptions && elements.attachmentTargetCategoryCustom
  ? createAttachmentCategoryPicker(elements.attachmentTargetCategoryOptions, elements.attachmentTargetCategoryCustom)
  : null;

let attachmentCategoryResolver = null;

function finishAttachmentCategorySelection(category = null) {
  const resolver = attachmentCategoryResolver;
  attachmentCategoryResolver = null;
  if (elements.attachmentCategoryDialog?.open) elements.attachmentCategoryDialog.close();
  resolver?.(category);
}


function requestAttachmentCategory(files) {
  if (!elements.attachmentCategoryDialog?.showModal || !attachmentCategoryPicker) {
    return Promise.resolve(DEFAULT_ATTACHMENT_CATEGORY);
  }
  if (attachmentCategoryResolver) return Promise.resolve(null);
  attachmentCategoryPicker.reset();
  elements.attachmentCategorySummary.textContent = describeAttachmentSelection(files);
  return new Promise((resolve) => {
    attachmentCategoryResolver = resolve;
    elements.attachmentCategoryDialog.showModal();
  });
}



let attachmentTargetResolver = null;
let attachmentTargetSelectedPolicyId = null;

function getAttachmentTargetHaystack(policy) {
  return normalize(
    [policy.clientName, policy.policyNumber, policy.registration, policy.identityNumber, policy.insurer]
      .filter(Boolean)
      .join(" "),
  );
}

function findAttachmentTargetPolicies(query) {
  const terms = normalize(query).split(" ").filter(Boolean);
  const matches = terms.length === 0
    ? [...policies]
    : policies.filter((policy) => {
      const haystack = getAttachmentTargetHaystack(policy);
      return terms.every((term) => haystack.includes(term));
    });
  return matches
    .sort((first, second) => String(second.validUntil ?? "").localeCompare(String(first.validUntil ?? "")))
    .slice(0, 30);
}

function updateAttachmentTargetConfirmState() {
  if (!elements.confirmAttachmentTarget) return;
  elements.confirmAttachmentTarget.disabled = !policies.some((policy) => policy.id === attachmentTargetSelectedPolicyId);
}

function renderAttachmentTargetResults() {
  if (!elements.attachmentTargetResults) return;
  const results = findAttachmentTargetPolicies(elements.attachmentTargetSearch?.value ?? "");
  if (attachmentTargetSelectedPolicyId && !results.some((policy) => policy.id === attachmentTargetSelectedPolicyId)) {
    attachmentTargetSelectedPolicyId = null;
  }
  elements.attachmentTargetResults.innerHTML = results.length === 0
    ? '<p class="attachment-target-results__empty">Nie znaleziono polis dla tego wyszukiwania.</p>'
    : results.map((policy) => {
      const selected = policy.id === attachmentTargetSelectedPolicyId;
      return `
        <button
          type="button"
          class="attachment-target-result${selected ? " attachment-target-result--selected" : ""}"
          data-target-policy-id="${escapeHtml(policy.id)}"
          aria-pressed="${selected}"
        >
          <span class="attachment-target-result__main">
            <strong>${escapeHtml(policy.clientName || "Bez nazwy")}</strong>
            <span>${escapeHtml(policy.policyNumber || "brak numeru")}</span>
          </span>
          <span class="attachment-target-result__meta">
            ${policy.insurer ? `<span>${escapeHtml(policy.insurer)}</span>` : ""}
            ${policy.registration ? `<span>${escapeHtml(policy.registration)}</span>` : ""}
            <span>do ${escapeHtml(formatDate(policy.validUntil) || "-")}</span>
          </span>
        </button>
      `;
    }).join("");
  updateAttachmentTargetConfirmState();
}

function finishAttachmentTargetSelection(result = null) {
  const resolver = attachmentTargetResolver;
  attachmentTargetResolver = null;
  if (elements.attachmentTargetDialog?.open) elements.attachmentTargetDialog.close();
  resolver?.(result);
}


function requestAttachmentTargetPolicy(files) {
  if (!elements.attachmentTargetDialog?.showModal || !attachmentTargetCategoryPicker) {
    return Promise.resolve(null);
  }
  if (attachmentTargetResolver) return Promise.resolve(null);
  attachmentTargetSelectedPolicyId = null;
  attachmentTargetCategoryPicker.reset();
  if (elements.attachmentTargetSearch) elements.attachmentTargetSearch.value = "";
  elements.attachmentTargetSummary.textContent = describeAttachmentSelection(files);
  renderAttachmentTargetResults();
  return new Promise((resolve) => {
    attachmentTargetResolver = resolve;
    elements.attachmentTargetDialog.showModal();
    requestAnimationFrame(() => elements.attachmentTargetSearch?.focus());
  });
}

async function attachImageFilesToChosenPolicy(imageFiles) {
  if (imageFiles.length === 0) return;
  if (policies.length === 0) {
    showToast("W bazie nie ma jeszcze polis, do których można podpiąć obrazy.", "warning");
    return;
  }
  const selection = await requestAttachmentTargetPolicy(imageFiles);
  if (!selection) {
    showToast(imageFiles.length === 1 ? "Nie wybrano polisy - obraz pominięto." : "Nie wybrano polisy - obrazy pominięto.", "warning");
    return;
  }
  await addAttachmentsToPolicy(selection.policyId, imageFiles, selection.category);
}

function createRenewalControls(policy, safeId, options = {}) {
  if (!renewalsOnly && !options.alwaysVisible) return "";
  if (POLICY_BUYER_TRANSFER_FEATURE_ENABLED && policy?.transferredToBuyer === true) {
    return `
      <div class="cell renewal-cell" role="cell" data-label="Odnowiona / utracona">
        <span class="renewal-result">Nie dotyczy</span>
      </div>
    `;
  }
  if (policy?.vehicleSold === true) {
    return `
      <div class="cell renewal-cell" role="cell" data-label="Odnowiona / utracona">
        <span class="renewal-result">Pojazd sprzedany</span>
      </div>
    `;
  }
  const renewed = policy.renewalStatus === "renewed";
  const notRenewed = policy.renewalStatus === "not-renewed";
  const statusLabel = renewed
    ? '<span class="renewal-result renewal-result--renewed">Odnowiona</span>'
    : notRenewed
      ? '<span class="renewal-result renewal-result--lost">Utracona</span>'
      : '<span class="renewal-result" aria-hidden="true"></span>';
  const editingClass = options.editing ? " renewal-cell--editing" : "";

  return `
    <div class="cell renewal-cell${editingClass}" role="cell" data-label="Odnowiona / utracona">
      ${statusLabel}
      <span class="renewal-choice">
        <button
          class="renewal-yes"
          type="button"
          data-action="renewed"
          data-policy-id="${safeId}"
          aria-label="Oznacz jako odnowioną"
          aria-pressed="${renewed}"
          title="Odnowiona"
        >✓</button>
        <button
          class="renewal-no"
          type="button"
          data-action="not-renewed"
          data-policy-id="${safeId}"
          aria-label="Oznacz jako utraconą"
          aria-pressed="${notRenewed}"
          title="Utracona"
        >×</button>
      </span>
    </div>
  `;
}

function getRenewalRowClass(policy) {
  if (POLICY_BUYER_TRANSFER_FEATURE_ENABLED && policy.transferredToBuyer === true) {
    return " policy-row--transferred";
  }
  if (policy.vehicleSold === true) return " policy-row--vehicle-sold";
  if (policy.renewalStatus === "renewed") return " policy-row--renewal-marked policy-row--renewed";
  if (policy.renewalStatus === "not-renewed") return " policy-row--renewal-marked policy-row--lost";
  return "";
}

function createEditingPolicyDraft(policy) {
  return {
    id: policy.id,
    clientName: policy.clientName ?? "",
    identityNumber: policy.identityNumber ?? "",
    insurer: policy.insurer ?? "",
    policyNumber: policy.policyNumber ?? "",
    registration: policy.registration ?? "",
    validFrom: formatDateForInput(getPolicyStartDate(policy)),
    validUntil: policy.validUntil ?? "",
    premium: policy.premium ?? "",
    contact: policy.contact ?? "",
    startDateManual: Boolean(policy.validFromManuallyEdited && parseLocalDate(policy.validFrom)),
  };
}

function captureEditingPolicyDraft(editForm = null) {
  const form = editForm || elements.rows.querySelector?.("[data-edit-form]");
  if (!form) return editingPolicyDraft;
  const formData = new FormData(form);
  editingPolicyDraft = {
    id: form.dataset.editForm,
    clientName: String(formData.get("clientName") ?? ""),
    identityNumber: String(formData.get("identityNumber") ?? ""),
    insurer: String(formData.get("insurer") ?? ""),
    policyNumber: String(formData.get("policyNumber") ?? ""),
    registration: String(formData.get("registration") ?? ""),
    validFrom: String(formData.get("validFrom") ?? ""),
    validUntil: String(formData.get("validUntil") ?? ""),
    premium: String(formData.get("premium") ?? ""),
    contact: String(formData.get("contact") ?? ""),
    startDateManual: form.dataset.startDateManual === "true",
  };
  return editingPolicyDraft;
}

function createEditablePolicyRow(policy) {
  const draft = editingPolicyDraft?.id === policy.id
    ? editingPolicyDraft
    : createEditingPolicyDraft(policy);
  const safeId = escapeHtml(policy.id);
  const safeName = escapeHtml(draft.clientName);
  const safeIdentityNumber = escapeHtml(draft.identityNumber);
  const safeInsurer = escapeHtml(draft.insurer);
  const safePolicyNumber = escapeHtml(draft.policyNumber);
  const safeRegistration = escapeHtml(draft.registration);
  const safeStartDate = escapeHtml(draft.validFrom);
  const safeValidUntil = escapeHtml(draft.validUntil);
  const safePremium = escapeHtml(draft.premium);
  const safeContact = escapeHtml(draft.contact);
  const startDateWasManual = Boolean(draft.startDateManual);

  return `
    <form
      class="policy-grid policy-row policy-row--editing policy-row--editing-with-renewals${getRenewalRowClass(policy)}"
      role="row"
      data-edit-form="${safeId}"
      data-start-date-manual="${startDateWasManual}"
      novalidate
    >
      ${createRenewalControls(policy, safeId, { alwaysVisible: true, editing: true })}
      <label class="inline-field" role="cell">
        <span class="inline-label">Imię i nazwisko / nazwa</span>
        <input name="clientName" type="text" list="clientOptions" autocomplete="off" value="${safeName}" />
      </label>
      <label class="inline-field" role="cell">
        <span class="inline-label">PESEL / NIP / REGON</span>
        <input name="identityNumber" type="text" inputmode="numeric" value="${safeIdentityNumber}" placeholder="pesel/nip/regon" />
      </label>
      <label class="inline-field" role="cell">
        <span class="inline-label">Towarzystwo</span>
        <input name="insurer" type="text" data-always-suggestions="insurer" aria-haspopup="listbox" aria-controls="alwaysVisibleSuggestions" aria-expanded="false" autocomplete="off" value="${safeInsurer}" placeholder="Towarzystwo" />
      </label>
      <label class="inline-field" role="cell">
        <span class="inline-label">Numer Polisy</span>
        <input name="policyNumber" type="text" value="${safePolicyNumber}" placeholder="Numer Polisy" />
      </label>
      <label class="inline-field" role="cell">
        <span class="inline-label">Nr Rej. / Rodzaj Polisy</span>
        <input name="registration" type="text" data-always-suggestions="registration" aria-haspopup="listbox" aria-controls="alwaysVisibleSuggestions" aria-expanded="false" autocomplete="off" value="${safeRegistration}" placeholder="Nr Rej albo rodzaj" />
      </label>
      <label class="inline-field" role="cell">
        <span class="inline-label">Od kiedy</span>
        <input name="validFrom" type="date" value="${safeStartDate}" />
      </label>
      <label class="inline-field" role="cell">
        <span class="inline-label">Do kiedy</span>
        <input name="validUntil" type="date" value="${safeValidUntil}" />
      </label>
      <label class="inline-field" role="cell">
        <span class="inline-label">Składka</span>
        <span class="premium-input">
          <input name="premium" type="text" inputmode="decimal" value="${safePremium}" placeholder="0,00" />
          <span>zł</span>
        </span>
      </label>
      <label class="inline-field" role="cell">
        <span class="inline-label">Notatki</span>
        <textarea name="contact" rows="1" data-auto-grow="true" placeholder="Tel, email, opis">${safeContact}</textarea>
      </label>
      <div class="inline-actions" role="cell">
        <button class="inline-save" type="submit" aria-label="Zapisz zmiany" title="Zapisz">✓</button>
        <button class="inline-cancel" type="button" data-action="cancel-edit" data-policy-id="${safeId}" aria-label="Anuluj edycję" title="Anuluj">×</button>
      </div>
    </form>
  `;
}

function createPolicyRow(policy) {
  if (editingPolicyId === policy.id) return createEditablePolicyRow(policy);
  const status = getPolicyStatus(policy.validUntil);
  const attachments = normalizePolicyAttachments(policy.attachments);
  const isExpanded = expandedPolicyId === policy.id;
  const attachmentPanelId = getAttachmentPanelId(policy.id);
  const safeId = escapeHtml(policy.id);
  const safeName = escapeHtml(policy.clientName || "-");
  const safeIdentityNumber = escapeHtml(policy.identityNumber || "-");
  const identityNumberCopyButton = formatIdentityNumberCopyButton(policy.identityNumber);
  const identityNumberTypeBadge = formatIdentityNumberTypeBadge(policy.identityNumber);
  const safeContact = escapeHtml(policy.contact || "-");
  const contactWithEmailLinks = formatContactWithEmailLinks(policy.contact);
  const safeInsurer = escapeHtml(policy.insurer || "-");
  const insurerCalculatorLink = formatInsurerCalculatorLink(policy.insurer);
  const safePolicyNumber = escapeHtml(policy.policyNumber || "-");
  const policyNumberCopyButton = String(policy.policyNumber || "").trim()
    ? `<button
        type="button"
        class="copy-value-button"
        data-action="copy-value"
        data-copy-value="${safePolicyNumber}"
        aria-label="Skopiuj numer polisy ${safePolicyNumber}"
        title="Kliknij, aby skopiować"
      >${safePolicyNumber}</button>`
    : `<span>${safePolicyNumber}</span>`;
  const renewalRelation = getRenewalRelationMarkup(policy);
  const safeRegistration = escapeHtml(policy.registration || "-");
  
  
  const homeStreetLabel = normalize(policy.registration) === "mieszkanie"
    ? formatHomeAddressLabel(policy.clientAddress)
    : "";
  const homeStreetMarkup = homeStreetLabel
    ? `<span class="registration-street" title="${escapeHtml(normalizeClientAddress(policy.clientAddress))}">${escapeHtml(homeStreetLabel)}</span>`
    : "";
  const safePremium = escapeHtml(formatPremium(policy.premium));
  const safeStartDate = escapeHtml(formatStartDate(policy));
  const safeDate = escapeHtml(formatDate(policy.validUntil));
  const dotClass = status.modifier === "active" ? "" : ` date-dot--${status.modifier}`;
  const recordQuoteButton = hasRegistrationNumber(policy)
    ? `
      <button
        class="record-quote-button"
        type="button"
        data-action="calculate-quote"
        data-policy-id="${safeId}"
        aria-label="Oblicz składkę dla ${safeRegistration}"
        title="Przenieś dane rekordu do kalkulatora"
      >Oblicz</button>
    `
    : "";
  const terminationButton = hasRegistrationNumber(policy)
    ? `
      <button
        class="termination-button"
        type="button"
        data-action="open-termination"
        data-policy-id="${safeId}"
        aria-label="Otwórz wypełnione wypowiedzenie OC dla ${safeRegistration}"
        title="Otwórz wypełnione wypowiedzenie OC"
      >Wypowiedzenie</button>
    `
    : "";

  return `
    <div class="policy-entry${isExpanded ? " policy-entry--expanded" : ""}" role="presentation" data-policy-entry="${safeId}">
      ${createPolicyOwnerBadge(policy)}
      <article
        class="policy-grid policy-row${getRenewalRowClass(policy)}"
        role="row"
      >
        ${createRenewalControls(policy, safeId)}
        <div class="cell cell--name" role="cell" title="${safeName}">
          <button
            class="attachment-button${isExpanded ? " attachment-button--active" : ""}"
            type="button"
            data-action="toggle-attachments"
            data-policy-id="${safeId}"
            aria-label="${attachments.length > 0 ? `Pokaż ${pluralizeAttachments(attachments.length)}` : "Pokaż załączniki rekordu"}"
            aria-expanded="${isExpanded}"
            aria-controls="${escapeHtml(attachmentPanelId)}"
            title="Załączniki"
          >
            <svg viewBox="0 0 20 20" fill="none" aria-hidden="true">
              <path d="m7.2 10.8 5.4-5.4a2.35 2.35 0 0 1 3.3 3.3l-7.2 7.2a3.65 3.65 0 0 1-5.2-5.1l7-7a2.45 2.45 0 0 1 3.45 3.45l-6.7 6.7a1.25 1.25 0 0 1-1.8-1.75l5.9-5.9" />
            </svg>
            ${attachments.length > 0 ? `<strong class="attachment-count">${attachments.length}</strong>` : ""}
          </button>
          <button
            class="client-profile-link"
            type="button"
            data-action="open-client-profile"
            data-policy-id="${safeId}"
            aria-label="Pokaż pełną kartę klienta ${safeName}"
            title="Pokaż wszystkie dane i polisy klienta"
          >${safeName}</button>
          ${POLICY_BUYER_TRANSFER_FEATURE_ENABLED && policy.transferredToBuyer === true
            ? `<span class="transferred-badge" title="${escapeHtml(`Pojazd zbyty - polisa przepisana na nabywcę: ${policy.buyerName || "nieznany"}${policy.buyerIdentityNumber ? ` (${policy.buyerIdentityNumber})` : ""}`)}">Pojazd zbyty</span>`
            : ""}
          ${policy.vehicleSold === true
            ? `<span class="vehicle-sold-badge" title="Pojazd sprzedany - oznaczony na karcie klienta, bez podpowiedzi odnowień">Pojazd sprzedany</span>`
            : ""}
        </div>
        <div class="cell identity-number-value" role="cell" data-label="PESEL / NIP / REGON" title="${safeIdentityNumber}">
          <span class="identity-number-text">${identityNumberCopyButton}</span>
          ${identityNumberTypeBadge}
        </div>
        <div class="cell" role="cell" data-label="Towarzystwo" title="${safeInsurer}">${insurerCalculatorLink}</div>
        <div class="cell policy-number-value" role="cell" data-label="Numer Polisy" title="${safePolicyNumber}">
          ${policyNumberCopyButton}
          ${renewalRelation}
        </div>
        <div class="cell registration-value" role="cell" data-label="Nr Rej. / Rodzaj Polisy">
          ${policy.registration ? (
            hasRegistrationNumber(policy)
              ? `<button
                  class="registration-pill registration-pill--button"
                  type="button"
                  data-action="open-vehicle-details"
                  data-policy-id="${safeId}"
                  aria-label="Pokaż dane pojazdu ${safeRegistration}"
                  title="Pokaż markę, model, VIN i datę pierwszej rejestracji"
                >${safeRegistration}</button>`
              : `<span class="registration-pill">${safeRegistration}</span>`
          ) : "-"}
          ${homeStreetMarkup}
          ${recordQuoteButton}
        </div>
        <div class="cell" role="cell" data-label="Od kiedy">${safeStartDate}</div>
        <div class="cell termination-date-cell" role="cell" data-label="Do kiedy">
          <span class="date-wrap" title="${escapeHtml(status.label)}"><span class="date-dot${dotClass}" aria-hidden="true"></span>${safeDate}</span>
          ${terminationButton}
        </div>
        <div class="cell premium-value" role="cell" data-label="Składka">${
          String(policy.riskSummary || "").trim()
            ? `<button
                class="premium-details-button"
                type="button"
                data-action="open-premium-details"
                data-policy-id="${safeId}"
                aria-label="Pokaż ryzyka i ceny dla ${safeName}"
                title="Pokaż ryzyka i ceny z polisy"
              >${safePremium}</button>`
            : safePremium
        }</div>
        <div class="cell contact-value" role="cell" data-label="Notatki" title="${safeContact}">
          <span class="contact-value__preview">${contactWithEmailLinks}</span>
          <button
            class="contact-details-button"
            type="button"
            data-action="open-contact-details"
            data-policy-id="${safeId}"
            aria-label="Otwórz pełny opis i informacje kontaktowe dla ${safeName}"
            title="Pełny opis i edycja"
          >...</button>
        </div>
        <div class="cell cell--actions row-actions" role="cell" data-label="Akcje">
          <button class="edit-button" type="button" data-action="edit" data-policy-id="${safeId}" aria-label="Edytuj rekord" title="Edytuj rekord">
            <svg viewBox="0 0 16 16" fill="none" aria-hidden="true">
              <path d="m9.8 3.2 3 3M3.5 12.5l.7-3 6.7-6.7a1.1 1.1 0 0 1 1.6 0l.7.7a1.1 1.1 0 0 1 0 1.6l-6.7 6.7-3 .7Z" />
            </svg>
          </button>
          <button
            class="delete-button"
            type="button"
            data-action="delete"
            data-policy-id="${safeId}"
            aria-label="Usuń rekord"
            title="Usuń rekord"
          >×</button>
        </div>
      </article>
      ${isExpanded ? createAttachmentsPanel(policy) : ""}
    </div>
  `;
}

function updateSummary(visiblePolicies, hasQuery) {
  const typedQueryLength = normalize(elements.search.value).length;
  if (typedQueryLength > 0 && typedQueryLength < MINIMUM_SEARCH_QUERY_LENGTH) {
    elements.resultsSummary.textContent = `Wpisz co najmniej ${MINIMUM_SEARCH_QUERY_LENGTH} znaki, aby wyszukać`;
  } else if (hasQuery) {
    elements.resultsSummary.textContent = `${pluralizePolicies(visiblePolicies.length)} znaleziono`;
  } else if (renewalsOnly) {
    const pendingCount = visiblePolicies.filter(isRenewalPending).length;
    elements.resultsSummary.textContent = `${pluralizePolicies(pendingCount)} do odnowienia`;
  } else if (hideRenewedPolicies || hideInactivePolicies) {
    const hiddenCount = policies.filter(isPolicyHiddenByVisibilityToggles).length;
    elements.resultsSummary.textContent = hiddenCount > 0
      ? `Ukryto: ${pluralizePolicies(hiddenCount)}`
      : "";
  } else {
    elements.resultsSummary.textContent = "";
  }
}

function updatePolicyVisibilityToggles() {
  elements.toggleRenewedPolicies.setAttribute("aria-pressed", String(hideRenewedPolicies));
  elements.toggleRenewedPoliciesLabel.textContent = hideRenewedPolicies
    ? "Pokaż polisy wznowione"
    : "Ukryj polisy wznowione";
  elements.toggleRenewedPolicies.title = hideRenewedPolicies
    ? "Polisy oznaczone jako wznowione są ukryte - kliknij, aby znów je pokazać"
    : "Ukryj polisy oznaczone jako wznowione";
  elements.toggleInactivePolicies.setAttribute("aria-pressed", String(hideInactivePolicies));
  elements.toggleInactivePoliciesLabel.textContent = hideInactivePolicies
    ? "Pokaż polisy nieaktywne"
    : "Ukryj polisy nieaktywne";
  elements.toggleInactivePolicies.title = hideInactivePolicies
    ? "Polisy po terminie są ukryte - kliknij, aby znów je pokazać"
    : "Ukryj polisy po terminie";
}

function updateEmptyState(hasQuery) {
  if (hasQuery) {
    elements.emptyTitle.textContent = "Brak pasujących wyników";
    elements.emptyCopy.textContent = "Spróbuj innej frazy lub zakresu dat albo wyczyść filtry wyszukiwania.";
  } else if (renewalsOnly) {
    elements.emptyTitle.textContent = "Brak polis do odnowienia";
    elements.emptyCopy.textContent = renewalShowExpired
      ? `Żadna polisa poza podróżnymi nie zakończyła się w ciągu ostatnich ${RENEWAL_PAST_DAYS} dni ani nie kończy się w ciągu najbliższych ${renewalWindowDays} dni.`
      : `Żadna polisa poza podróżnymi nie kończy się dzisiaj ani w ciągu najbliższych ${renewalWindowDays} dni.`;
  } else if ((hideRenewedPolicies || hideInactivePolicies) && policies.length > 0) {
    elements.emptyTitle.textContent = "Wszystkie polisy są ukryte";
    elements.emptyCopy.textContent = "Kliknij przycisk „Pokaż polisy” nad listą, aby znów je zobaczyć.";
  } else {
    elements.emptyTitle.textContent = "Brak zapisanych polis";
    elements.emptyCopy.textContent = "Uzupełnij dowolne pola powyżej i kliknij „Dodaj”.";
  }
}

function render() {
  renewalRelationIndexCache = null;
  if (editingPolicyId) captureEditingPolicyDraft();
  const visiblePolicies = getVisiblePolicies();
  const displayedPolicies = getPaginatedPolicies(visiblePolicies);
  const hasQuery = getEffectiveSearchQuery().length > 0
    || Boolean(elements.dateFilterFrom.value)
    || Boolean(elements.dateFilterTo.value);
  const renewalPoliciesCount = policies.filter(isRenewalPending).length;
  const activePoliciesCount = policies.filter(isPolicyActive).length;

  updateClientSuggestions();
  elements.rows.innerHTML = displayedPolicies.map(createPolicyRow).join("");
  elements.recordCount.textContent = pluralizePolicies(activePoliciesCount);
  elements.renewalCount.textContent = String(renewalPoliciesCount);
  elements.renewalButton.setAttribute("aria-pressed", String(renewalsOnly));
  elements.renewalWindow30.setAttribute("aria-pressed", String(renewalWindowDays === 30));
  elements.renewalWindow60.setAttribute("aria-pressed", String(renewalWindowDays === 60));
  updatePolicyVisibilityToggles();
  elements.card.classList.toggle("policies-card--renewals", renewalsOnly);
  elements.dateFilterToggle.classList.toggle(
    "date-filter-toggle--active",
    Boolean(elements.dateFilterFrom.value || elements.dateFilterTo.value),
  );
  elements.sortButton.setAttribute("aria-pressed", String(sortMode === "date"));
  elements.startDateSortButton.setAttribute("aria-pressed", String(sortMode === "startDate"));
  elements.premiumSortButton.setAttribute("aria-pressed", String(sortMode === "premium"));
  elements.clientNameSortButton.setAttribute("aria-pressed", String(sortMode === "clientName"));
  elements.insurerSortButton.setAttribute("aria-pressed", String(sortMode === "insurer"));
  elements.registrationSortButton.setAttribute("aria-pressed", String(sortMode === "registration" || sortMode === "policyType"));
  elements.sortButton.setAttribute("aria-sort", sortMode === "date" ? (sortDirection === "asc" ? "ascending" : "descending") : "none");
  elements.startDateSortButton.setAttribute("aria-sort", sortMode === "startDate" ? (sortDirection === "asc" ? "ascending" : "descending") : "none");
  elements.premiumSortButton.setAttribute("aria-sort", sortMode === "premium" ? (sortDirection === "asc" ? "ascending" : "descending") : "none");
  elements.clientNameSortButton.setAttribute("aria-sort", sortMode === "clientName" ? (sortDirection === "asc" ? "ascending" : "descending") : "none");
  elements.insurerSortButton.setAttribute("aria-sort", sortMode === "insurer" ? "other" : "none");
  elements.registrationSortButton.setAttribute("aria-sort", sortMode === "registration" || sortMode === "policyType" ? "other" : "none");
  elements.sortButton.setAttribute("data-sort-direction", sortMode === "date" ? sortDirection : "none");
  elements.startDateSortButton.setAttribute("data-sort-direction", sortMode === "startDate" ? sortDirection : "none");
  elements.premiumSortButton.setAttribute("data-sort-direction", sortMode === "premium" ? sortDirection : "none");
  elements.clientNameSortButton.setAttribute("data-sort-direction", sortMode === "clientName" ? sortDirection : "none");
  elements.registrationSortButton.setAttribute(
    "data-registration-sort-mode",
    sortMode === "registration" || sortMode === "policyType" ? sortMode : "none",
  );
  const insurerCycleLabel = sortMode === "insurer" && insurerSortSelection ? insurerSortSelection.label : "";
  setSortCycleValue(elements.insurerSortButton, insurerCycleLabel);
  elements.insurerSortButton.title = insurerCycleLabel
    ? `Na górze: ${insurerCycleLabel} - kliknij, aby przejść do następnego towarzystwa`
    : "Sortuj po towarzystwie - kolejne kliknięcia przełączają towarzystwa";
  const registrationCycleLabel = sortMode === "registration"
    ? REGISTRATION_GROUP_LABEL
    : sortMode === "policyType" && policyTypeSortIndex >= 0
      ? REGISTRATION_SUGGESTIONS[policyTypeSortIndex] ?? ""
      : "";
  setSortCycleValue(elements.registrationSortButton, registrationCycleLabel);
  elements.registrationSortButton.title = registrationCycleLabel
    ? `Na górze: ${registrationCycleLabel} - kliknij, aby przejść do następnej grupy`
    : "Sortuj najpierw po numerach rejestracyjnych, potem po rodzajach polis";
  elements.resetSortingButton.disabled = sortMode === null;
  elements.sortButton.title = sortMode === "date" && sortDirection === "asc"
    ? "Najwcześniejsze daty są u góry - kliknij, aby odwrócić kolejność"
    : "Sortuj od najwcześniejszej daty zakończenia";
  elements.startDateSortButton.title = sortMode === "startDate" && sortDirection === "asc"
    ? "Najwcześniejsze daty rozpoczęcia są u góry - kliknij, aby odwrócić kolejność"
    : "Sortuj od najwcześniejszej daty rozpoczęcia";
  elements.premiumSortButton.title = sortMode === "premium" && sortDirection === "asc"
    ? "Najniższe składki są u góry - kliknij, aby odwrócić kolejność"
    : "Sortuj od najniższej składki";
  updateSummary(visiblePolicies, hasQuery);
  updatePaginationControls(visiblePolicies.length);

  elements.emptyState.hidden = visiblePolicies.length > 0;
  if (visiblePolicies.length === 0) updateEmptyState(hasQuery);
  applyFontSize(document.documentElement.dataset.fontSize);
  document.querySelectorAll("textarea[data-auto-grow]").forEach(resizeAutoGrowingTextarea);
  if (expandedPolicyId) startAttachmentPanelOpenTransition(expandedPolicyId);
  if (expandedPolicyId) {
    void loadAttachmentPreviews(expandedPolicyId);
  }
  updateTodayTaskIndicator();
  schedulePageScrollControlsUpdate();
}

function getClientProfileIdentityValues(policy) {
  return [policy?.identityNumber, policy?.secondaryIdentityNumber]
    .map((value) => String(value ?? "").trim())
    .filter(Boolean);
}

function getClientProfileIdentityKey(value) {
  const text = String(value ?? "").trim();
  const digits = text.replace(/\D/g, "");
  return digits || normalize(text).replace(/\s+/g, "");
}

function hasAmbiguousClientProfileName(clientName) {
  const normalizedName = normalize(clientName);
  if (!normalizedName) return false;
  const identitiesByType = new Map();
  policies.forEach((policy) => {
    if (normalize(policy.clientName) !== normalizedName) return;
    getClientProfileIdentityValues(policy).forEach((value) => {
      const identityType = getIdentityNumberType(value) || "INNY";
      const identityKeys = identitiesByType.get(identityType) || new Set();
      identityKeys.add(getClientProfileIdentityKey(value));
      identitiesByType.set(identityType, identityKeys);
    });
  });
  return [...identitiesByType.values()].some((identityKeys) => identityKeys.size > 1);
}

function haveMatchingClientProfile(firstPolicy, secondPolicy) {
  if (!firstPolicy || !secondPolicy) return false;
  if (firstPolicy.id && firstPolicy.id === secondPolicy.id) return true;
  const firstIdentities = getClientProfileIdentityValues(firstPolicy);
  const secondIdentities = getClientProfileIdentityValues(secondPolicy);
  const secondIdentityKeys = new Set(secondIdentities.map(getClientProfileIdentityKey));
  if (firstIdentities.some((value) => secondIdentityKeys.has(getClientProfileIdentityKey(value)))) return true;

  const firstPrimary = String(firstPolicy.identityNumber ?? "").trim();
  const secondPrimary = String(secondPolicy.identityNumber ?? "").trim();
  const firstType = getIdentityNumberType(firstPrimary);
  const secondType = getIdentityNumberType(secondPrimary);
  if (firstPrimary && secondPrimary && firstType && firstType === secondType) return false;
  const normalizedName = normalize(firstPolicy.clientName);
  if (!normalizedName || normalizedName !== normalize(secondPolicy.clientName)) return false;
  if (
    (firstIdentities.length === 0 || secondIdentities.length === 0)
    && hasAmbiguousClientProfileName(normalizedName)
  ) return false;
  return true;
}

function getClientProfilePolicies(anchorPolicy) {
  if (!anchorPolicy) return [];
  return policies
    .filter((policy) => haveMatchingClientProfile(anchorPolicy, policy))
    .sort((first, second) => {
      const activeDifference = Number(!isPolicyExpired(second)) - Number(!isPolicyExpired(first));
      if (activeDifference) return activeDifference;
      const firstDate = parseLocalDate(first.validUntil)?.getTime() || 0;
      const secondDate = parseLocalDate(second.validUntil)?.getTime() || 0;
      return secondDate - firstDate || Number(second.updatedAt || second.createdAt || 0) - Number(first.updatedAt || first.createdAt || 0);
    });
}

function haveMatchingVehicleHistoryClient(firstPolicy, secondPolicy) {
  if (!firstPolicy || !secondPolicy) return false;
  if (firstPolicy.id && firstPolicy.id === secondPolicy.id) return true;
  const firstIdentityKeys = new Set(
    getClientProfileIdentityValues(firstPolicy).map(getClientProfileIdentityKey),
  );
  const secondIdentityKeys = new Set(
    getClientProfileIdentityValues(secondPolicy).map(getClientProfileIdentityKey),
  );
  if (firstIdentityKeys.size > 0 || secondIdentityKeys.size > 0) {
    return [...firstIdentityKeys].some((identityKey) => secondIdentityKeys.has(identityKey));
  }
  const firstName = normalize(firstPolicy.clientName);
  return Boolean(firstName) && firstName === normalize(secondPolicy.clientName);
}

function getSameClientVehiclePolicies(anchorPolicy) {
  const registrationKey = normalizeVehicleIdentifier(anchorPolicy?.registration);
  if (!anchorPolicy || !registrationKey) return [];
  return policies.filter((policy) => (
    hasRegistrationNumber(policy)
    && normalizeVehicleIdentifier(policy.registration) === registrationKey
    && haveMatchingVehicleHistoryClient(anchorPolicy, policy)
  ));
}

function getClientProfileCurrentPolicies() {
  const anchorPolicy = policies.find((policy) => policy.id === clientProfilePolicyId);
  return getClientProfilePolicies(anchorPolicy);
}

function pickClientProfileValue(profilePolicies, fieldName) {
  for (const policy of profilePolicies) {
    const value = String(policy?.[fieldName] ?? "").trim();
    if (value) return value;
  }
  return "";
}

function getClientProfilePhone(profilePolicies) {
  return pickClientProfileValue(profilePolicies, "clientPhone")
    || profilePolicies.map((policy) => extractClientPhone(policy.contact)).find(Boolean)
    || "";
}

function getClientProfileEmail(profilePolicies) {
  return pickClientProfileValue(profilePolicies, "clientEmail")
    || profilePolicies.map((policy) => extractClientEmail(policy.contact)).find(Boolean)
    || "";
}

function getClientProfileDistinctValues(profilePolicies, fieldName) {
  const values = new Map();
  profilePolicies.forEach((policy) => {
    const value = String(policy?.[fieldName] ?? "").trim();
    const key = normalize(value);
    if (key && !values.has(key)) values.set(key, value);
  });
  return [...values.values()];
}

function getPeselDetails(value) {
  const pesel = String(value ?? "").replace(/\D/g, "");
  if (pesel.length !== 11) return null;
  let year = 1900 + Number(pesel.slice(0, 2));
  let month = Number(pesel.slice(2, 4));
  const day = Number(pesel.slice(4, 6));
  if (month >= 81 && month <= 92) {
    year -= 100;
    month -= 80;
  } else if (month >= 21 && month <= 32) {
    year += 100;
    month -= 20;
  } else if (month >= 41 && month <= 52) {
    year += 200;
    month -= 40;
  } else if (month >= 61 && month <= 72) {
    year += 300;
    month -= 60;
  }
  const date = new Date(year, month - 1, day);
  if (
    date.getFullYear() !== year
    || date.getMonth() !== month - 1
    || date.getDate() !== day
  ) return null;
  return {
    birthDate: SHORT_DATE_FORMAT.format(date),
    sex: Number(pesel[9]) % 2 ? "mężczyzna" : "kobieta",
  };
}

function getClientProfileVehicleGroups(profilePolicies) {
  const groups = new Map();
  profilePolicies.filter(hasRegistrationNumber).forEach((policy) => {
    const key = normalize(policy.registration).replace(/\s+/g, "");
    if (!key) return;
    const group = groups.get(key);
    if (group) group.push(policy);
    else groups.set(key, [policy]);
  });
  return [...groups.entries()].map(([key, vehiclePolicies]) => ({
    key,
    policies: vehiclePolicies,
    latest: vehiclePolicies[0],
    sold: vehiclePolicies.some((policy) => policy.vehicleSold === true),
    removedFromProfile: vehiclePolicies.every((policy) => policy.vehicleRemovedFromProfile === true),
  }));
}

function getClientProfilePremiumTotal(profilePolicies) {
  const total = profilePolicies.reduce((sum, policy) => sum + (parsePremiumValue(policy.premium) || 0), 0);
  return total > 0 ? formatPremium(String(total)) : "brak danych";
}

function formatClientProfileIdentityLabel(value) {
  const trimmed = String(value ?? "").trim();
  if (!trimmed) return "";
  const type = getIdentityNumberType(trimmed);
  return type ? `${type} ${trimmed}` : trimmed;
}






function getClientProfileSearchOptions() {
  const items = [];
  policies.forEach((policy) => {
    const name = String(policy.clientName ?? "").trim();
    if (!name) return;
    items.push({ policy, name, nameKey: normalize(name) });
  });
  const parents = items.map((_, index) => index);
  const findRoot = (index) => {
    let root = index;
    while (parents[root] !== root) root = parents[root];
    while (parents[index] !== root) {
      const next = parents[index];
      parents[index] = root;
      index = next;
    }
    return root;
  };
  const union = (firstIndex, secondIndex) => {
    const firstRoot = findRoot(firstIndex);
    const secondRoot = findRoot(secondIndex);
    if (firstRoot !== secondRoot) parents[secondRoot] = firstRoot;
  };

  const identityAnchors = new Map();
  items.forEach((item, index) => {
    getClientProfileIdentityValues(item.policy).forEach((value) => {
      const key = getClientProfileIdentityKey(value);
      if (!key) return;
      if (identityAnchors.has(key)) union(identityAnchors.get(key), index);
      else identityAnchors.set(key, index);
    });
  });

  const nameGroups = new Map();
  items.forEach((item, index) => {
    if (!nameGroups.has(item.nameKey)) nameGroups.set(item.nameKey, []);
    nameGroups.get(item.nameKey).push(index);
  });
  nameGroups.forEach((indexes) => {
    const primaryKeysByType = new Map();
    let hasSameTypeConflict = false;
    indexes.forEach((index) => {
      const primary = String(items[index].policy.identityNumber ?? "").trim();
      const type = getIdentityNumberType(primary);
      if (!primary || !type) return;
      const key = getClientProfileIdentityKey(primary);
      const existingKey = primaryKeysByType.get(type);
      if (existingKey && existingKey !== key) hasSameTypeConflict = true;
      else primaryKeysByType.set(type, key);
    });
    if (hasSameTypeConflict) return;
    indexes.slice(1).forEach((index) => union(indexes[0], index));
  });

  const clusters = new Map();
  items.forEach((item, index) => {
    const root = findRoot(index);
    if (!clusters.has(root)) clusters.set(root, { names: new Map(), identities: new Map() });
    const cluster = clusters.get(root);
    if (!cluster.names.has(item.nameKey)) cluster.names.set(item.nameKey, item.name);
    getClientProfileIdentityValues(item.policy).forEach((value) => {
      const key = getClientProfileIdentityKey(value);
      if (key && !cluster.identities.has(key)) cluster.identities.set(key, value);
    });
  });

  const options = [];
  clusters.forEach((cluster) => {
    const identity = [...cluster.identities.values()]
      .map(formatClientProfileIdentityLabel)
      .join(" · ");
    cluster.names.forEach((name) => options.push({ name, identity }));
  });
  return options.sort((first, second) => compareAlphabetically(first.name, second.name));
}

function findClientProfilePolicy(query, excludedPolicyIds = null) {
  const normalizedQuery = normalize(query);
  if (!normalizedQuery) return null;
  const compactQuery = normalizedQuery.replace(/\s+/g, "");
  const ranked = policies.map((policy) => {
    if (excludedPolicyIds?.has(policy.id)) return { policy, score: 0 };
    const clientName = normalize(policy.clientName);
    const identityValues = getClientProfileIdentityValues(policy).map((value) => normalize(value).replace(/\s+/g, ""));
    const searchableValues = [
      policy.clientName,
      policy.identityNumber,
      policy.secondaryIdentityNumber,
      policy.clientPhone,
      policy.clientEmail,
      policy.policyNumber,
      policy.registration,
    ].map((value) => normalize(value));
    let score = 0;
    if (clientName === normalizedQuery) score = 100;
    else if (identityValues.includes(compactQuery)) score = 95;
    else if (searchableValues.some((value) => value === normalizedQuery)) score = 90;
    else if (searchableValues.some((value) => value.includes(normalizedQuery))) score = 60;
    else if (normalizedQuery.split(/\s+/).every((term) => searchableValues.some((value) => value.includes(term)))) score = 40;
    return { policy, score };
  }).filter((item) => item.score > 0);
  ranked.sort((first, second) => second.score - first.score);
  return ranked[0]?.policy || null;
}

function formatClientProfilePolicyStatus(policy) {
  if (POLICY_BUYER_TRANSFER_FEATURE_ENABLED && policy?.transferredToBuyer === true) {
    return { label: "Pojazd zbyty", modifier: "transferred" };
  }
  if (policy?.vehicleSold === true && !isPolicyExpired(policy)) {
    return { label: "Pojazd sprzedany", modifier: "sold" };
  }
  if (isPolicyExpired(policy)) return { label: "Historyczna", modifier: "history" };
  const status = getPolicyStatus(policy.validUntil);
  if (status.modifier === "unknown") return { label: "Bez daty końca", modifier: "unknown" };
  return {
    label: status.modifier === "soon" ? "Kończy się wkrótce" : "Aktywna",
    modifier: status.modifier === "soon" ? "soon" : "active",
  };
}

function getClientProfilePolicyOwnerLabel(policy) {
  const ownerId = getPolicyOwnerIdForFiltering(policy);
  if (!ownerId) return "Brak oznaczenia konta";
  if (currentAccount?.id === ownerId) return `${currentAccount.name || "Moje konto"} (moje)`;
  return agencyMembers.find((member) => member.id === ownerId)?.label || ownerId;
}

function getClientProfileRenewalLabel(policy) {
  if (POLICY_BUYER_TRANSFER_FEATURE_ENABLED && policy?.transferredToBuyer === true) {
    return "Nie dotyczy - pojazd zbyty";
  }
  if (policy?.vehicleSold === true) return "Nie dotyczy - pojazd sprzedany";
  const previousPolicy = policies.find((item) => item.id === policy.previousPolicyId);
  const successorPolicy = policies.find((item) => item.previousPolicyId === policy.id);
  if (successorPolicy) return `Wznowiona polisą ${successorPolicy.policyNumber || "bez numeru"}`;
  if (previousPolicy) return `Wznowienie polisy ${previousPolicy.policyNumber || "bez numeru"}`;
  if (policy.renewalStatus === "renewed") return "Oznaczona jako wznowiona";
  if (policy.renewalStatus === "not-renewed") return "Oznaczona jako niewznowiona";
  return "Brak oznaczenia";
}

function formatVehicleSoldDate(value) {
  const date = new Date(Number(value));
  if (!Number.isFinite(Number(value)) || Number.isNaN(date.getTime())) return "";
  return ` (${SHORT_DATE_FORMAT.format(date)})`;
}

function formatClientProfileTimestamp(value) {
  const date = new Date(Number(value));
  if (Number.isNaN(date.getTime())) return "Brak danych";
  return new Intl.DateTimeFormat("pl-PL", {
    day: "2-digit",
    month: "2-digit",
    year: "numeric",
    hour: "2-digit",
    minute: "2-digit",
  }).format(date);
}

function createClientProfilePolicyEditForm(policy) {
  return `
    <form class="client-profile-policy-edit" data-client-profile-policy-form="${escapeHtml(policy.id)}">
      <div class="client-profile-edit-grid">
        <label><span>Towarzystwo</span><input name="insurer" value="${escapeHtml(policy.insurer || "")}" /></label>
        <label><span>Numer polisy</span><input name="policyNumber" value="${escapeHtml(policy.policyNumber || "")}" /></label>
        <label><span>Nr rej. / rodzaj</span><input name="registration" value="${escapeHtml(policy.registration || "")}" /></label>
        <label><span>Data wystawienia</span><input name="issueDate" type="date" value="${escapeHtml(policy.issueDate || "")}" /></label>
        <label><span>Od kiedy</span><input name="validFrom" type="date" value="${escapeHtml(formatDateForInput(getPolicyStartDate(policy)))}" /></label>
        <label><span>Do kiedy</span><input name="validUntil" type="date" value="${escapeHtml(policy.validUntil || "")}" /></label>
        <label><span>Składka</span><input name="premium" inputmode="decimal" value="${escapeHtml(policy.premium || "")}" /></label>
        <label>
          <span>Status wznowienia</span>
          ${POLICY_BUYER_TRANSFER_FEATURE_ENABLED && policy.transferredToBuyer === true
            ? `<select name="renewalStatus" disabled><option value="">Nie dotyczy - pojazd zbyty</option></select>`
            : `<select name="renewalStatus">
                <option value=""${!policy.renewalStatus ? " selected" : ""}>Brak oznaczenia</option>
                <option value="renewed"${policy.renewalStatus === "renewed" ? " selected" : ""}>Wznowiona</option>
                <option value="not-renewed"${policy.renewalStatus === "not-renewed" ? " selected" : ""}>Niewznowiona</option>
              </select>`}
        </label>
        ${POLICY_BUYER_TRANSFER_FEATURE_ENABLED && policy.transferredToBuyer === true
          ? `<label>
              <span>Pojazd zbyty</span>
              ${isValidPolicyBuyerSnapshot(policy.buyerSnapshot)
                ? `<select name="transferredToBuyer">
                    <option value="yes" selected>Tak - przepisana na nabywcę</option>
                    <option value="">Nie - przywróć nabywcę jako klienta</option>
                  </select>`
                : `<select disabled>
                    <option>Tak - brak bezpiecznej migawki do cofnięcia</option>
                  </select>`}
            </label>`
          : ""}
      </div>
      <label class="client-profile-wide-field">
        <span>Ryzyka i ceny z polisy</span>
        <textarea name="riskSummary" rows="2">${escapeHtml(policy.riskSummary || "")}</textarea>
      </label>
      <label class="client-profile-wide-field">
        <span>Kontakt / notatki tej polisy</span>
        <textarea name="contact" rows="3">${escapeHtml(policy.contact || "")}</textarea>
      </label>
      <div class="client-profile-form-actions">
        <button class="settings-secondary-button" type="button" data-client-profile-cancel-policy>Anuluj</button>
        <button class="settings-save-button" type="submit">Zapisz polisę</button>
      </div>
    </form>
  `;
}

function createClientProfilePolicyCard(policy) {
  const status = formatClientProfilePolicyStatus(policy);
  const isEditing = clientProfileEditingPolicyId === policy.id;
  const attachments = normalizePolicyAttachments(policy.attachments);
  const meta = [
    policy.insurer || "Bez towarzystwa",
    policy.policyNumber ? `Polisa ${policy.policyNumber}` : "Bez numeru polisy",
  ].join(" · ");
  const attachmentButtons = attachments.map((attachment, index) => `
    <button
      type="button"
      class="client-profile-attachment-open"
      data-client-profile-open-attachment="${escapeHtml(policy.id)}"
      data-attachment-id="${escapeHtml(attachment.id)}"
      title="${escapeHtml(`Otwórz załącznik ${attachment.name || ""}`.trim())}"
    >${attachments.length === 1 ? "Otwórz załącznik" : `Załącznik ${index + 1}`}</button>
  `).join("");
  return `
    <article
      class="client-profile-policy-card client-profile-policy-card--${status.modifier}"
      data-client-profile-policy-card="${escapeHtml(policy.id)}"
    >
      <div class="client-profile-policy-card__top">
        <div>
          <span class="client-profile-status client-profile-status--${status.modifier}">${status.label}</span>
          <strong>${escapeHtml(meta)}</strong>
          <small>${escapeHtml(policy.registration || "Polisa bez numeru rejestracyjnego / rodzaju")}</small>
        </div>
        <div class="client-profile-policy-premium">
          <span>Składka</span>
          <strong>${escapeHtml(formatPremium(policy.premium))}</strong>
        </div>
      </div>
      <dl class="client-profile-policy-facts">
        <div><dt>Wystawiona</dt><dd>${escapeHtml(policy.issueDate ? formatDate(policy.issueDate) : "Brak informacji")}</dd></div>
        <div><dt>Okres</dt><dd>${escapeHtml(formatStartDate(policy))} - ${escapeHtml(formatDate(policy.validUntil))}</dd></div>
        <div><dt>Ryzyka</dt><dd>${escapeHtml(policy.riskSummary || "Brak szczegółów")}</dd></div>
        ${POLICY_BUYER_TRANSFER_FEATURE_ENABLED && policy.transferredToBuyer === true
          ? `<div><dt>Pojazd zbyty</dt><dd>${escapeHtml(`Polisa przepisana na nabywcę: ${policy.buyerName || "nieznany"}${policy.buyerIdentityNumber ? ` (${policy.buyerIdentityNumber})` : ""}`)}</dd></div>`
          : ""}
        ${policy.vehicleSold === true
          ? `<div><dt>Pojazd sprzedany</dt><dd>${escapeHtml(`Oznaczony jako sprzedany na karcie klienta${formatVehicleSoldDate(policy.vehicleSoldAt)}`)}</dd></div>`
          : ""}
        <div><dt>Wznowienie</dt><dd>${escapeHtml(getClientProfileRenewalLabel(policy))}</dd></div>
        <div><dt>Konto</dt><dd>${escapeHtml(getClientProfilePolicyOwnerLabel(policy))}</dd></div>
        <div><dt>Dodano</dt><dd>${escapeHtml(formatClientProfileTimestamp(policy.createdAt))}</dd></div>
        <div><dt>Załączniki</dt><dd>${attachments.length}</dd></div>
      </dl>
      ${policy.contact ? `<p class="client-profile-policy-note">${formatContactWithEmailLinks(policy.contact)}</p>` : ""}
      ${isEditing
        ? createClientProfilePolicyEditForm(policy)
        : `<div class="client-profile-card-actions">
            ${attachmentButtons}
            <button type="button" data-client-profile-edit-policy="${escapeHtml(policy.id)}">Edytuj dane polisy</button>
          </div>`}
    </article>
  `;
}

function createClientProfileVehicleEditForm(vehicleGroup) {
  const policy = vehicleGroup.latest;
  return `
    <form class="client-profile-vehicle-edit" data-client-profile-vehicle-form="${escapeHtml(vehicleGroup.key)}">
      <div class="client-profile-edit-grid">
        <label><span>Numer rejestracyjny</span><input name="registration" value="${escapeHtml(policy.registration || "")}" /></label>
        <label><span>Marka</span><input name="vehicleMake" value="${escapeHtml(policy.vehicleMake || "")}" /></label>
        <label><span>Model</span><input name="vehicleModel" value="${escapeHtml(policy.vehicleModel || "")}" /></label>
        <label><span>Rodzaj pojazdu</span><input name="vehicleType" value="${escapeHtml(policy.vehicleType || "")}" placeholder="np. samochód osobowy" /></label>
        <label><span>Rok produkcji</span><input name="productionYear" value="${escapeHtml(policy.productionYear || "")}" /></label>
        <label><span>VIN</span><input name="vin" value="${escapeHtml(policy.vin || "")}" /></label>
        <label><span>Pierwsza rejestracja</span><input name="firstRegistrationDate" type="date" value="${escapeHtml(policy.firstRegistrationDate || "")}" /></label>
        <label><span>Paliwo</span><input name="fuelType" value="${escapeHtml(policy.fuelType || "")}" /></label>
        <label><span>Pojemność silnika</span><input name="engineCapacity" value="${escapeHtml(getVehicleNumericEditValue("engineCapacity", policy.engineCapacity))}" /></label>
        <label><span>Moc silnika</span><input name="enginePower" value="${escapeHtml(getVehicleNumericEditValue("enginePower", policy.enginePower))}" /></label>
        <label><span>Liczba miejsc</span><input name="seats" value="${escapeHtml(policy.seats || "")}" /></label>
        <label><span>DMC</span><input name="grossWeight" value="${escapeHtml(getVehicleNumericEditValue("grossWeight", policy.grossWeight))}" /></label>
        <label><span>Przebieg</span><input name="mileage" value="${escapeHtml(getVehicleNumericEditValue("mileage", policy.mileage))}" /></label>
        <label><span>Prawo jazdy od</span><input name="driverLicenseDate" value="${escapeHtml(policy.driverLicenseDate || "")}" placeholder="RRRR lub RRRR-MM-DD" /></label>
      </div>
      <div class="client-profile-form-actions">
        <button class="settings-secondary-button" type="button" data-client-profile-cancel-vehicle>Anuluj</button>
        <button class="settings-save-button" type="submit">Zapisz dane pojazdu</button>
      </div>
    </form>
  `;
}

function createClientProfileVehicleCard(vehicleGroup) {
  const policy = vehicleGroup.latest;
  const vehicleName = [
    [policy.vehicleMake, policy.vehicleModel].filter(Boolean).join(" "),
    policy.vehicleType,
  ].filter(Boolean).join(" · ") || "Pojazd bez marki i modelu";
  const isEditing = clientProfileEditingVehicleKey === vehicleGroup.key;
  const historyBusy = clientProfileVehicleHistoryBusyKey === vehicleGroup.key;
  
  
  const highlightMissing = clientProfileVehicleHistoryHighlights.has(vehicleGroup.key);
  const missingRegistration = !String(policy.registration ?? "").trim();
  const missingVin = !String(policy.vin ?? "").trim();
  const missingFirstRegistration = !normalizeFirstRegistrationDate(policy.firstRegistrationDate);
  
  
  const detailPairs = [
    ["VIN", policy.vin, highlightMissing && missingVin, true],
    ["Pierwsza rejestracja", formatDate(policy.firstRegistrationDate), highlightMissing && missingFirstRegistration, false],
    ["Rok produkcji", policy.productionYear, false, false],
    ["Rodzaj pojazdu", policy.vehicleType, false, false],
    ["Paliwo", policy.fuelType, false, false],
    ["Pojemność silnika", policy.engineCapacity, false, false],
    ["Moc silnika", policy.enginePower, false, false],
    ["Liczba miejsc", policy.seats, false, false],
    ["DMC", policy.grossWeight, false, false],
    ["Przebieg", policy.mileage, false, false],
    ["Prawo jazdy od", formatDriverLicenseDateDisplay(policy.driverLicenseDate), false, false],
  ];
  return `
    <article class="client-profile-vehicle-card${vehicleGroup.sold ? " client-profile-vehicle-card--sold" : ""}">
      <div class="client-profile-vehicle-title">
        <div>
          <button type="button" class="client-profile-vehicle-registration-button" data-client-profile-edit-vehicle="${escapeHtml(vehicleGroup.key)}"
            title="Kliknij, aby edytować numer rejestracyjny"${historyBusy ? " disabled" : ""}>
            <strong${highlightMissing && missingRegistration ? ` class="client-profile-vehicle-fact--missing"` : ""}>${escapeHtml(policy.registration)}</strong>
          </button>
          <span>${escapeHtml(vehicleName)}</span>
          ${vehicleGroup.sold ? `<span class="client-profile-vehicle-sold-badge">Sprzedany</span>` : ""}
        </div>
        <small>${pluralizePolicies(vehicleGroup.policies.length)} w historii</small>
      </div>
      <dl class="client-profile-vehicle-facts">
        ${detailPairs.map(([label, value, missing, wide]) => {
          const hasValue = Boolean(value && value !== "-");
          const tileClasses = [
            wide ? "client-profile-vehicle-fact--wide" : "",
            missing ? "client-profile-vehicle-fact--missing" : "",
          ].filter(Boolean).join(" ");
          return `
          <div${tileClasses ? ` class="${tileClasses}"` : ""}><dt>${escapeHtml(label)}</dt><dd${hasValue ? "" : ` class="client-profile-vehicle-fact-empty"`}>${escapeHtml(hasValue ? String(value) : "Brak danych")}</dd></div>
        `;
        }).join("")}
      </dl>
      ${isEditing
        ? createClientProfileVehicleEditForm(vehicleGroup)
        : `<div class="client-profile-card-actions client-profile-card-actions--vehicle">
            <button type="button" class="client-profile-vehicle-history-button${historyBusy ? " client-profile-vehicle-history-button--busy" : ""}"
              data-client-profile-vehicle-history="${escapeHtml(vehicleGroup.key)}"${historyBusy ? " disabled" : ""}>
              ${historyBusy ? "Pobieranie..." : "HistoriaPojazdu.gov"}
            </button>
            <button type="button" data-client-profile-edit-vehicle="${escapeHtml(vehicleGroup.key)}"${historyBusy ? " disabled" : ""}>Edytuj pojazd</button>
            <button type="button" data-client-profile-vehicle-sold="${escapeHtml(vehicleGroup.key)}" data-sold-next="${vehicleGroup.sold ? "" : "yes"}"${historyBusy ? " disabled" : ""}>
              ${vehicleGroup.sold ? "Cofnij oznaczenie sprzedaży" : "Pojazd sprzedany"}
            </button>
            <button type="button" class="client-profile-card-action--danger" data-client-profile-remove-vehicle="${escapeHtml(vehicleGroup.key)}"${historyBusy ? " disabled" : ""}>Usuń pojazd</button>
          </div>`}
    </article>
  `;
}




const CLIENT_PROFILE_MERGE_ENABLED = true;
document.documentElement.dataset.clientProfileMergeEnabled = CLIENT_PROFILE_MERGE_ENABLED ? "true" : "false";

function createClientProfileMergeDisabledError() {
  const error = new Error("Funkcja łączenia kart klienta jest wyłączona.");
  error.code = "FEATURE_DISABLED";
  return error;
}







function getClientProfileMergeIdentityTypeSets(policiesList) {
  const sets = { PESEL: new Set(), NIP: new Set(), REGON: new Set() };
  policiesList.forEach((policy) => {
    getClientProfileIdentityValues(policy).forEach((value) => {
      const type = getIdentityNumberType(value);
      if (type) sets[type].add(getClientProfileIdentityKey(value));
    });
  });
  return sets;
}

function getClientProfileMergeSuggestions(profilePolicies) {
  const excludedIds = new Set(profilePolicies.map((policy) => policy.id));
  const profileIdentities = getClientProfileMergeIdentityTypeSets(profilePolicies);
  const nameVariants = getClientProfileDistinctValues(profilePolicies, "clientName").map((name) => normalize(name));
  const compactNames = nameVariants
    .map((name) => name.replace(/[^\p{L}\p{N}]+/gu, ""))
    .filter((name) => name.length >= 5);

  const groups = new Map();
  policies.forEach((policy) => {
    if (excludedIds.has(policy.id)) return;
    const name = String(policy.clientName ?? "").trim();
    if (!name) return;
    const key = `${normalize(name)}|${getClientProfileIdentityKey(String(policy.identityNumber ?? "").trim())}`;
    const group = groups.get(key);
    if (group) group.policies.push(policy);
    else groups.set(key, { name, policies: [policy] });
  });

  return [...groups.values()].map((group) => {
    const candidateIdentities = getClientProfileMergeIdentityTypeSets(group.policies);
    const sharedPesel = [...candidateIdentities.PESEL].some((key) => profileIdentities.PESEL.has(key));
    if (!sharedPesel && candidateIdentities.PESEL.size > 0 && profileIdentities.PESEL.size > 0) return null;

    const reasons = [];
    let score = 0;
    if (sharedPesel) {
      score += 100;
      reasons.push("ten sam PESEL");
    }

    
    
    
    
    const nipRegonPair = profileIdentities.PESEL.size === 0
      && candidateIdentities.PESEL.size === 0
      && ((profileIdentities.NIP.size > 0 && candidateIdentities.REGON.size > 0)
        || (profileIdentities.REGON.size > 0 && candidateIdentities.NIP.size > 0));
    if (nipRegonPair) {
      const groupName = normalize(group.name);
      const compactGroupName = groupName.replace(/[^\p{L}\p{N}]+/gu, "");
      const exactName = nameVariants.includes(groupName);
      const similarName = compactGroupName.length >= 5
        && compactNames.some((name) => name.includes(compactGroupName) || compactGroupName.includes(name));
      if (exactName || similarName) {
        score += exactName ? 90 : 80;
        reasons.push("NIP i REGON tej samej firmy");
      }
    }

    return reasons.length > 0 ? { group, score, reasons } : null;
  })
    .filter(Boolean)
    .sort((first, second) => second.score - first.score || second.group.policies.length - first.group.policies.length)
    .slice(0, 6);
}

function createClientProfileMergeRow({ anchorId, name, identity, policiesCount, reasons }) {
  const identityLabel = identity
    ? `${getIdentityNumberType(identity) || "Numer"} ${identity}`
    : "Bez numeru identyfikacyjnego";
  return `
    <div class="client-profile-merge-row">
      <div class="client-profile-merge-row-info">
        <strong>${escapeHtml(name)}</strong>
        <small>${escapeHtml(identityLabel)} · ${pluralizePolicies(policiesCount)}</small>
        <span class="client-profile-merge-reasons">${reasons.map((reason) => `<span>${escapeHtml(reason)}</span>`).join("")}</span>
      </div>
      <button type="button" data-client-profile-merge-confirm="${escapeHtml(anchorId)}">Połącz</button>
    </div>
  `;
}




function createClientProfileMergeSection(profilePolicies) {
  if (!CLIENT_PROFILE_MERGE_ENABLED || !clientProfileMergeOpen) return "";
  const suggestions = getClientProfileMergeSuggestions(profilePolicies);
  const profileIds = new Set(profilePolicies.map((policy) => policy.id));
  const searchPolicy = clientProfileMergeSearchPolicyId
    ? policies.find((policy) => policy.id === clientProfileMergeSearchPolicyId)
    : null;
  const searchRow = searchPolicy && !profileIds.has(searchPolicy.id)
    ? createClientProfileMergeRow({
        anchorId: searchPolicy.id,
        name: String(searchPolicy.clientName ?? "").trim() || "Klient bez nazwy",
        identity: String(searchPolicy.identityNumber ?? "").trim(),
        policiesCount: getClientProfilePolicies(searchPolicy).filter((policy) => !profileIds.has(policy.id)).length,
        reasons: ["wynik wyszukiwania"],
      })
    : "";
  const suggestionRows = suggestions
    .filter((item) => item.group.policies[0].id !== searchPolicy?.id)
    .map((item) => createClientProfileMergeRow({
      anchorId: item.group.policies[0].id,
      name: item.group.name,
      identity: pickClientProfileValue(item.group.policies, "identityNumber"),
      policiesCount: item.group.policies.length,
      reasons: item.reasons,
    })).join("");
  return `
    <section class="client-profile-section client-profile-merge-section" aria-labelledby="clientProfileMergeTitle">
      <div class="client-profile-section-heading">
        <div><span>Porządkowanie bazy</span><h3 id="clientProfileMergeTitle">Połącz konta klienta</h3></div>
        <button type="button" class="client-profile-merge-toggle" data-client-profile-merge-toggle>Zwiń</button>
      </div>
      <p class="client-profile-merge-hint">Jeśli ten sam klient występuje w bazie podwójnie (np. raz z NIP-em, raz z REGON-em), wybierz drugie konto poniżej. Wszystkie jego polisy dostaną wspólną nazwę i numery, więc trafią na jedną kartę.</p>
      <form class="client-profile-merge-search" data-client-profile-merge-search>
        <input type="search" name="mergeQuery" autocomplete="off" placeholder="Wyszukaj konto po nazwie, PESEL-u/NIP-ie, numerze polisy lub rejestracji" />
        <button class="settings-secondary-button" type="submit">Szukaj</button>
      </form>
      ${searchRow}
      ${suggestionRows ? `<div class="client-profile-merge-list">${suggestionRows}</div>` : ""}
      ${!searchRow && !suggestionRows ? `<p class="client-profile-empty">Nie znaleziono podobnych kont. Wyszukaj konto powyżej, aby połączyć je ręcznie.</p>` : ""}
    </section>
  `;
}

function getClientProfileMergeIdentityPlan(profilePolicies, targetPolicies) {
  const candidates = [];
  const pushIdentity = (value) => {
    const trimmed = String(value ?? "").trim();
    if (!trimmed) return;
    const key = getClientProfileIdentityKey(trimmed);
    if (!key || candidates.some((item) => item.key === key)) return;
    candidates.push({ key, value: trimmed });
  };
  pushIdentity(pickClientProfileValue(profilePolicies, "identityNumber"));
  pushIdentity(pickClientProfileValue(profilePolicies, "secondaryIdentityNumber"));
  pushIdentity(pickClientProfileValue(targetPolicies, "identityNumber"));
  pushIdentity(pickClientProfileValue(targetPolicies, "secondaryIdentityNumber"));
  [...profilePolicies, ...targetPolicies].flatMap(getClientProfileIdentityValues).forEach(pushIdentity);
  return {
    identityNumber: candidates[0]?.value || "",
    secondaryIdentityNumber: candidates[1]?.value || "",
    droppedIdentities: candidates.slice(2).map((item) => item.value),
  };
}

function buildClientProfileMergeAccountSummary(policiesList) {
  const name = pickClientProfileValue(policiesList, "clientName") || "Klient bez nazwy";
  const identity = pickClientProfileValue(policiesList, "identityNumber");
  const contactParts = [
    getClientProfilePhone(policiesList),
    getClientProfileEmail(policiesList),
    pickClientProfileValue(policiesList, "clientAddress"),
  ].filter(Boolean);
  return {
    name,
    identityLabel: identity ? `${getIdentityNumberType(identity) || "Numer"} ${identity}` : "Bez numeru",
    policiesLabel: pluralizePolicies(policiesList.length),
    contactLabel: contactParts.join(" · ") || "Brak danych kontaktowych",
  };
}





function requestClientProfileMergePrimaryChoice({ profileSummary, targetSummary, warningText }) {
  const dialog = elements.clientProfileMergePrimaryDialog;
  if (
    !dialog?.showModal
    || !elements.clientProfileMergePrimaryOptions
    || !elements.clientProfileMergePrimaryCancel
  ) {
    const fallbackMessage = [
      `Połączyć konto „${targetSummary.name}” (${targetSummary.policiesLabel}) z kontem „${profileSummary.name}” (${profileSummary.policiesLabel})?`,
      `Wszystkie polisy będą podpisane danymi karty „${profileSummary.name}”.`,
      warningText,
    ].filter(Boolean).join("\n\n");
    return Promise.resolve(
      typeof globalThis.confirm !== "function" || globalThis.confirm(fallbackMessage)
        ? "profile"
        : null,
    );
  }
  if (elements.clientProfileMergePrimaryCopy) {
    elements.clientProfileMergePrimaryCopy.textContent = [
      "Wybrana karta ustala wspólną nazwę, numery, kontakt, adres i nazwisko rodowe - braki uzupełnią się z drugiej karty. Wszystkie polisy obu kont trafią na jedną kartę.",
      warningText,
    ].filter(Boolean).join(" ");
  }
  const createOption = (side, summary) => {
    const option = document.createElement("button");
    option.type = "button";
    option.className = "merge-primary-option";
    option.dataset.mergePrimarySide = side;
    const nameElement = document.createElement("strong");
    nameElement.textContent = summary.name;
    const detailElement = document.createElement("small");
    detailElement.textContent = `${summary.identityLabel} · ${summary.policiesLabel}`;
    const contactElement = document.createElement("span");
    contactElement.textContent = summary.contactLabel;
    option.append(nameElement, detailElement, contactElement);
    return option;
  };
  elements.clientProfileMergePrimaryOptions.replaceChildren(
    createOption("profile", profileSummary),
    createOption("target", targetSummary),
  );
  return new Promise((resolve) => {
    const finish = (side) => {
      elements.clientProfileMergePrimaryOptions.removeEventListener("click", onOptionClick);
      elements.clientProfileMergePrimaryCancel.removeEventListener("click", onCancel);
      dialog.removeEventListener("cancel", onDialogCancel);
      if (dialog.open) dialog.close();
      resolve(side);
    };
    const onOptionClick = (event) => {
      const option = event.target.closest("[data-merge-primary-side]");
      if (option) finish(option.dataset.mergePrimarySide);
    };
    const onCancel = () => finish(null);
    const onDialogCancel = (event) => {
      event.preventDefault();
      finish(null);
    };
    elements.clientProfileMergePrimaryOptions.addEventListener("click", onOptionClick);
    elements.clientProfileMergePrimaryCancel.addEventListener("click", onCancel);
    dialog.addEventListener("cancel", onDialogCancel);
    dialog.showModal();
  });
}

async function mergeClientProfiles(targetPolicyId) {
  if (!CLIENT_PROFILE_MERGE_ENABLED) throw createClientProfileMergeDisabledError();
  if (clientProfileSaving || !clientProfilePolicyId) return;
  const profilePolicies = getClientProfileCurrentPolicies();
  const targetAnchorPolicy = policies.find((policy) => policy.id === targetPolicyId);
  if (profilePolicies.length === 0 || !targetAnchorPolicy) {
    showToast("Nie znaleziono konta do połączenia", "error");
    return;
  }
  const profileIds = new Set(profilePolicies.map((policy) => policy.id));
  const targetPolicies = getClientProfilePolicies(targetAnchorPolicy)
    .filter((policy) => !profileIds.has(policy.id));
  if (targetPolicies.length === 0) {
    showToast("Te konta są już połączone", "warning");
    return;
  }
  
  
  const profileHasPesel = getClientProfileMergeIdentityTypeSets(profilePolicies).PESEL.size > 0;
  const targetHasPesel = getClientProfileMergeIdentityTypeSets(targetPolicies).PESEL.size > 0;
  if (profileHasPesel !== targetHasPesel) {
    showToast("To wygląda na osobę i jej firmę. Zamiast łączyć karty, użyj przycisku „Powiąż konto” - polisy zostaną nietknięte.", "error");
    return;
  }

  const profileSummary = buildClientProfileMergeAccountSummary(profilePolicies);
  const targetSummary = buildClientProfileMergeAccountSummary(targetPolicies);
  const droppedCount = getClientProfileMergeIdentityPlan(profilePolicies, targetPolicies)
    .droppedIdentities.length;
  const warningText = droppedCount > 0
    ? `Uwaga: ${droppedCount === 1 ? "jeden numer nie zmieści się" : `${droppedCount} numery nie zmieszczą się`} w polach karty i zostanie zastąpiony wspólnymi.`
    : "";
  const primarySide = await requestClientProfileMergePrimaryChoice({
    profileSummary,
    targetSummary,
    warningText,
  });
  if (!primarySide) return;

  const primaryPolicies = primarySide === "target" ? targetPolicies : profilePolicies;
  const secondaryPolicies = primarySide === "target" ? profilePolicies : targetPolicies;
  const clientName = pickClientProfileValue(primaryPolicies, "clientName")
    || pickClientProfileValue(secondaryPolicies, "clientName")
    || "Klient bez nazwy";
  const identityPlan = getClientProfileMergeIdentityPlan(primaryPolicies, secondaryPolicies);
  const clientAddress = pickClientProfileValue(primaryPolicies, "clientAddress")
    || pickClientProfileValue(secondaryPolicies, "clientAddress");
  const nextValues = {
    clientName,
    identityNumber: identityPlan.identityNumber,
    secondaryIdentityNumber: identityPlan.secondaryIdentityNumber,
    clientMaidenName: pickClientProfileValue(primaryPolicies, "clientMaidenName")
      || pickClientProfileValue(secondaryPolicies, "clientMaidenName"),
    clientPhone: getClientProfilePhone(primaryPolicies) || getClientProfilePhone(secondaryPolicies),
    clientEmail: getClientProfileEmail(primaryPolicies) || getClientProfileEmail(secondaryPolicies),
    clientAddress,
    clientPostalCode: pickClientProfileValue(primaryPolicies, "clientPostalCode")
      || pickClientProfileValue(secondaryPolicies, "clientPostalCode")
      || extractClientPostalCode(clientAddress),
  };

  clientProfileMergeOpen = false;
  clientProfileMergeSearchPolicyId = null;
  const policyIds = [
    ...profilePolicies.map((policy) => policy.id),
    ...targetPolicies.map((policy) => policy.id),
  ];
  await persistClientProfileClientValues({
    policyIds,
    nextValues,
    statusText: "Konta klienta połączone",
    successText: `Połączono konta klienta - ${pluralizePolicies(policyIds.length)} na jednej karcie`,
  });
}

function renderClientProfileSearchOptions() {
  elements.clientProfileOptions.innerHTML = getClientProfileSearchOptions().map((option) => `
    <option value="${escapeHtml(option.name)}" label="${escapeHtml(option.identity || "Brak numeru identyfikacyjnego")}"></option>
  `).join("");
}




function getClientAccountClusters() {
  const items = [];
  policies.forEach((policy) => {
    const name = String(policy.clientName ?? "").trim();
    if (!name) return;
    items.push({ policy, name, nameKey: normalize(name) });
  });
  const parents = items.map((_, index) => index);
  const findRoot = (index) => {
    let root = index;
    while (parents[root] !== root) root = parents[root];
    while (parents[index] !== root) {
      const next = parents[index];
      parents[index] = root;
      index = next;
    }
    return root;
  };
  const union = (firstIndex, secondIndex) => {
    const firstRoot = findRoot(firstIndex);
    const secondRoot = findRoot(secondIndex);
    if (firstRoot !== secondRoot) parents[secondRoot] = firstRoot;
  };

  const identityAnchors = new Map();
  items.forEach((item, index) => {
    getClientProfileIdentityValues(item.policy).forEach((value) => {
      const key = getClientProfileIdentityKey(value);
      if (!key) return;
      if (identityAnchors.has(key)) union(identityAnchors.get(key), index);
      else identityAnchors.set(key, index);
    });
  });

  
  
  const nameGroups = new Map();
  items.forEach((item, index) => {
    if (!nameGroups.has(item.nameKey)) nameGroups.set(item.nameKey, []);
    nameGroups.get(item.nameKey).push(index);
  });
  nameGroups.forEach((indexes) => {
    const primaryKeysByType = new Map();
    let hasSameTypeConflict = false;
    indexes.forEach((index) => {
      const primary = String(items[index].policy.identityNumber ?? "").trim();
      const type = getIdentityNumberType(primary);
      if (!primary || !type) return;
      const key = getClientProfileIdentityKey(primary);
      const existingKey = primaryKeysByType.get(type);
      if (existingKey && existingKey !== key) hasSameTypeConflict = true;
      else primaryKeysByType.set(type, key);
    });
    if (hasSameTypeConflict) return;
    indexes.slice(1).forEach((index) => union(indexes[0], index));
  });

  const clusters = new Map();
  items.forEach((item, index) => {
    const root = findRoot(index);
    if (!clusters.has(root)) {
      clusters.set(root, {
        policies: [],
        names: new Map(),
        identityTypeSets: { PESEL: new Set(), NIP: new Set(), REGON: new Set() },
      });
    }
    const cluster = clusters.get(root);
    cluster.policies.push(item.policy);
    if (!cluster.names.has(item.nameKey)) cluster.names.set(item.nameKey, item.name);
    getClientProfileIdentityValues(item.policy).forEach((value) => {
      const type = getIdentityNumberType(value);
      if (type) cluster.identityTypeSets[type].add(getClientProfileIdentityKey(value));
    });
  });
  return [...clusters.values()];
}

function getClientAccountClusterCompanyKeys(cluster) {
  return [...cluster.identityTypeSets.NIP, ...cluster.identityTypeSets.REGON];
}

function clusterIsPersonAccount(cluster) {
  return cluster.identityTypeSets.PESEL.size > 0;
}

function clusterIsCompanyAccount(cluster) {
  return cluster.identityTypeSets.PESEL.size === 0
    && getClientAccountClusterCompanyKeys(cluster).length > 0;
}




function clientAccountLinkNamesMatch(personName, companyName) {
  const personTokens = new Set(normalizeClientNameTokens(personName));
  const companyTokens = new Set(normalizeClientNameTokens(companyName));
  if (personTokens.size < 2 || companyTokens.size <= personTokens.size) return false;
  return [...personTokens].every((token) => companyTokens.has(token));
}

function areClientAccountsLinked(personKeys, companyKeys) {
  const personKeySet = new Set(personKeys);
  const companyKeySet = new Set(companyKeys);
  return clientAccountLinks.some((link) => (
    link.personKeys.some((key) => personKeySet.has(key))
    && link.companyKeys.some((key) => companyKeySet.has(key))
  ));
}

function getClientProfileLinkedAccounts(profilePolicies) {
  const identitySets = getClientProfileMergeIdentityTypeSets(profilePolicies);
  const profileIds = new Set(profilePolicies.map((policy) => policy.id));
  const linkedAccounts = [];
  clientAccountLinks.forEach((link) => {
    const matchesPerson = link.personKeys.some((key) => identitySets.PESEL.has(key));
    const matchesCompany = !matchesPerson && link.companyKeys.some((key) => (
      identitySets.NIP.has(key) || identitySets.REGON.has(key)
    ));
    if (!matchesPerson && !matchesCompany) return;
    const otherKeys = matchesPerson ? link.companyKeys : link.personKeys;
    const otherKeySet = new Set(otherKeys);
    const anchorPolicy = policies.find((policy) => (
      !profileIds.has(policy.id)
      && getClientProfileIdentityValues(policy).some((value) => otherKeySet.has(getClientProfileIdentityKey(value)))
    ));
    const linkedPolicies = anchorPolicy
      ? getClientProfilePolicies(anchorPolicy).filter((policy) => !profileIds.has(policy.id))
      : [];
    const storedName = matchesPerson ? link.companyName : link.personName;
    linkedAccounts.push({
      pairKey: getClientAccountLinkPairKey(link),
      linkedSide: matchesPerson ? "company" : "person",
      name: pickClientProfileValue(linkedPolicies, "clientName") || storedName || "Klient bez nazwy",
      identities: linkedPolicies.length
        ? [...new Map(
          linkedPolicies.flatMap(getClientProfileIdentityValues)
            .map((value) => [getClientProfileIdentityKey(value), value]),
        ).values()]
        : otherKeys,
      policiesCount: linkedPolicies.length,
      anchorPolicyId: anchorPolicy?.id || "",
    });
  });
  return linkedAccounts;
}

function getClientProfileLinkSuggestions(profilePolicies) {
  const profileIds = new Set(profilePolicies.map((policy) => policy.id));
  const identitySets = getClientProfileMergeIdentityTypeSets(profilePolicies);
  const profileIsPerson = identitySets.PESEL.size > 0;
  const profileCompanyKeys = [...identitySets.NIP, ...identitySets.REGON];
  if (!profileIsPerson && profileCompanyKeys.length === 0) return [];
  const profileNames = getClientProfileDistinctValues(profilePolicies, "clientName");
  const suggestions = [];
  getClientAccountClusters().forEach((cluster) => {
    if (cluster.policies.some((policy) => profileIds.has(policy.id))) return;
    const clusterNames = [...cluster.names.values()];
    if (profileIsPerson) {
      if (!clusterIsCompanyAccount(cluster)) return;
      if (areClientAccountsLinked([...identitySets.PESEL], getClientAccountClusterCompanyKeys(cluster))) return;
      const nameMatches = profileNames.some((personName) => (
        clusterNames.some((companyName) => clientAccountLinkNamesMatch(personName, companyName))
      ));
      if (!nameMatches) return;
    } else {
      if (!clusterIsPersonAccount(cluster)) return;
      if (areClientAccountsLinked([...cluster.identityTypeSets.PESEL], profileCompanyKeys)) return;
      const nameMatches = clusterNames.some((personName) => (
        profileNames.some((companyName) => clientAccountLinkNamesMatch(personName, companyName))
      ));
      if (!nameMatches) return;
    }
    suggestions.push({
      cluster,
      name: [...cluster.names.values()][0],
      anchorId: cluster.policies[0].id,
    });
  });
  return suggestions
    .sort((first, second) => compareAlphabetically(first.name, second.name))
    .slice(0, 6);
}




function getClientAccountLinkProposals() {
  const clusters = getClientAccountClusters();
  const personClusters = clusters.filter(clusterIsPersonAccount);
  const companyClusters = clusters.filter(clusterIsCompanyAccount);
  if (personClusters.length === 0 || companyClusters.length === 0) return [];
  const proposals = [];
  companyClusters.forEach((companyCluster) => {
    const companyKeys = getClientAccountClusterCompanyKeys(companyCluster);
    const companyNames = [...companyCluster.names.values()];
    const matchingPersons = personClusters.filter((personCluster) => (
      [...personCluster.names.values()].some((personName) => (
        companyNames.some((companyName) => clientAccountLinkNamesMatch(personName, companyName))
      ))
    ));
    if (matchingPersons.length !== 1) return;
    const personCluster = matchingPersons[0];
    const personKeys = [...personCluster.identityTypeSets.PESEL].sort();
    if (areClientAccountsLinked(personKeys, companyKeys)) return;
    proposals.push({
      personAnchorId: personCluster.policies[0].id,
      companyAnchorId: companyCluster.policies[0].id,
      personName: [...personCluster.names.values()][0],
      companyName: companyNames[0],
      personKeys,
      companyKeys: [...companyKeys].sort(),
      personPolicies: personCluster.policies,
      companyPolicies: companyCluster.policies,
    });
  });
  return proposals.sort((first, second) => compareAlphabetically(first.companyName, second.companyName));
}



function clientAccountSplitCompanySticksTogether(companyPolicies, peselKey) {
  const roots = companyPolicies.map((_, index) => index);
  const findRoot = (index) => {
    let root = index;
    while (roots[root] !== root) root = roots[root];
    while (roots[index] !== root) {
      const next = roots[index];
      roots[index] = root;
      index = next;
    }
    return root;
  };
  const anchorsByKey = new Map();
  companyPolicies.forEach((policy, index) => {
    getClientProfileIdentityValues(policy).forEach((value) => {
      const key = getClientProfileIdentityKey(value);
      if (!key || key === peselKey) return;
      if (anchorsByKey.has(key)) roots[findRoot(anchorsByKey.get(key))] = findRoot(index);
      else anchorsByKey.set(key, index);
    });
  });
  return companyPolicies.every((_, index) => findRoot(index) === findRoot(0));
}



function getClientNameTokensKey(value) {
  return [...normalizeClientNameTokens(value)].sort().join(" ");
}








function getClientAccountSplitProposals() {
  const proposals = [];
  getClientAccountClusters().forEach((cluster) => {
    if (cluster.identityTypeSets.PESEL.size !== 1) return;
    const companyKeys = getClientAccountClusterCompanyKeys(cluster);
    if (companyKeys.length === 0) return;
    const peselKey = [...cluster.identityTypeSets.PESEL][0];
    const companyKeySet = new Set(companyKeys);
    const companyPolicies = [];
    const personPolicies = [];
    const namedOnlyPolicies = [];
    cluster.policies.forEach((policy) => {
      const identityKeys = getClientProfileIdentityValues(policy).map(getClientProfileIdentityKey);
      if (identityKeys.some((key) => companyKeySet.has(key))) companyPolicies.push(policy);
      else if (identityKeys.includes(peselKey)) personPolicies.push(policy);
      else namedOnlyPolicies.push(policy);
    });
    if (companyPolicies.length === 0 || personPolicies.length === 0) return;
    const fusedPolicies = companyPolicies.filter((policy) => (
      getClientProfileIdentityValues(policy).some((value) => getClientProfileIdentityKey(value) === peselKey)
    ));
    if (fusedPolicies.length === 0) return;
    const personNameKeys = new Set(
      personPolicies.map((policy) => normalize(policy.clientName)).filter(Boolean),
    );
    if (personNameKeys.size !== 1) return;
    const personNameKey = [...personNameKeys][0];
    const personName = personPolicies
      .map((policy) => String(policy.clientName ?? "").trim())
      .find(Boolean) || "";
    
    
    const personNameTokensKey = getClientNameTokensKey(personName);
    const companyNameCandidates = companyPolicies.filter((policy) => {
      const nameKey = normalize(policy.clientName);
      return nameKey
        && nameKey !== personNameKey
        && getClientNameTokensKey(policy.clientName) !== personNameTokensKey;
    });
    if (companyNameCandidates.length === 0) return;
    const matchingNameCandidates = companyNameCandidates.filter((policy) => (
      clientAccountLinkNamesMatch(personName, String(policy.clientName ?? "").trim())
    ));
    if (matchingNameCandidates.length === 0) return;
    const freshestCompanyPolicy = matchingNameCandidates.reduce((best, policy) => (
      String(policy.validUntil ?? "") > String(best.validUntil ?? "") ? policy : best
    ));
    const companyName = String(freshestCompanyPolicy.clientName ?? "").trim();
    const companyNameKeys = new Set(
      companyNameCandidates.map((policy) => normalize(policy.clientName)),
    );
    
    
    const hasUnresolvedName = namedOnlyPolicies.some((policy) => {
      const nameKey = normalize(policy.clientName);
      if (nameKey === personNameKey) return false;
      if (getClientNameTokensKey(policy.clientName) === personNameTokensKey) return false;
      return !companyNameKeys.has(nameKey);
    });
    if (hasUnresolvedName) return;
    if (!clientAccountSplitCompanySticksTogether(companyPolicies, peselKey)) return;
    
    
    const renamePolicies = companyPolicies.filter((policy) => (
      getClientNameTokensKey(policy.clientName) === personNameTokensKey
    ));
    proposals.push({
      personAnchorId: personPolicies[0].id,
      companyAnchorId: freshestCompanyPolicy.id,
      personName,
      personNameTokensKey,
      companyName,
      peselKey,
      personKeys: [peselKey],
      companyKeys: [...companyKeys].sort(),
      fusedPolicyIds: fusedPolicies.map((policy) => policy.id),
      renamePolicyIds: renamePolicies.map((policy) => policy.id),
      personPoliciesCount: personPolicies.length
        + namedOnlyPolicies.filter((policy) => (
          normalize(policy.clientName) === personNameKey
          || getClientNameTokensKey(policy.clientName) === personNameTokensKey
        )).length,
      companyPoliciesCount: companyPolicies.length
        + namedOnlyPolicies.filter((policy) => companyNameKeys.has(normalize(policy.clientName))).length,
      companyInsurers: [...new Set(
        companyPolicies.map((policy) => String(policy.insurer ?? "").trim()).filter(Boolean),
      )],
    });
  });
  return proposals.sort((first, second) => compareAlphabetically(first.companyName, second.companyName));
}






function applyClientAccountSplitChanges(proposal, policiesList, mutationStates) {
  const changedAt = Date.now();
  const fusedIds = new Set(proposal.fusedPolicyIds);
  const renameIds = new Set(proposal.renamePolicyIds);
  let changedCount = 0;
  [...new Set([...proposal.fusedPolicyIds, ...proposal.renamePolicyIds])].forEach((policyId) => {
    const target = policiesList.find((policy) => policy.id === policyId);
    if (!target) return;
    const rollbackState = {
      policy: target,
      identityNumber: target.identityNumber,
      hasSecondaryIdentityNumber: Object.prototype.hasOwnProperty.call(target, "secondaryIdentityNumber"),
      secondaryIdentityNumber: target.secondaryIdentityNumber,
      clientName: target.clientName,
      hasUpdatedAt: Object.prototype.hasOwnProperty.call(target, "updatedAt"),
      updatedAt: target.updatedAt,
      importedPolicyTracking: captureImportedPolicyTrackingRollbackState(target),
    };
    let touched = false;
    if (fusedIds.has(policyId)) {
      const identityValues = getClientProfileIdentityValues(target);
      const keptValues = identityValues.filter((value) => getClientProfileIdentityKey(value) !== proposal.peselKey);
      if (keptValues.length > 0 && keptValues.length < identityValues.length) {
        markImportedPolicyFieldsManuallyEdited(target, { identityNumber: keptValues[0] });
        target.identityNumber = keptValues[0];
        target.secondaryIdentityNumber = keptValues[1] ?? "";
        touched = true;
      }
    }
    if (renameIds.has(policyId) && getClientNameTokensKey(target.clientName) === proposal.personNameTokensKey) {
      target.clientName = proposal.companyName;
      touched = true;
    }
    if (!touched) return;
    target.updatedAt = changedAt;
    if (!mutationStates.has(policyId)) mutationStates.set(policyId, rollbackState);
    changedCount += 1;
  });
  return changedCount;
}

function restoreClientAccountSplitMutationStates(mutationStates) {
  mutationStates.forEach((state) => {
    if (!policies.includes(state.policy)) return;
    state.policy.identityNumber = state.identityNumber;
    if (state.hasSecondaryIdentityNumber) state.policy.secondaryIdentityNumber = state.secondaryIdentityNumber;
    else delete state.policy.secondaryIdentityNumber;
    state.policy.clientName = state.clientName;
    restoreImportedPolicyTrackingRollbackState(state.policy, state.importedPolicyTracking);
    if (state.hasUpdatedAt) state.policy.updatedAt = state.updatedAt;
    else delete state.policy.updatedAt;
  });
}




function getEntryOrganizerNipFillCandidates() {
  return getClientAccountClusters()
    .filter((cluster) => (
      cluster.identityTypeSets.PESEL.size === 0
      && cluster.identityTypeSets.NIP.size === 0
      && cluster.identityTypeSets.REGON.size === 1
    ))
    .map((cluster) => ({
      regon: [...cluster.identityTypeSets.REGON][0],
      names: [...cluster.names.values()],
      policyIds: cluster.policies.map((policy) => policy.id),
    }))
    .sort((first, second) => compareAlphabetically(first.names[0] || "", second.names[0] || ""));
}





function shouldFillNipFromRegistry(candidateNames, registryResult) {
  if (registryResult?.znaleziono !== true) return false;
  const nipDigits = String(registryResult.nip ?? "").replace(/\D/g, "");
  if (getIdentityNumberType(nipDigits) !== "NIP") return false;
  const registryName = String(registryResult.nazwa ?? "").trim();
  if (!registryName) return false;
  return (Array.isArray(candidateNames) ? candidateNames : [])
    .some((name) => getClientNameRelationship(name, registryName) === "same");
}





function buildClientProfileIdentitySlots({ pesel, nip, regon, other, currentPrimary }) {
  const numbers = [
    { type: "PESEL", value: String(pesel ?? "").trim() },
    { type: "NIP", value: String(nip ?? "").trim() },
    { type: "REGON", value: String(regon ?? "").trim() },
    { type: "INNY", value: String(other ?? "").trim() },
  ].filter((entry) => entry.value);
  if (numbers.length > 2) return { error: "too-many" };
  const primaryValue = String(currentPrimary ?? "").trim();
  const currentPrimaryType = primaryValue ? (getIdentityNumberType(primaryValue) || "INNY") : "";
  const primary = numbers.find((entry) => entry.type === currentPrimaryType) || numbers[0] || null;
  const secondary = numbers.find((entry) => entry !== primary) || null;
  return {
    identityNumber: primary ? primary.value : "",
    secondaryIdentityNumber: secondary ? secondary.value : "",
  };
}

function createClientProfileLinkCandidateRow({ anchorId, name, identities, policiesCount, reason }) {
  const identityLabel = identities.map(formatClientProfileIdentityLabel).filter(Boolean).join(" · ")
    || "Brak numeru identyfikacyjnego";
  return `
    <div class="client-profile-link-row">
      <div class="client-profile-link-row-info">
        <strong>${escapeHtml(name)}</strong>
        <small>${escapeHtml(identityLabel)} · ${pluralizePolicies(policiesCount)}</small>
        <span class="client-profile-link-reasons"><span>${escapeHtml(reason)}</span></span>
      </div>
      <div class="client-profile-link-row-actions">
        <button type="button" data-client-profile-link-confirm="${escapeHtml(anchorId)}">Powiąż</button>
      </div>
    </div>
  `;
}

function createClientProfileLinkedAccountRow(entry) {
  const kicker = entry.linkedSide === "company" ? "Działalność klienta" : "Właściciel firmy";
  const identityLabel = entry.identities.map(formatClientProfileIdentityLabel).filter(Boolean).join(" · ")
    || "Brak numeru identyfikacyjnego";
  const detail = entry.policiesCount > 0
    ? `${identityLabel} · ${pluralizePolicies(entry.policiesCount)}`
    : `${identityLabel} · brak polis w bazie`;
  return `
    <div class="client-profile-link-row">
      <div class="client-profile-link-row-info">
        <small>${escapeHtml(kicker)}</small>
        <strong>${escapeHtml(entry.name)}</strong>
        <span>${escapeHtml(detail)}</span>
      </div>
      <div class="client-profile-link-row-actions">
        ${entry.anchorPolicyId ? `<button type="button" class="settings-secondary-button" data-client-profile-link-open="${escapeHtml(entry.anchorPolicyId)}">Otwórz kartę</button>` : ""}
        <button type="button" class="settings-secondary-button" data-client-profile-link-remove="${escapeHtml(entry.pairKey)}">Rozłącz</button>
      </div>
    </div>
  `;
}

function createClientProfileLinkedAccountsSection(profilePolicies) {
  const linkedAccounts = getClientProfileLinkedAccounts(profilePolicies);
  const suggestions = getClientProfileLinkSuggestions(profilePolicies);
  const profileIds = new Set(profilePolicies.map((policy) => policy.id));
  const toggleLabel = clientProfileLinkPanelOpen
    ? "Zwiń"
    : suggestions.length ? `Powiąż konto (${suggestions.length})` : "Powiąż konto";
  const linkedRows = linkedAccounts.map(createClientProfileLinkedAccountRow).join("");
  let panel = "";
  if (clientProfileLinkPanelOpen) {
    const searchPolicy = clientProfileLinkSearchPolicyId
      ? policies.find((policy) => policy.id === clientProfileLinkSearchPolicyId)
      : null;
    const searchRow = searchPolicy && !profileIds.has(searchPolicy.id)
      ? createClientProfileLinkCandidateRow({
        anchorId: searchPolicy.id,
        name: String(searchPolicy.clientName ?? "").trim() || "Klient bez nazwy",
        identities: getClientProfileIdentityValues(searchPolicy),
        policiesCount: getClientProfilePolicies(searchPolicy).filter((policy) => !profileIds.has(policy.id)).length,
        reason: "wynik wyszukiwania",
      })
      : "";
    const suggestionRows = suggestions
      .filter((item) => item.anchorId !== searchPolicy?.id)
      .map((item) => createClientProfileLinkCandidateRow({
        anchorId: item.anchorId,
        name: item.name,
        identities: [
          ...item.cluster.identityTypeSets.PESEL,
          ...getClientAccountClusterCompanyKeys(item.cluster),
        ],
        policiesCount: item.cluster.policies.length,
        reason: "imię i nazwisko pasuje do nazwy firmy",
      })).join("");
    panel = `
      <p class="client-profile-link-hint">Powiązanie łączy osobę prywatną z jej działalnością. Obie karty pokazują nawzajem swoje numery (PESEL, NIP, REGON), a polisy zostają dokładnie tak, jak je wystawiono.</p>
      <form class="client-profile-link-search" data-client-profile-link-search>
        <input type="search" name="linkQuery" autocomplete="off" placeholder="Wyszukaj konto po nazwie, PESEL-u/NIP-ie, numerze polisy lub rejestracji" />
        <button class="settings-secondary-button" type="submit">Szukaj</button>
      </form>
      ${searchRow}
      ${suggestionRows ? `<div class="client-profile-link-list">${suggestionRows}</div>` : ""}
      ${!searchRow && !suggestionRows ? `<p class="client-profile-empty">Nie znaleziono pasującego konta. Wyszukaj je powyżej, aby powiązać ręcznie.</p>` : ""}
    `;
  }
  return `
    <section class="client-profile-section client-profile-link-section" aria-labelledby="clientProfileLinkTitle">
      <div class="client-profile-section-heading">
        <div><span>Osoba i firma</span><h3 id="clientProfileLinkTitle">Powiązane konta</h3></div>
        <button type="button" class="client-profile-link-toggle" data-client-profile-link-toggle aria-expanded="${clientProfileLinkPanelOpen ? "true" : "false"}">${escapeHtml(toggleLabel)}</button>
      </div>
      ${linkedRows
        ? `<div class="client-profile-link-list">${linkedRows}</div>`
        : `<p class="client-profile-empty">To konto nie ma jeszcze powiązania osoby z firmą.</p>`}
      ${panel}
    </section>
  `;
}

async function saveClientAccountLinksChange({ applyChange, rollbackChange, statusText, successText, reapplyFailureMessage }) {
  setClientProfileSaving(true);
  try {
    if (!(await ensureWritableDataFile({ deferFreshnessCheck: true }))) return false;
    applyChange();
    saveStatusPopupSuccessText = statusText;
    if (!(await persistPolicies({ reapplyAfterConflict: applyChange, reapplyFailureMessage }))) {
      rollbackChange();
      markPoliciesRolledBack();
      renderClientProfile();
      return false;
    }
    renderClientProfile();
    showToast(successText, "success");
    return true;
  } finally {
    if (elements.clientProfileDialog.open) setClientProfileSaving(false);
  }
}

async function linkClientProfileAccounts(targetPolicyId) {
  if (clientProfileSaving || !clientProfilePolicyId) return;
  const profilePolicies = getClientProfileCurrentPolicies();
  const targetAnchorPolicy = policies.find((policy) => policy.id === targetPolicyId);
  if (profilePolicies.length === 0 || !targetAnchorPolicy) {
    showToast("Nie znaleziono konta do powiązania", "error");
    return;
  }
  const profileIds = new Set(profilePolicies.map((policy) => policy.id));
  const targetPolicies = getClientProfilePolicies(targetAnchorPolicy)
    .filter((policy) => !profileIds.has(policy.id));
  if (targetPolicies.length === 0) {
    showToast("To ta sama karta klienta - nie ma czego powiązać", "warning");
    return;
  }
  const profileSets = getClientProfileMergeIdentityTypeSets(profilePolicies);
  const targetSets = getClientProfileMergeIdentityTypeSets(targetPolicies);
  const profileHasPesel = profileSets.PESEL.size > 0;
  const targetHasPesel = targetSets.PESEL.size > 0;
  if (profileHasPesel && targetHasPesel) {
    showToast("Oba konta mają PESEL, więc to dwie osoby prywatne. Takie konta łączy przycisk „Połącz konta”.", "error");
    return;
  }
  if (!profileHasPesel && !targetHasPesel) {
    showToast("Żadne z kont nie ma PESEL-u. Powiązanie łączy osobę prywatną z jej firmą - konta z parą NIP i REGON łączy przycisk „Połącz konta”.", "error");
    return;
  }
  const personPolicies = profileHasPesel ? profilePolicies : targetPolicies;
  const companyPolicies = profileHasPesel ? targetPolicies : profilePolicies;
  const personSets = profileHasPesel ? profileSets : targetSets;
  const companySets = profileHasPesel ? targetSets : profileSets;
  const personKeys = [...personSets.PESEL].sort();
  const companyKeys = [...companySets.NIP, ...companySets.REGON].sort();
  if (companyKeys.length === 0) {
    showToast("Konto firmy nie ma NIP-u ani REGON-u. Uzupełnij numer, aby powiązać konta.", "error");
    return;
  }
  if (areClientAccountsLinked(personKeys, companyKeys)) {
    showToast("Te konta są już powiązane", "warning");
    return;
  }
  const personName = pickClientProfileValue(personPolicies, "clientName") || "Klient bez nazwy";
  const companyName = pickClientProfileValue(companyPolicies, "clientName") || "Klient bez nazwy";
  const confirmText = [
    `Powiązać osobę „${personName}” z firmą „${companyName}”?`,
    "Polisy zostają bez zmian. Obie karty będą pokazywać nawzajem swoje numery, a okno „Policz składkę” podpowie PESEL, NIP i REGON razem.",
  ].join("\n\n");
  if (typeof globalThis.confirm === "function" && !globalThis.confirm(confirmText)) return;

  clientProfileLinkPanelOpen = false;
  clientProfileLinkSearchPolicyId = null;
  const newLink = {
    personKeys,
    companyKeys,
    personName,
    companyName,
    createdAt: new Date().toISOString(),
    source: "reczne",
  };
  let previousLinks = clientAccountLinks;
  const applyLink = () => {
    previousLinks = clientAccountLinks;
    clientAccountLinks = normalizeClientAccountLinks([...clientAccountLinks, newLink]);
    return true;
  };
  await saveClientAccountLinksChange({
    applyChange: applyLink,
    rollbackChange: () => { clientAccountLinks = previousLinks; },
    statusText: "Powiązanie kont zapisane",
    successText: "Konta powiązane - obie karty pokazują teraz wspólne numery",
    reapplyFailureMessage: "Nie udało się zapisać powiązania w nowszej bazie.",
  });
}

async function unlinkClientProfileAccounts(pairKey) {
  if (clientProfileSaving || !clientProfilePolicyId) return;
  const link = clientAccountLinks.find((entry) => getClientAccountLinkPairKey(entry) === pairKey);
  if (!link) {
    showToast("To powiązanie zostało już usunięte", "warning");
    renderClientProfile();
    return;
  }
  const personLabel = link.personName || "osoba prywatna";
  const companyLabel = link.companyName || "firma";
  const accepted = await requestDeleteConfirmation({
    title: "Rozłączyć konta?",
    message: `Karty „${personLabel}” i „${companyLabel}” przestaną pokazywać nawzajem swoje numery. Polisy pozostają bez zmian.`,
    confirmLabel: "Rozłącz",
  });
  if (!accepted) return;
  let previousLinks = clientAccountLinks;
  const applyUnlink = () => {
    previousLinks = clientAccountLinks;
    clientAccountLinks = clientAccountLinks.filter((entry) => getClientAccountLinkPairKey(entry) !== pairKey);
    return true;
  };
  await saveClientAccountLinksChange({
    applyChange: applyUnlink,
    rollbackChange: () => { clientAccountLinks = previousLinks; },
    statusText: "Powiązanie kont usunięte",
    successText: "Konta zostały rozłączone",
    reapplyFailureMessage: "Nie udało się rozłączyć kont w nowszej bazie.",
  });
}

function renderClientProfile() {
  if (!clientProfilePolicyId) return;
  const anchorPolicy = policies.find((policy) => policy.id === clientProfilePolicyId);
  if (!anchorPolicy) {
    closeClientProfileDialog(true);
    return;
  }
  const profilePolicies = getClientProfilePolicies(anchorPolicy);
  if (profilePolicies.length === 0) {
    closeClientProfileDialog(true);
    return;
  }

  const clientName = pickClientProfileValue(profilePolicies, "clientName") || "Klient bez nazwy";
  const identityNumber = pickClientProfileValue(profilePolicies, "identityNumber");
  const maidenName = pickClientProfileValue(profilePolicies, "clientMaidenName");
  const address = pickClientProfileValue(profilePolicies, "clientAddress");
  const postalCode = pickClientProfileValue(profilePolicies, "clientPostalCode") || extractClientPostalCode(address);
  const phone = getClientProfilePhone(profilePolicies);
  const email = getClientProfileEmail(profilePolicies);
  const identities = [...new Map(
    profilePolicies.flatMap(getClientProfileIdentityValues).map((value) => [getClientProfileIdentityKey(value), value]),
  ).values()];
  const addresses = getClientProfileDistinctValues(profilePolicies, "clientAddress");
  const peselDetails = getPeselDetails(
    identities.find((value) => getIdentityNumberType(value) === "PESEL") || "",
  );
  const activePolicies = profilePolicies.filter((policy) => !isPolicyExpired(policy));
  const historicalPolicies = profilePolicies.filter(isPolicyExpired);
  const vehicleGroups = getClientProfileVehicleGroups(profilePolicies);
  const vehicles = vehicleGroups.filter((group) => !group.removedFromProfile);
  const removedVehicles = vehicleGroups.filter((group) => group.removedFromProfile);
  const latestPolicy = profilePolicies[0];

  elements.clientProfileTitle.textContent = clientName;
  elements.clientProfileSubtitle.textContent = [
    identityNumber ? `${getIdentityNumberType(identityNumber) || "Identyfikator"} ${identityNumber}` : "",
    `${pluralizePolicies(profilePolicies.length)} łącznie`,
  ].filter(Boolean).join(" · ");
  elements.clientProfileSearch.value = "";
  renderClientProfileSearchOptions();

  const additionalAddresses = addresses.filter((value) => normalize(value) !== normalize(address));
  
  
  
  const ownIdentityByType = { PESEL: "", NIP: "", REGON: "" };
  let ownOtherIdentity = "";
  identities.forEach((value) => {
    const type = getIdentityNumberType(value);
    if (type && !ownIdentityByType[type]) ownIdentityByType[type] = value;
    else if (!type && !ownOtherIdentity) ownOtherIdentity = value;
  });
  const linkedAccountsForForm = getClientProfileLinkedAccounts(profilePolicies);
  const linkedIdentityByType = { PESEL: "", NIP: "", REGON: "" };
  let linkedPersonName = "";
  let linkedCompanyName = "";
  linkedAccountsForForm.forEach((entry) => {
    entry.identities.forEach((value) => {
      const type = getIdentityNumberType(value);
      if (type && !ownIdentityByType[type] && !linkedIdentityByType[type]) linkedIdentityByType[type] = value;
    });
    if (entry.linkedSide === "person" && !linkedPersonName) linkedPersonName = entry.name;
    if (entry.linkedSide === "company" && !linkedCompanyName) linkedCompanyName = entry.name;
  });
  const clientNameLabel = ownIdentityByType.PESEL
    ? "Imię i nazwisko"
    : (ownIdentityByType.NIP || ownIdentityByType.REGON)
      ? "Nazwa firmy"
      : "Imię i nazwisko / nazwa";
  
  
  
  const identityFieldDefs = [
    ["PESEL", "identityPesel"],
    ["NIP", "identityNip"],
    ["REGON", "identityRegon"],
  ];
  let identityFieldOrder = identityFieldDefs;
  if (linkedPersonName || linkedCompanyName) {
    const isLinkedIdentityField = ([identityType]) =>
      Boolean(!ownIdentityByType[identityType] && linkedIdentityByType[identityType]);
    const leadingFields = [
      identityFieldDefs.find(([identityType]) => ownIdentityByType[identityType])
        || identityFieldDefs.find((def) => !isLinkedIdentityField(def)),
      identityFieldDefs.find(isLinkedIdentityField),
    ].filter(Boolean);
    identityFieldOrder = [
      ...leadingFields,
      ...identityFieldDefs.filter((def) => !leadingFields.includes(def)),
    ];
  }
  const identityFields = identityFieldOrder.map(([identityType, fieldName]) => {
    if (!ownIdentityByType[identityType] && linkedIdentityByType[identityType]) {
      return `<label class="client-profile-field--linked"><span>${identityType} (konto powiązane)</span><input value="${escapeHtml(linkedIdentityByType[identityType])}" readonly title="Numer z powiązanego konta - edytuj go na tamtej karcie" /></label>`;
    }
    return `<label><span>${identityType}</span><input name="${fieldName}" inputmode="numeric" value="${escapeHtml(ownIdentityByType[identityType])}" /></label>`;
  });
  const otherIdentityFieldMarkup = ownOtherIdentity
    ? `<label><span>Inny numer</span><input name="identityOther" value="${escapeHtml(ownOtherIdentity)}" /></label>`
    : "";
  const linkedNameFieldMarkup = [
    linkedCompanyName
      ? `<label class="client-profile-field--wide client-profile-field--linked"><span>Nazwa firmy (konto powiązane)</span><input value="${escapeHtml(linkedCompanyName)}" readonly title="Nazwa z powiązanego konta - edytuj ją na tamtej karcie" /></label>`
      : "",
    linkedPersonName
      ? `<label class="client-profile-field--wide client-profile-field--linked"><span>Imię i nazwisko (konto powiązane)</span><input value="${escapeHtml(linkedPersonName)}" readonly title="Nazwa z powiązanego konta - edytuj ją na tamtej karcie" /></label>`
      : "",
  ].join("");
  const formShownIdentityKeys = new Set(
    [...Object.values(ownIdentityByType), ownOtherIdentity]
      .filter(Boolean)
      .map(getClientProfileIdentityKey),
  );
  const otherIdentityBadges = identities.filter((value) => (
    !formShownIdentityKeys.has(getClientProfileIdentityKey(value))
  ));
  const directPhone = phone ? phone.replace(/[^\d+]/g, "") : "";
  
  
  const mergeSuggestionsCount = CLIENT_PROFILE_MERGE_ENABLED && !clientProfileMergeOpen
    ? getClientProfileMergeSuggestions(profilePolicies).length
    : 0;
  const mergeToggleLabel = clientProfileMergeOpen
    ? "Zwiń"
    : mergeSuggestionsCount
      ? `Połącz konta (${mergeSuggestionsCount})`
      : "Połącz konta";
  const policyList = profilePolicies.map((policy) => {
    const status = formatClientProfilePolicyStatus(policy);
    const policyDetail = hasRegistrationNumber(policy)
      ? [policy.insurer, policy.registration].filter(Boolean).join(" · ")
      : policy.insurer || policy.registration || status.label;
    return `
      <button type="button" data-client-profile-jump-policy="${escapeHtml(policy.id)}">
        <span class="client-profile-status-dot client-profile-status-dot--${status.modifier}" aria-hidden="true"></span>
        <span><strong>${escapeHtml(policy.policyNumber || policy.insurer || "Polisa bez numeru")}</strong><small>${escapeHtml(policyDetail)}</small></span>
        <b>${escapeHtml(formatPremium(policy.premium))}</b>
      </button>
    `;
  }).join("");

  elements.clientProfileContent.innerHTML = `
    <div class="client-profile-layout">
      <div class="client-profile-main">
        <section class="client-profile-overview" aria-label="Podsumowanie klienta">
          <div><span>Aktywne polisy</span><strong>${activePolicies.length}</strong><small>${escapeHtml(getClientProfilePremiumTotal(activePolicies))} składek</small></div>
          <div><span>Historia polis</span><strong>${historicalPolicies.length}</strong><small>${escapeHtml(getClientProfilePremiumTotal(historicalPolicies))} historycznie</small></div>
          <div><span>Pojazdy</span><strong>${vehicles.length}</strong><small>${vehicles.length === 1 ? "zarejestrowany pojazd" : "zarejestrowane pojazdy"}</small></div>
          <div><span>Ostatnia polisa</span><strong>${escapeHtml(latestPolicy.insurer || "–")}</strong><small>do ${escapeHtml(formatDate(latestPolicy.validUntil))}</small></div>
        </section>

        <section class="client-profile-section client-profile-person-section" aria-labelledby="clientProfilePersonTitle">
          <div class="client-profile-section-heading">
            <div><span>Dane wspólne</span><h3 id="clientProfilePersonTitle">Klient i kontakt</h3></div>
            <small>Zapis zaktualizuje ${pluralizePolicies(profilePolicies.length)} tego klienta</small>
          </div>
          <form id="clientProfilePersonForm" class="client-profile-person-form">
            <div class="client-profile-edit-grid">
              <div class="client-profile-field--wide client-profile-name-field">
                <label><span>${clientNameLabel}</span><input name="clientName" required value="${escapeHtml(clientName)}" /></label>
                ${CLIENT_PROFILE_MERGE_ENABLED ? `<button type="button" class="client-profile-merge-toggle client-profile-merge-toggle--inline" data-client-profile-merge-toggle aria-expanded="${clientProfileMergeOpen ? "true" : "false"}">${mergeToggleLabel}</button>` : ""}
              </div>
              ${identityFields[0]}
              ${linkedNameFieldMarkup}
              ${identityFields[1]}
              ${identityFields[2]}
              ${otherIdentityFieldMarkup}
              <label><span>Nazwisko rodowe</span><input name="clientMaidenName" value="${escapeHtml(maidenName)}" placeholder="np. przy zmianie nazwiska po ślubie" /></label>
              <label><span>Telefon</span><input name="clientPhone" type="tel" value="${escapeHtml(phone)}" /></label>
              <label><span>E-mail</span><input name="clientEmail" type="email" value="${escapeHtml(email)}" /></label>
              <label><span>Kod pocztowy</span><input name="clientPostalCode" inputmode="numeric" value="${escapeHtml(postalCode)}" placeholder="00-000" /></label>
              <label class="client-profile-field--wide"><span>Adres klienta / firmy</span><input name="clientAddress" autocomplete="street-address" value="${escapeHtml(address)}" /></label>
            </div>
            ${(peselDetails || otherIdentityBadges.length || additionalAddresses.length) ? `
              <div class="client-profile-source-details">
                ${peselDetails ? `<span><b>Dane z PESEL:</b> ur. ${escapeHtml(peselDetails.birthDate)}, ${escapeHtml(peselDetails.sex)}</span>` : ""}
                ${otherIdentityBadges.map((value) => `<span><b>${escapeHtml(getIdentityNumberType(value) || "Identyfikator")}:</b> ${escapeHtml(value)}</span>`).join("")}
                ${additionalAddresses.map((value) => `<span><b>Inny adres z polisy:</b> ${escapeHtml(value)}</span>`).join("")}
              </div>
            ` : ""}
            <div class="client-profile-form-actions">
              <span>Zmiana nazwy przeniesie także foldery załączników polis.</span>
              <button class="settings-save-button" type="submit">Zapisz dane klienta</button>
            </div>
          </form>
        </section>

        ${createClientProfileMergeSection(profilePolicies)}

        ${createClientProfileLinkedAccountsSection(profilePolicies)}

        <section class="client-profile-section" aria-labelledby="clientProfileVehiclesTitle">
          <div class="client-profile-section-heading">
            <div><span>Majątek komunikacyjny</span><h3 id="clientProfileVehiclesTitle">Posiadane pojazdy</h3></div>
            <small>${vehicles.length ? `${vehicles.length} ${vehicles.length === 1 ? "pojazd" : "pojazdy"}` : "Brak pojazdów w polisach"}</small>
          </div>
          <div class="client-profile-vehicle-list">
            ${vehicles.length ? vehicles.map(createClientProfileVehicleCard).join("") : `<p class="client-profile-empty">W polisach klienta nie znaleziono numeru rejestracyjnego.</p>`}
          </div>
          ${removedVehicles.length
            ? `<button type="button" class="client-profile-vehicle-restore" data-client-profile-restore-vehicles>Przywróć usunięte pojazdy (${removedVehicles.length})</button>`
            : ""}
        </section>

        <section class="client-profile-section" aria-labelledby="clientProfileActiveTitle">
          <div class="client-profile-section-heading">
            <div><span>Bieżąca ochrona</span><h3 id="clientProfileActiveTitle">Aktywne składki i polisy</h3></div>
            <strong>${escapeHtml(getClientProfilePremiumTotal(activePolicies))}</strong>
          </div>
          <div class="client-profile-policy-list">
            ${activePolicies.length ? activePolicies.map(createClientProfilePolicyCard).join("") : `<p class="client-profile-empty">Brak aktywnych polis.</p>`}
          </div>
        </section>

        <section class="client-profile-section client-profile-section--history" aria-labelledby="clientProfileHistoryTitle">
          <div class="client-profile-section-heading">
            <div><span>Archiwum klienta</span><h3 id="clientProfileHistoryTitle">Historyczne składki i polisy</h3></div>
            <strong>${escapeHtml(getClientProfilePremiumTotal(historicalPolicies))}</strong>
          </div>
          <div class="client-profile-policy-list">
            ${historicalPolicies.length ? historicalPolicies.map(createClientProfilePolicyCard).join("") : `<p class="client-profile-empty">Brak polis historycznych.</p>`}
          </div>
        </section>
      </div>

      <aside class="client-profile-sidebar">
        <section class="client-profile-contact-card">
          <span>Dane kontaktowe</span>
          <strong>${escapeHtml(clientName)}</strong>
          ${phone ? `<a href="tel:${escapeHtml(directPhone)}">${escapeHtml(phone)}</a>` : `<small>Brak telefonu</small>`}
          ${email ? `<a href="mailto:${escapeHtml(email)}">${escapeHtml(email)}</a>` : `<small>Brak adresu e-mail</small>`}
          ${address ? `<p>${escapeHtml([postalCode, address].filter(Boolean).join(" · "))}</p>` : `<p>Brak adresu</p>`}
        </section>
        <section class="client-profile-all-policies">
          <div><span>Wszystkie polisy</span><strong>${profilePolicies.length}</strong></div>
          <nav aria-label="Lista polis klienta">${policyList}</nav>
        </section>
      </aside>
    </div>
  `;
  setClientProfileSaving(false);
}

function openClientProfileDialog(policyId) {
  const policy = policies.find((item) => item.id === policyId);
  if (!policy) return;
  clientProfilePolicyId = policy.id;
  clientProfileEditingPolicyId = null;
  clientProfileEditingVehicleKey = "";
  clientProfileVehicleHistoryHighlights.clear();
  clientProfileMergeOpen = false;
  clientProfileMergeSearchPolicyId = null;
  clientProfileLinkPanelOpen = false;
  clientProfileLinkSearchPolicyId = null;
  renderClientProfile();
  if (!elements.clientProfileDialog.open) elements.clientProfileDialog.showModal();
  requestAnimationFrame(() => elements.clientProfileSearch.focus());
}

function closeClientProfileDialog(force = false) {
  if (clientProfileSaving && !force) return;
  if (elements.clientProfileDialog.open) elements.clientProfileDialog.close();
  clientProfilePolicyId = null;
  clientProfileEditingPolicyId = null;
  clientProfileEditingVehicleKey = "";
  clientProfileVehicleHistoryBusyKey = "";
  clientProfileVehicleHistoryHighlights.clear();
  clientProfileMergeOpen = false;
  clientProfileMergeSearchPolicyId = null;
  clientProfileLinkPanelOpen = false;
  clientProfileLinkSearchPolicyId = null;
  clientProfileSaving = false;
  elements.clientProfileContent.innerHTML = "";
  elements.clientProfileSearch.value = "";
}

function setClientProfileSaving(isSaving) {
  clientProfileSaving = Boolean(isSaving);
  elements.clientProfileContent.setAttribute("aria-busy", String(clientProfileSaving));
  elements.clientProfileContent.querySelectorAll("button, input, textarea").forEach((control) => {
    control.disabled = clientProfileSaving;
  });
  elements.closeClientProfile.disabled = clientProfileSaving;
}

function captureClientProfilePolicySnapshots(policyIds) {
  const snapshots = new Map();
  policyIds.forEach((policyId) => {
    const policy = policies.find((item) => item.id === policyId);
    if (!policy) return;
    snapshots.set(policyId, {
      policy,
      value: { ...policy, attachments: policy.attachments },
    });
  });
  return snapshots;
}

function restoreClientProfilePolicySnapshots(snapshots) {
  snapshots.forEach(({ policy, value }) => {
    if (!policies.includes(policy)) return;
    Object.keys(policy).forEach((key) => {
      if (!Object.prototype.hasOwnProperty.call(value, key)) delete policy[key];
    });
    Object.assign(policy, value);
  });
}

async function saveClientProfilePerson(form) {
  if (clientProfileSaving || !clientProfilePolicyId) return;
  const profilePolicies = getClientProfileCurrentPolicies();
  if (profilePolicies.length === 0) return;
  const formData = new FormData(form);
  const rawPostalCode = String(formData.get("clientPostalCode") ?? "").trim();
  const rawEmail = String(formData.get("clientEmail") ?? "").trim();
  const rawPesel = String(formData.get("identityPesel") ?? "").trim();
  const rawNip = String(formData.get("identityNip") ?? "").trim();
  const rawRegon = String(formData.get("identityRegon") ?? "").trim();
  const peselDigits = rawPesel.replace(/\D/g, "");
  const nipDigits = rawNip.replace(/\D/g, "");
  const regonDigits = rawRegon.replace(/\D/g, "");
  if (rawPesel && peselDigits.length !== 11) {
    showToast("PESEL ma 11 cyfr - sprawdź wpisany numer", "error");
    form.elements.identityPesel?.focus();
    return;
  }
  if (rawNip && nipDigits.length !== 10) {
    showToast("NIP ma 10 cyfr - sprawdź wpisany numer", "error");
    form.elements.identityNip?.focus();
    return;
  }
  if (rawRegon && regonDigits.length !== 9) {
    showToast("REGON ma 9 cyfr - sprawdź wpisany numer", "error");
    form.elements.identityRegon?.focus();
    return;
  }
  const identitySlots = buildClientProfileIdentitySlots({
    pesel: peselDigits,
    nip: nipDigits,
    regon: regonDigits,
    other: String(formData.get("identityOther") ?? "").trim(),
    currentPrimary: pickClientProfileValue(profilePolicies, "identityNumber"),
  });
  if (identitySlots.error) {
    showToast("Na jednym koncie mieszczą się dwa numery. Numery firmy zapisz na jej koncie i użyj przycisku „Powiąż konto”.", "error");
    return;
  }
  const nextValues = {
    clientName: String(formData.get("clientName") ?? "").trim(),
    identityNumber: identitySlots.identityNumber,
    secondaryIdentityNumber: identitySlots.secondaryIdentityNumber,
    clientMaidenName: String(formData.get("clientMaidenName") ?? "").trim(),
    clientPhone: normalizeClientPhone(formData.get("clientPhone")),
    clientEmail: normalizeClientEmail(rawEmail),
    clientAddress: normalizeClientAddress(formData.get("clientAddress")),
    clientPostalCode: normalizeClientPostalCode(rawPostalCode),
  };
  if (!nextValues.clientName) {
    showToast("Wpisz imię i nazwisko albo nazwę klienta", "error");
    form.elements.clientName.focus();
    return;
  }
  if (rawEmail && !/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(nextValues.clientEmail)) {
    showToast("Sprawdź adres e-mail klienta", "error");
    form.elements.clientEmail.focus();
    return;
  }
  if (rawPostalCode && !nextValues.clientPostalCode) {
    showToast("Wpisz kod pocztowy w formacie 00-000", "error");
    form.elements.clientPostalCode.focus();
    return;
  }
  if (!nextValues.clientPostalCode) {
    nextValues.clientPostalCode = extractClientPostalCode(nextValues.clientAddress);
  }

  await persistClientProfileClientValues({
    policyIds: profilePolicies.map((policy) => policy.id),
    nextValues,
    statusText: "Dane klienta zapisane we wszystkich polisach",
    successText: `Dane klienta zapisano w ${pluralizePolicies(profilePolicies.length)}`,
  });
}

async function persistClientProfileClientValues({ policyIds, nextValues, statusText, successText }) {
  setClientProfileSaving(true);
  if (!(await ensureWritableDataFile({ deferFreshnessCheck: true }))) {
    setClientProfileSaving(false);
    return false;
  }

  const targetPolicies = policyIds
    .map((policyId) => policies.find((policy) => policy.id === policyId))
    .filter(Boolean);
  const relocations = new Map();
  const copiedAttachments = [];
  const sourceAttachments = [];
  const missingAttachments = [];
  const nameChangedPolicies = targetPolicies.filter((policy) => (
    normalize(policy.clientName) !== normalize(nextValues.clientName)
  ));
  if (nameChangedPolicies.some((policy) => normalizePolicyAttachments(policy.attachments).some(isExternalAttachment))) {
    showAppBusyOverlay("Przenoszenie folderów klienta…");
  }

  try {
    for (const policy of nameChangedPolicies) {
      const relocation = await prepareRelocatedPolicyAttachments(
        policy,
        nextValues.clientName,
        policy.policyNumber,
      );
      relocations.set(policy.id, relocation);
      copiedAttachments.push(...relocation.copiedAttachments);
      sourceAttachments.push(...relocation.sourceAttachments);
      missingAttachments.push(...relocation.missingAttachments);
    }

    let mutationSnapshots = new Map();
    const applyClientValues = () => {
      const currentPolicies = policyIds
        .map((policyId) => policies.find((policy) => policy.id === policyId))
        .filter(Boolean);
      if (currentPolicies.length === 0) return false;
      mutationSnapshots = captureClientProfilePolicySnapshots(currentPolicies.map((policy) => policy.id));
      currentPolicies.forEach((policy) => {
        markImportedPolicyFieldsManuallyEdited(policy, nextValues);
        Object.assign(policy, nextValues);
        const relocation = relocations.get(policy.id);
        if (relocation) {
          const desiredAttachments = normalizePolicyAttachments(relocation.nextAttachments);
          const desiredIds = new Set(desiredAttachments.map((attachment) => attachment.id));
          const concurrentAttachments = normalizePolicyAttachments(policy.attachments)
            .filter((attachment) => !desiredIds.has(attachment.id));
          policy.attachments = [...desiredAttachments, ...concurrentAttachments];
        }
        policy.updatedAt = Date.now();
      });
      return true;
    };

    if (!applyClientValues()) {
      showToast("Nie znaleziono polis tego klienta", "error");
      return false;
    }
    saveStatusPopupSuccessText = statusText;
    if (!(await persistPolicies({
      reapplyAfterConflict: applyClientValues,
      reapplyFailureMessage: "Polisy klienta zmieniły się w nowszej bazie. Dane nie zostały zapisane.",
    }))) {
      restoreClientProfilePolicySnapshots(mutationSnapshots);
      await deleteExternalAttachmentFiles(copiedAttachments);
      markPoliciesRolledBack();
      render();
      renderClientProfile();
      return false;
    }

    await deleteExternalAttachmentFiles(
      getUnsharedAttachmentsForDeletion(sourceAttachments),
    );
    render();
    renderClientProfile();
    showToast(
      missingAttachments.length
        ? `Dane zapisano, ale nie odnaleziono ${pluralizeAttachments(missingAttachments.length)} do przeniesienia`
        : successText,
      missingAttachments.length ? "warning" : "success",
    );
    return true;
  } catch (error) {
    await deleteExternalAttachmentFiles(copiedAttachments);
    showToast(error?.message || "Nie udało się zapisać danych klienta", "error");
    return false;
  } finally {
    hideAppBusyOverlay();
    if (elements.clientProfileDialog.open) setClientProfileSaving(false);
  }
}

async function saveClientProfileVehicle(form) {
  if (clientProfileSaving || !clientProfilePolicyId) return;
  const vehicleKey = form.dataset.clientProfileVehicleForm;
  const vehicleGroup = getClientProfileVehicleGroups(getClientProfileCurrentPolicies())
    .find((group) => group.key === vehicleKey);
  if (!vehicleGroup) {
    showToast("Nie znaleziono pojazdu w polisach klienta", "error");
    return;
  }
  const formData = new FormData(form);
  const nextValues = {
    vehicleMake: normalizeVehicleDetail(formData.get("vehicleMake")),
    vehicleModel: normalizeVehicleDetail(formData.get("vehicleModel")),
    vehicleType: normalizeVehicleDetail(formData.get("vehicleType")),
    productionYear: normalizeVehicleDetail(formData.get("productionYear")),
    vin: normalizeVehicleIdentifier(formData.get("vin")),
    firstRegistrationDate: normalizeFirstRegistrationDate(formData.get("firstRegistrationDate")),
    fuelType: normalizeVehicleDetail(formData.get("fuelType")),
    
    
    engineCapacity: normalizeVehicleDetail(mergeVehicleNumericEditValue("engineCapacity", formData.get("engineCapacity"), vehicleGroup.latest.engineCapacity)),
    enginePower: normalizeVehicleDetail(mergeVehicleNumericEditValue("enginePower", formData.get("enginePower"), vehicleGroup.latest.enginePower)),
    seats: normalizeVehicleDetail(formData.get("seats")),
    grossWeight: normalizeVehicleDetail(mergeVehicleNumericEditValue("grossWeight", formData.get("grossWeight"), vehicleGroup.latest.grossWeight)),
    mileage: normalizeVehicleDetail(mergeVehicleNumericEditValue("mileage", formData.get("mileage"), vehicleGroup.latest.mileage)),
    driverLicenseDate: normalizeDriverLicenseDate(formData.get("driverLicenseDate")),
  };
  const nextRegistration = normalizeRegistration(formData.get("registration"));
  if (!nextRegistration || getPolicyTypeIndex(nextRegistration) >= 0) {
    showToast("Wpisz numer rejestracyjny pojazdu, a nie rodzaj polisy", "error");
    form.elements.registration.focus();
    return;
  }
  if (String(formData.get("firstRegistrationDate") ?? "").trim() && !nextValues.firstRegistrationDate) {
    showToast("Sprawdź datę pierwszej rejestracji", "error");
    form.elements.firstRegistrationDate.focus();
    return;
  }
  if (String(formData.get("driverLicenseDate") ?? "").trim() && !nextValues.driverLicenseDate) {
    showToast("Wpisz rok lub datę uzyskania prawa jazdy", "error");
    form.elements.driverLicenseDate.focus();
    return;
  }

  setClientProfileSaving(true);
  if (!(await ensureWritableDataFile({ deferFreshnessCheck: true }))) {
    setClientProfileSaving(false);
    return;
  }
  const policyIds = vehicleGroup.policies.map((policy) => policy.id);
  let mutationSnapshots = new Map();
  const applyVehicleValues = () => {
    const currentPolicies = policyIds
      .map((policyId) => policies.find((policy) => policy.id === policyId))
      .filter(Boolean);
    if (currentPolicies.length === 0) return false;
    mutationSnapshots = captureClientProfilePolicySnapshots(currentPolicies.map((policy) => policy.id));
    currentPolicies.forEach((policy) => {
      markImportedPolicyFieldsManuallyEdited(policy, {
        ...nextValues,
        registration: nextRegistration,
      });
      Object.assign(policy, nextValues, { updatedAt: Date.now() });
      
      
      if (normalizeRegistration(policy.registration) !== nextRegistration) {
        policy.registration = nextRegistration;
        policy.registrationManuallyEdited = true;
      }
    });
    return true;
  };

  try {
    if (!applyVehicleValues()) return;
    saveStatusPopupSuccessText = "Dane pojazdu zapisane";
    if (!(await persistPolicies({
      reapplyAfterConflict: applyVehicleValues,
      reapplyFailureMessage: "Polisy pojazdu zmieniły się w nowszej bazie. Dane nie zostały zapisane.",
    }))) {
      restoreClientProfilePolicySnapshots(mutationSnapshots);
      markPoliciesRolledBack();
      render();
      renderClientProfile();
      return;
    }
    clientProfileEditingVehicleKey = "";
    render();
    renderClientProfile();
    showToast(`Dane pojazdu zapisano w ${pluralizePolicies(policyIds.length)}`);
  } catch (error) {
    restoreClientProfilePolicySnapshots(mutationSnapshots);
    markPoliciesRolledBack();
    render();
    renderClientProfile();
    showToast(error?.message || "Nie udało się zapisać danych pojazdu", "error");
  } finally {
    if (elements.clientProfileDialog.open) setClientProfileSaving(false);
  }
}

function describeClientProfileVehicle(vehicleGroup) {
  const policy = vehicleGroup.latest;
  const registration = String(policy.registration ?? "").trim();
  const vehicleName = [policy.vehicleMake, policy.vehicleModel].filter(Boolean).join(" ");
  return vehicleName ? `${registration} (${vehicleName})` : registration;
}



async function updateClientProfileVehiclePolicies({ policyIds, mutatePolicy, statusText, successText, failureText }) {
  setClientProfileSaving(true);
  if (!(await ensureWritableDataFile({ deferFreshnessCheck: true }))) {
    setClientProfileSaving(false);
    return false;
  }
  let mutationSnapshots = new Map();
  const applyVehicleFlags = () => {
    const currentPolicies = policyIds
      .map((policyId) => policies.find((policy) => policy.id === policyId))
      .filter(Boolean);
    if (currentPolicies.length === 0) return false;
    mutationSnapshots = captureClientProfilePolicySnapshots(currentPolicies.map((policy) => policy.id));
    currentPolicies.forEach((policy) => {
      mutatePolicy(policy);
      policy.updatedAt = Date.now();
    });
    return true;
  };
  try {
    if (!applyVehicleFlags()) return false;
    saveStatusPopupSuccessText = statusText;
    if (!(await persistPolicies({
      reapplyAfterConflict: applyVehicleFlags,
      reapplyFailureMessage: failureText,
    }))) {
      restoreClientProfilePolicySnapshots(mutationSnapshots);
      markPoliciesRolledBack();
      render();
      renderClientProfile();
      return false;
    }
    render();
    renderClientProfile();
    showToast(successText);
    return true;
  } catch (error) {
    restoreClientProfilePolicySnapshots(mutationSnapshots);
    markPoliciesRolledBack();
    render();
    renderClientProfile();
    showToast(error?.message || failureText, "error");
    return false;
  } finally {
    if (elements.clientProfileDialog.open) setClientProfileSaving(false);
  }
}

async function setClientProfileVehicleSold(vehicleKey, sold) {
  if (clientProfileSaving || !clientProfilePolicyId) return;
  const vehicleGroup = getClientProfileVehicleGroups(getClientProfileCurrentPolicies())
    .find((group) => group.key === vehicleKey);
  if (!vehicleGroup) {
    showToast("Nie znaleziono pojazdu w polisach klienta", "error");
    return;
  }
  const vehicleLabel = describeClientProfileVehicle(vehicleGroup);
  if (sold && typeof globalThis.confirm === "function" && !globalThis.confirm([
    `Oznaczyć pojazd ${vehicleLabel} jako sprzedany?`,
    `Polisy tego pojazdu (${pluralizePolicies(vehicleGroup.policies.length)}) dostaną oznaczenie „Pojazd sprzedany" i nie będą pojawiać się w polisach do odnowienia. Oznaczenie można cofnąć na karcie pojazdu.`,
  ].join("\n\n"))) return;
  const soldAt = Date.now();
  await updateClientProfileVehiclePolicies({
    policyIds: vehicleGroup.policies.map((policy) => policy.id),
    mutatePolicy: (policy) => {
      if (sold) {
        policy.vehicleSold = true;
        policy.vehicleSoldAt = soldAt;
      } else {
        delete policy.vehicleSold;
        delete policy.vehicleSoldAt;
      }
    },
    statusText: sold ? "Pojazd oznaczony jako sprzedany" : "Cofnięto oznaczenie sprzedaży pojazdu",
    successText: sold
      ? `Pojazd ${vehicleLabel} oznaczony jako sprzedany - bez podpowiedzi odnowień`
      : `Pojazd ${vehicleLabel} wrócił do odnowień`,
    failureText: "Polisy pojazdu zmieniły się w nowszej bazie. Oznaczenie nie zostało zapisane.",
  });
}

async function removeClientProfileVehicle(vehicleKey) {
  if (clientProfileSaving || !clientProfilePolicyId) return;
  const vehicleGroup = getClientProfileVehicleGroups(getClientProfileCurrentPolicies())
    .find((group) => group.key === vehicleKey);
  if (!vehicleGroup) {
    showToast("Nie znaleziono pojazdu w polisach klienta", "error");
    return;
  }
  const vehicleLabel = describeClientProfileVehicle(vehicleGroup);
  if (typeof globalThis.confirm === "function" && !globalThis.confirm([
    `Usunąć pojazd ${vehicleLabel} z karty klienta?`,
    `Pojazd zniknie z listy „Posiadane pojazdy", ale polisy, na których był ubezpieczony, pozostaną bez zmian. Usunięcie można cofnąć przyciskiem „Przywróć usunięte pojazdy".`,
  ].join("\n\n"))) return;
  await updateClientProfileVehiclePolicies({
    policyIds: vehicleGroup.policies.map((policy) => policy.id),
    mutatePolicy: (policy) => {
      policy.vehicleRemovedFromProfile = true;
    },
    statusText: "Pojazd usunięty z karty klienta",
    successText: `Pojazd ${vehicleLabel} usunięty z karty klienta - polisy pozostały bez zmian`,
    failureText: "Polisy pojazdu zmieniły się w nowszej bazie. Pojazd nie został usunięty z karty.",
  });
}

async function restoreClientProfileRemovedVehicles() {
  if (clientProfileSaving || !clientProfilePolicyId) return;
  const removedPolicies = getClientProfileCurrentPolicies()
    .filter((policy) => policy.vehicleRemovedFromProfile === true);
  if (removedPolicies.length === 0) return;
  await updateClientProfileVehiclePolicies({
    policyIds: removedPolicies.map((policy) => policy.id),
    mutatePolicy: (policy) => {
      delete policy.vehicleRemovedFromProfile;
    },
    statusText: "Pojazdy przywrócone na kartę klienta",
    successText: "Usunięte pojazdy wróciły na kartę klienta",
    failureText: "Polisy klienta zmieniły się w nowszej bazie. Pojazdy nie zostały przywrócone.",
  });
}




async function requestVehicleHistoryData(policy) {
  const response = await apiFetch("/api/historia-pojazdu", {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({
      registration: normalizeVehicleIdentifier(policy.registration),
      vin: normalizeVehicleIdentifier(policy.vin),
      firstRegistrationDate: normalizeFirstRegistrationDate(policy.firstRegistrationDate),
      pesel: String(policy.identityNumber ?? "").trim(),
    }),
  });
  const data = await response.json().catch(() => null);
  if (!response.ok) throw new Error(data?.error || "Nie udało się pobrać danych z HistoriaPojazdu.gov.");
  if (!data?.pojazd) throw new Error("Serwis HistoriaPojazdu.gov nie zwrócił danych pojazdu.");
  return data.pojazd;
}



function buildVehicleHistoryMissingMessage({ registration, vin, firstRegistrationDate }) {
  const missing = [
    !registration ? "numer rejestracyjny" : "",
    !vin ? "VIN" : "",
    !firstRegistrationDate ? "datę pierwszej rejestracji" : "",
  ].filter(Boolean);
  if (missing.length === 1) return `Uzupełnij zaznaczone pole pojazdu: ${missing[0]}`;
  return `Uzupełnij zaznaczone dane pojazdu: ${missing.slice(0, -1).join(", ")} i ${missing[missing.length - 1]}`;
}





function buildVehicleHistoryValues(policy, vehicleData) {
  const nextValues = {};
  const setValue = (fieldName, rawValue, { overwrite = false } = {}) => {
    const cleanValue = normalizeVehicleDetail(rawValue);
    if (!cleanValue) return;
    if (!overwrite && String(policy?.[fieldName] ?? "").trim()) return;
    if (String(policy?.[fieldName] ?? "").trim() === cleanValue) return;
    nextValues[fieldName] = cleanValue;
  };
  setValue("vehicleType", vehicleData.vehicleType, { overwrite: true });
  setValue("vehicleMake", vehicleData.make);
  setValue("vehicleModel", vehicleData.model);
  setValue("productionYear", vehicleData.yearOfManufacture);
  setValue("fuelType", vehicleData.fuelType);
  setValue("engineCapacity", vehicleData.engineCapacity ? `${vehicleData.engineCapacity} cm³` : "");
  setValue("enginePower", vehicleData.enginePower ? `${vehicleData.enginePower} kW` : "");
  setValue("seats", vehicleData.seats);
  setValue("grossWeight", vehicleData.grossWeight ? `${vehicleData.grossWeight} kg` : "");
  const mileageReading = vehicleData.mileage;
  if (Number.isFinite(mileageReading?.value) && mileageReading.value > 0) {
    const mileageText = `${Number(mileageReading.value).toLocaleString("pl-PL")} ${mileageReading.unit || "km"}`;
    const readingDate = mileageReading.date ? formatDate(mileageReading.date) : "";
    setValue("mileage", readingDate && readingDate !== "-" ? `${mileageText} (odczyt ${readingDate})` : mileageText, { overwrite: true });
  }
  return nextValues;
}

async function fetchClientProfileVehicleHistory(vehicleKey) {
  if (clientProfileSaving || !clientProfilePolicyId || clientProfileVehicleHistoryBusyKey) return;
  const vehicleGroup = getClientProfileVehicleGroups(getClientProfileCurrentPolicies())
    .find((group) => group.key === vehicleKey);
  if (!vehicleGroup) {
    showToast("Nie znaleziono pojazdu w polisach klienta", "error");
    return;
  }
  const policy = vehicleGroup.latest;
  const registration = normalizeVehicleIdentifier(policy.registration);
  const vin = normalizeVehicleIdentifier(policy.vin);
  const firstRegistrationDate = normalizeFirstRegistrationDate(policy.firstRegistrationDate);
  if (!registration || !vin || !firstRegistrationDate) {
    clientProfileVehicleHistoryHighlights.add(vehicleGroup.key);
    renderClientProfile();
    showToast(buildVehicleHistoryMissingMessage({ registration, vin, firstRegistrationDate }), "error");
    return;
  }
  clientProfileVehicleHistoryHighlights.delete(vehicleGroup.key);
  clientProfileVehicleHistoryBusyKey = vehicleGroup.key;
  renderClientProfile();
  let vehicleData = null;
  try {
    vehicleData = await requestVehicleHistoryData(policy);
  } catch (error) {
    clientProfileVehicleHistoryBusyKey = "";
    renderClientProfile();
    showToast(error?.message || "Nie udało się pobrać danych z HistoriaPojazdu.gov.", "error");
    return;
  }
  clientProfileVehicleHistoryBusyKey = "";
  const nextValues = buildVehicleHistoryValues(policy, vehicleData);
  if (Object.keys(nextValues).length === 0) {
    renderClientProfile();
    showToast("Dane pojazdu są już zgodne z HistoriaPojazdu.gov");
    return;
  }
  await updateClientProfileVehiclePolicies({
    policyIds: vehicleGroup.policies.map((item) => item.id),
    mutatePolicy: (item) => {
      Object.assign(item, nextValues);
    },
    statusText: "Dane pojazdu z HistoriaPojazdu.gov zapisane",
    successText: `Pojazd ${describeClientProfileVehicle(vehicleGroup)}: dane uzupełnione z HistoriaPojazdu.gov`,
    failureText: "Polisy pojazdu zmieniły się w nowszej bazie. Dane z HistoriaPojazdu.gov nie zostały zapisane.",
  });
}

async function saveClientProfilePolicy(form) {
  if (clientProfileSaving || !clientProfilePolicyId) return;
  const policyId = form.dataset.clientProfilePolicyForm;
  const existingPolicy = policies.find((policy) => policy.id === policyId);
  if (!existingPolicy) {
    showToast("Nie znaleziono edytowanej polisy", "error");
    return;
  }
  const formData = new FormData(form);
  const nextValues = {
    insurer: String(formData.get("insurer") ?? "").trim(),
    policyNumber: String(formData.get("policyNumber") ?? "").trim(),
    registration: normalizeRegistration(formData.get("registration")),
    issueDate: String(formData.get("issueDate") ?? "").trim(),
    validFrom: String(formData.get("validFrom") ?? "").trim(),
    validUntil: String(formData.get("validUntil") ?? "").trim(),
    premium: String(formData.get("premium") ?? "").trim(),
    riskSummary: String(formData.get("riskSummary") ?? "").trim().slice(0, 400),
    contact: String(formData.get("contact") ?? "").trim(),
    renewalStatus: String(formData.get("renewalStatus") ?? "").trim() || null,
  };
  const displayedValidFrom = formatDateForInput(getPolicyStartDate(existingPolicy));
  const validFromWasEdited = nextValues.validFrom !== displayedValidFrom;
  const renewalStatusWasEdited = nextValues.renewalStatus
    !== (existingPolicy.renewalStatus || null);
  const validUntilWasEdited = nextValues.validUntil
    !== String(existingPolicy.validUntil ?? "").trim();
  const registrationWasEdited = nextValues.registration
    !== normalizeRegistration(existingPolicy.registration);
  if (
    !validFromWasEdited
    && !isImportedPolicyFieldManuallyProtected(existingPolicy, "validFrom")
    && (validUntilWasEdited || registrationWasEdited)
  ) {
    nextValues.validFrom = getAutomaticallyCalculatedValidFrom({
      ...existingPolicy,
      ...nextValues,
    });
  }
  
  
  const undoBuyerTransfer = POLICY_BUYER_TRANSFER_FEATURE_ENABLED
    && formData.get("transferredToBuyer") !== null
    && String(formData.get("transferredToBuyer")) === ""
    && existingPolicy.transferredToBuyer === true;
  if (undoBuyerTransfer && !isValidPolicyBuyerSnapshot(existingPolicy.buyerSnapshot)) {
    showToast(
      "Nie można bezpiecznie cofnąć zbycia, ponieważ brakuje pełnej migawki nabywcy.",
      "warning",
    );
    return;
  }
  const expectedTransferUndoState = undoBuyerTransfer
    ? getPolicyBuyerTransferUndoPrecondition(existingPolicy)
    : "";
  if (nextValues.issueDate && !parseLocalDate(nextValues.issueDate)) {
    showToast("Sprawdź datę wystawienia polisy", "error");
    form.elements.issueDate.focus();
    return;
  }
  if (nextValues.validFrom && !parseLocalDate(nextValues.validFrom)) {
    showToast("Sprawdź datę początku polisy", "error");
    form.elements.validFrom.focus();
    return;
  }
  if (nextValues.validUntil && !parseLocalDate(nextValues.validUntil)) {
    showToast("Sprawdź datę końca polisy", "error");
    form.elements.validUntil.focus();
    return;
  }

  setClientProfileSaving(true);
  if (!(await ensureWritableDataFile({ deferFreshnessCheck: true }))) {
    setClientProfileSaving(false);
    return;
  }
  let relocation = {
    nextAttachments: normalizePolicyAttachments(existingPolicy.attachments),
    copiedAttachments: [],
    sourceAttachments: [],
    missingAttachments: [],
  };
  let mutationSnapshots = new Map();
  try {
    const undoBuyerName = undoBuyerTransfer
      ? String(
          getPolicyBuyerSnapshotValue(existingPolicy.buyerSnapshot, "clientName")
          || existingPolicy.buyerName
          || "",
        ).trim()
      : "";
    if (
      nextValues.policyNumber !== String(existingPolicy.policyNumber || "").trim()
      || (undoBuyerTransfer && undoBuyerName && undoBuyerName !== existingPolicy.clientName)
    ) {
      relocation = await prepareRelocatedPolicyAttachments(
        existingPolicy,
        undoBuyerName || existingPolicy.clientName,
        nextValues.policyNumber,
      );
    }
    const applyPolicyValues = () => {
      const currentPolicy = policies.find((policy) => policy.id === policyId);
      if (!currentPolicy) return false;
      if (
        undoBuyerTransfer
        && getPolicyBuyerTransferUndoPrecondition(currentPolicy) !== expectedTransferUndoState
      ) return false;
      mutationSnapshots = captureClientProfilePolicySnapshots(policies.map((policy) => policy.id));
      const desiredAttachments = normalizePolicyAttachments(relocation.nextAttachments);
      const desiredIds = new Set(desiredAttachments.map((attachment) => attachment.id));
      const concurrentAttachments = normalizePolicyAttachments(currentPolicy.attachments)
        .filter((attachment) => !desiredIds.has(attachment.id));
      const manuallyEditedValues = { ...nextValues };
      if (!validFromWasEdited) delete manuallyEditedValues.validFrom;
      markImportedPolicyFieldsManuallyEdited(currentPolicy, manuallyEditedValues);
      Object.assign(currentPolicy, nextValues, {
        registrationManuallyEdited: currentPolicy.registrationManuallyEdited === true,
        riskSummaryManuallyEdited: currentPolicy.riskSummaryManuallyEdited === true,
        premiumManuallyEdited: currentPolicy.premiumManuallyEdited === true,
        validFromManuallyEdited: currentPolicy.validFromManuallyEdited === true,
        attachments: [...desiredAttachments, ...concurrentAttachments],
        updatedAt: Date.now(),
      });
      if (renewalStatusWasEdited) {
        setPolicyRenewalStatusValue(currentPolicy, nextValues.renewalStatus, true);
      }
      if (undoBuyerTransfer && currentPolicy.transferredToBuyer === true) {
        if (!restorePolicyBuyerSnapshot(currentPolicy)) return false;
        reconnectPolicyRenewalRelationships(currentPolicy);
      }
      if (undoBuyerTransfer) {
        
      } else if (nextValues.renewalStatus === "renewed") {
        linkRenewalSuccessor(currentPolicy);
      } else {
        unlinkRenewalSuccessors(currentPolicy);
      }
      return true;
    };
    if (!applyPolicyValues()) {
      await deleteExternalAttachmentFiles(relocation.copiedAttachments);
      showToast(
        "Polisa zmieniła się w nowszej bazie. Zmiany nie zostały zastosowane.",
        "warning",
      );
      return;
    }
    saveStatusPopupSuccessText = "Polisa zaktualizowana";
    if (!(await persistPolicies({
      reapplyAfterConflict: applyPolicyValues,
      reapplyFailureMessage: "Edytowana polisa została usunięta w nowszej bazie. Zmiany nie zostały zapisane.",
    }))) {
      restoreClientProfilePolicySnapshots(mutationSnapshots);
      await deleteExternalAttachmentFiles(relocation.copiedAttachments);
      markPoliciesRolledBack();
      render();
      renderClientProfile();
      return;
    }
    await deleteExternalAttachmentFiles(
      getUnsharedAttachmentsForDeletion(relocation.sourceAttachments),
    );
    clientProfileEditingPolicyId = null;
    render();
    renderClientProfile();
    showToast(
      relocation.missingAttachments.length
        ? "Polisę zapisano, ale nie odnaleziono części załączników do przeniesienia"
        : "Dane polisy zostały zapisane",
      relocation.missingAttachments.length ? "warning" : "success",
    );
  } catch (error) {
    await deleteExternalAttachmentFiles(relocation.copiedAttachments);
    showToast(error?.message || "Nie udało się zapisać polisy", "error");
  } finally {
    if (elements.clientProfileDialog.open) setClientProfileSaving(false);
  }
}

function setContactDetailsSaving(isSaving) {
  contactDetailsSaving = Boolean(isSaving);
  elements.saveContactDetails.disabled = contactDetailsSaving;
  elements.cancelContactDetails.disabled = contactDetailsSaving;
  elements.closeContactDetails.disabled = contactDetailsSaving;
  elements.saveContactDetails.textContent = contactDetailsSaving ? "Zapisywanie..." : "Zapisz opis";
}

function openContactDetailsDialog(policyId) {
  const policy = policies.find((item) => item.id === policyId);
  if (!policy) return;

  contactDetailsPolicyId = policy.id;
  elements.contactDetailsClient.textContent = policy.clientName || "Bez nazwy klienta";
  elements.contactDetailsMeta.textContent = [
    policy.insurer,
    policy.policyNumber ? `Polisa ${policy.policyNumber}` : "",
    policy.registration,
  ].filter(Boolean).join(" · ") || "Pozostałe informacje rekordu";
  elements.contactDetailsText.value = String(policy.contact ?? "");
  setContactDetailsSaving(false);
  elements.contactDetailsDialog.showModal();
  requestAnimationFrame(() => {
    elements.contactDetailsText.focus();
    const textLength = elements.contactDetailsText.value.length;
    elements.contactDetailsText.setSelectionRange?.(textLength, textLength);
  });
}

function closeContactDetailsDialog(force = false) {
  if (contactDetailsSaving && !force) return;
  if (elements.contactDetailsDialog.open) elements.contactDetailsDialog.close();
  contactDetailsPolicyId = null;
  elements.contactDetailsText.value = "";
  setContactDetailsSaving(false);
}

const VEHICLE_DETAILS_FIELD_CONFIG = Object.freeze({
  registration: {
    label: "numer rejestracyjny",
    title: "Numer rejestracyjny",
    normalize: normalizeRegistration,
    allowClear: false,
  },
  vehicleMake: {
    label: "markę pojazdu",
    title: "Marka pojazdu",
    normalize: normalizeVehicleDetail,
  },
  vehicleModel: {
    label: "model pojazdu",
    title: "Model pojazdu",
    normalize: normalizeVehicleDetail,
  },
  vehicleType: {
    label: "rodzaj pojazdu",
    title: "Rodzaj pojazdu",
    normalize: normalizeVehicleDetail,
  },
  productionYear: {
    label: "rok produkcji pojazdu",
    title: "Rok produkcji",
    normalize: normalizeVehicleDetail,
  },
  vin: {
    label: "VIN lub numer identyfikacyjny",
    title: "VIN",
    normalize: normalizeVehicleIdentifier,
  },
  firstRegistrationDate: {
    label: "datę pierwszej rejestracji",
    title: "Data pierwszej rejestracji",
    normalize: normalizeFirstRegistrationDate,
    format: formatDate,
    allowClear: false,
  },
  engineCapacity: {
    label: "pojemność silnika",
    title: "Pojemność silnika",
    normalize: normalizeVehicleDetail,
  },
  fuelType: {
    label: "rodzaj paliwa",
    title: "Paliwo",
    normalize: normalizeVehicleDetail,
  },
  enginePower: {
    label: "moc silnika",
    title: "Moc silnika",
    normalize: normalizeVehicleDetail,
  },
  seats: {
    label: "liczbę miejsc",
    title: "Liczba miejsc",
    normalize: normalizeVehicleDetail,
  },
  grossWeight: {
    label: "dopuszczalną masę całkowitą",
    title: "DMC",
    normalize: normalizeVehicleDetail,
  },
  mileage: {
    label: "przebieg pojazdu",
    title: "Przebieg",
    normalize: normalizeVehicleDetail,
  },
});

function getVehicleDetailsFieldElements(fieldName) {
  const item = elements.vehicleDetailsForm.querySelector(`[data-vehicle-field="${fieldName}"]`);
  return {
    item,
    display: item?.querySelector(".vehicle-details-value-display"),
    value: item?.querySelector(".vehicle-details-value"),
    extra: item?.querySelector(".vehicle-details-value-extra"),
    action: item?.querySelector(".vehicle-details-value-action"),
    input: item?.querySelector(".vehicle-details-value-input"),
  };
}

function normalizeVehicleDetailsFieldValue(fieldName, value) {
  return VEHICLE_DETAILS_FIELD_CONFIG[fieldName]?.normalize(value) || "";
}



const VEHICLE_DETAILS_NUMERIC_FIELDS = new Set(["engineCapacity", "enginePower", "grossWeight", "mileage"]);




function splitVehicleDetailsDisplayValue(fieldName, displayedValue) {
  const text = String(displayedValue ?? "").trim();
  if (fieldName === "registration") {
    return { value: text, copyValue: text.replace(/\s+/g, ""), extra: "" };
  }
  if (!VEHICLE_DETAILS_NUMERIC_FIELDS.has(fieldName)) return { value: text, copyValue: text, extra: "" };
  const match = text.match(/^(\d(?:[\d\s.,]*\d)?)\s*(.*)$/);
  if (!match) return { value: text, copyValue: text, extra: "" };
  return {
    value: match[1],
    copyValue: match[1].replace(/\s+/g, ""),
    extra: match[2].trim(),
  };
}





function parseEnginePowerDisplayValue(displayedValue) {
  const match = String(displayedValue ?? "").trim().match(
    /^([0-9]{1,4}(?:[.,][0-9]{1,2})?)\s*(kW|KM)(?:\s*\(\s*([0-9]{1,4}(?:[.,][0-9]{1,2})?)\s*(kW|KM)\s*\))?$/i,
  );
  if (!match) return null;
  const normalizeUnit = (unit) => (unit.toLowerCase() === "kw" ? "kW" : "KM");
  const mainUnit = normalizeUnit(match[2]);
  const result = { value: match[1], copyValue: match[1], unit: mainUnit, chip: null };
  const pairedUnit = match[4] ? normalizeUnit(match[4]) : "";
  if (match[3] && pairedUnit && pairedUnit !== mainUnit) {
    result.chip = { copyValue: match[3], label: `${match[3]} ${pairedUnit}`, unit: pairedUnit };
    return result;
  }
  const amount = Number(match[1].replace(",", "."));
  if (!Number.isFinite(amount) || amount <= 0) return result;
  const convertedAmount = mainUnit === "kW" ? Math.round(amount * 1.35962) : Math.round(amount / 1.35962);
  if (convertedAmount > 0) {
    const convertedUnit = mainUnit === "kW" ? "KM" : "kW";
    result.chip = { copyValue: String(convertedAmount), label: `≈ ${convertedAmount} ${convertedUnit}`, unit: convertedUnit };
  }
  return result;
}



function getVehicleNumericEditValue(fieldName, storedValue) {
  if (!VEHICLE_DETAILS_NUMERIC_FIELDS.has(fieldName)) return String(storedValue ?? "");
  return splitVehicleDetailsDisplayValue(fieldName, String(storedValue ?? "").trim()).value;
}





function mergeVehicleNumericEditValue(fieldName, typedValue, storedValue) {
  if (!VEHICLE_DETAILS_NUMERIC_FIELDS.has(fieldName)) return typedValue;
  const typedNumber = String(typedValue ?? "").trim();
  if (!/^\d(?:[\d\s.,]*\d)?$/.test(typedNumber)) return typedValue;
  const storedText = String(storedValue ?? "").trim();
  const storedParts = splitVehicleDetailsDisplayValue(fieldName, storedText);
  if (storedParts.copyValue && storedParts.copyValue === typedNumber.replace(/\s+/g, "")) return storedText;
  if (fieldName === "mileage") return `${typedNumber} km`;
  if (fieldName === "enginePower") {
    const parsedPower = parseEnginePowerDisplayValue(storedText);
    if (parsedPower) return `${typedNumber} ${parsedPower.unit}`;
  }
  return storedParts.extra ? `${typedNumber} ${storedParts.extra}` : typedNumber;
}

function renderVehicleDetailsFieldValue(fieldName, value) {
  const config = VEHICLE_DETAILS_FIELD_CONFIG[fieldName];
  if (!config) return;
  const fieldElements = getVehicleDetailsFieldElements(fieldName);
  const normalizedValue = normalizeVehicleDetailsFieldValue(fieldName, value);
  const hasValue = Boolean(normalizedValue);
  const displayedValue = hasValue ? (config.format?.(normalizedValue) || normalizedValue) : "";
  let mainText = displayedValue;
  let copyValue = displayedValue;
  let extraText = "";
  let conversionChip = null;
  if (hasValue) {
    const enginePowerParts = fieldName === "enginePower" ? parseEnginePowerDisplayValue(displayedValue) : null;
    if (enginePowerParts) {
      mainText = enginePowerParts.value;
      copyValue = enginePowerParts.copyValue;
      extraText = enginePowerParts.unit;
      conversionChip = enginePowerParts.chip;
    } else {
      const parts = splitVehicleDetailsDisplayValue(fieldName, displayedValue);
      mainText = parts.value;
      copyValue = parts.copyValue;
      extraText = parts.extra;
    }
  }
  fieldElements.value.textContent = hasValue ? mainText : "Brak danych w polisie";
  fieldElements.display.dataset.copyValue = hasValue ? copyValue : "";
  if (fieldElements.extra) {
    fieldElements.extra.textContent = "";
    if (extraText) fieldElements.extra.append(extraText);
    if (conversionChip) {
      if (extraText) fieldElements.extra.append(" · ");
      const chip = document.createElement("span");
      chip.className = "vehicle-details-value-convert";
      chip.textContent = conversionChip.label;
      chip.dataset.copyValue = conversionChip.copyValue;
      chip.title = `Kliknij, aby skopiować moc w ${conversionChip.unit}: ${conversionChip.copyValue}`;
      fieldElements.extra.append(chip);
    }
    fieldElements.extra.hidden = fieldElements.extra.childNodes.length === 0;
  }
  fieldElements.action.textContent = hasValue ? "Edytuj" : "Uzupełnij";
  fieldElements.action.title = hasValue ? `Edytuj ${config.label}` : `Uzupełnij ${config.label}`;
  fieldElements.action.setAttribute(
    "aria-label",
    hasValue ? `Edytuj ${config.label}` : `Uzupełnij ${config.label}`,
  );
  fieldElements.display.dataset.empty = String(!hasValue);
  fieldElements.display.title = hasValue
    ? `Kliknij, aby skopiować: ${copyValue}`
    : "Brak danych - uzupełnij przyciskiem przy etykiecie";
  fieldElements.display.setAttribute(
    "aria-label",
    hasValue ? `Skopiuj ${config.label}: ${copyValue}` : `${config.title}: brak danych w polisie`,
  );
}

function setVehicleDetailsSaving(isSaving) {
  vehicleDetailsSaving = Boolean(isSaving);
  Object.keys(VEHICLE_DETAILS_FIELD_CONFIG).forEach((fieldName) => {
    const fieldElements = getVehicleDetailsFieldElements(fieldName);
    fieldElements.display.disabled = vehicleDetailsSaving
      || Boolean(vehicleDetailsEditingField && vehicleDetailsEditingField !== fieldName);
    fieldElements.action.disabled = fieldElements.display.disabled;
    fieldElements.input.disabled = vehicleDetailsSaving || vehicleDetailsEditingField !== fieldName;
  });
  elements.saveVehicleDetails.disabled = vehicleDetailsSaving;
  elements.cancelVehicleDetails.disabled = vehicleDetailsSaving;
  elements.vehicleDetailsEditCancel.disabled = vehicleDetailsSaving;
  elements.closeVehicleDetails.disabled = vehicleDetailsSaving;
  if (vehicleDetailsSaving) {
    elements.saveVehicleDetails.textContent = "Zapisywanie...";
    return;
  }
  const config = VEHICLE_DETAILS_FIELD_CONFIG[vehicleDetailsEditingField];
  if (!config) return;
  const policy = policies.find((item) => item.id === vehicleDetailsPolicyId);
  const fieldElements = getVehicleDetailsFieldElements(vehicleDetailsEditingField);
  const storedValue = normalizeVehicleDetailsFieldValue(vehicleDetailsEditingField, policy?.[vehicleDetailsEditingField]);
  const editedValue = normalizeVehicleDetailsFieldValue(
    vehicleDetailsEditingField,
    mergeVehicleNumericEditValue(vehicleDetailsEditingField, fieldElements.input.value, policy?.[vehicleDetailsEditingField]),
  );
  elements.saveVehicleDetails.textContent = !editedValue && storedValue && config.allowClear !== false
    ? "Usuń wartość"
    : storedValue
      ? "Zapisz zmianę"
      : "Uzupełnij dane";
}

function setVehicleDetailsEditingField(fieldName = "") {
  vehicleDetailsEditingField = VEHICLE_DETAILS_FIELD_CONFIG[fieldName] ? fieldName : "";
  Object.keys(VEHICLE_DETAILS_FIELD_CONFIG).forEach((currentFieldName) => {
    const fieldElements = getVehicleDetailsFieldElements(currentFieldName);
    const isEditing = vehicleDetailsEditingField === currentFieldName;
    fieldElements.display.hidden = isEditing;
    fieldElements.action.hidden = isEditing;
    fieldElements.input.hidden = !isEditing;
  });
  
  
  if (vehicleDetailsEditingField) {
    getVehicleDetailsFieldElements(vehicleDetailsEditingField).input
      ?.insertAdjacentElement("afterend", elements.vehicleDetailsEditCancel);
  }
  elements.vehicleDetailsEditCancel.hidden = !vehicleDetailsEditingField;
  elements.saveVehicleDetails.hidden = !vehicleDetailsEditingField;
  elements.cancelVehicleDetails.textContent = vehicleDetailsEditingField ? "Anuluj" : "Zamknij";
  setVehicleDetailsSaving(false);
}

function startVehicleDetailsFieldEditing(fieldName) {
  if (vehicleDetailsSaving || vehicleDetailsEditingField || !VEHICLE_DETAILS_FIELD_CONFIG[fieldName]) return;
  const input = getVehicleDetailsFieldElements(fieldName).input;
  
  
  input.value = getVehicleNumericEditValue(fieldName, input.value);
  setVehicleDetailsEditingField(fieldName);
  requestAnimationFrame(() => {
    input.focus();
    if (input.type === "text") input.select();
  });
}

function cancelVehicleDetailsEditing() {
  if (!vehicleDetailsEditingField) {
    closeVehicleDetailsDialog();
    return;
  }
  const previouslyEditedField = vehicleDetailsEditingField;
  const policy = policies.find((item) => item.id === vehicleDetailsPolicyId);
  const storedValue = normalizeVehicleDetailsFieldValue(previouslyEditedField, policy?.[previouslyEditedField]);
  const fieldElements = getVehicleDetailsFieldElements(previouslyEditedField);
  fieldElements.input.value = storedValue;
  renderVehicleDetailsFieldValue(previouslyEditedField, storedValue);
  setVehicleDetailsEditingField();
  requestAnimationFrame(() => fieldElements.action.focus());
}




function parseRiskSummaryEntries(riskSummary) {
  const text = String(riskSummary ?? "").trim();
  if (!text) return [];
  const parts = text.includes(" • ") ? text.split(" • ") : text.split(/,\s+(?![^(]*\))/);
  return parts
    .map((part) => part.trim())
    .filter(Boolean)
    .slice(0, 40)
    .map((part) => {
      const amountMatch = part.match(/\(?\s*(\d[\d\s.,]*)\s*zł\s*\)?\s*$/i);
      if (!amountMatch) return { label: part, amount: "" };
      const label = part.slice(0, amountMatch.index).replace(/[\s(,–—-]+$/, "").trim();
      const amount = `${amountMatch[1].replace(/\s+/g, " ").trim()} zł`;
      return label ? { label, amount } : { label: part, amount: "" };
    });
}

function openPremiumDetailsDialog(policyId) {
  const policy = policies.find((item) => item.id === policyId);
  if (!policy) return;
  const riskEntries = parseRiskSummaryEntries(policy.riskSummary);
  if (riskEntries.length === 0) return;
  elements.premiumDetailsPremium.textContent = formatPremium(policy.premium);
  elements.premiumDetailsClient.textContent = policy.clientName || "Bez nazwy klienta";
  elements.premiumDetailsMeta.textContent = [
    policy.insurer,
    policy.policyNumber ? `Polisa ${policy.policyNumber}` : "",
  ].filter(Boolean).join(" · ") || "Ryzyka z importu polisy";
  elements.premiumDetailsRisks.innerHTML = riskEntries.map((entry) => `
    <li class="premium-risk-item">
      <span class="premium-risk-item__label">${escapeHtml(entry.label)}</span>
      ${entry.amount ? `<span class="premium-risk-item__amount">${escapeHtml(entry.amount)}</span>` : ""}
    </li>
  `).join("");
  elements.premiumDetailsDialog.showModal();
  requestAnimationFrame(() => elements.closePremiumDetails.focus());
}

function closePremiumDetailsDialog() {
  if (elements.premiumDetailsDialog.open) elements.premiumDetailsDialog.close();
}

function openVehicleDetailsDialog(policyId) {
  const policy = policies.find((item) => item.id === policyId);
  if (!policy || !hasRegistrationNumber(policy)) return;

  vehicleDetailsPolicyId = policy.id;
  elements.vehicleDetailsClient.textContent = policy.clientName || "Bez nazwy klienta";
  elements.vehicleDetailsMeta.textContent = [
    policy.insurer,
    policy.policyNumber ? `Polisa ${policy.policyNumber}` : "",
  ].filter(Boolean).join(" · ") || "Dane z polisy komunikacyjnej";
  refreshVehicleDetailsFieldsFromPolicy();
  setVehicleDetailsHistoryMissingHighlights();
  setVehicleDetailsHistoryBusy(false);
  getVehicleDetailsFieldElements("firstRegistrationDate").input.max = formatDateForInput(new Date());
  setVehicleDetailsEditingField();
  elements.vehicleDetailsDialog.showModal();
  requestAnimationFrame(() => elements.closeVehicleDetails.focus());
}

function closeVehicleDetailsDialog(force = false) {
  if (vehicleDetailsSaving && !force) return;
  if (elements.vehicleDetailsDialog.open) elements.vehicleDetailsDialog.close();
  vehicleDetailsPolicyId = null;
  Object.keys(VEHICLE_DETAILS_FIELD_CONFIG).forEach((fieldName) => {
    const fieldElements = getVehicleDetailsFieldElements(fieldName);
    fieldElements.input.value = "";
    renderVehicleDetailsFieldValue(fieldName, "");
  });
  setVehicleDetailsHistoryMissingHighlights();
  setVehicleDetailsHistoryBusy(false);
  setVehicleDetailsEditingField();
  
  
  if (elements.quoteCalculatorDialog?.open) renderQuoteClientInfo();
}



function refreshVehicleDetailsFieldsFromPolicy() {
  const policy = policies.find((item) => item.id === vehicleDetailsPolicyId);
  if (!policy) return;
  Object.keys(VEHICLE_DETAILS_FIELD_CONFIG).forEach((fieldName) => {
    const normalizedValue = normalizeVehicleDetailsFieldValue(fieldName, policy[fieldName]);
    const fieldElements = getVehicleDetailsFieldElements(fieldName);
    fieldElements.input.value = normalizedValue;
    renderVehicleDetailsFieldValue(fieldName, normalizedValue);
  });
}

function setVehicleDetailsHistoryBusy(busy) {
  vehicleDetailsHistoryBusy = Boolean(busy);
  elements.vehicleDetailsHistory.disabled = vehicleDetailsHistoryBusy;
  elements.vehicleDetailsHistory.textContent = vehicleDetailsHistoryBusy ? "Pobieranie..." : "HistoriaPojazdu.gov";
  elements.vehicleDetailsHistory.classList.toggle("vehicle-details-history-button--busy", vehicleDetailsHistoryBusy);
}



function setVehicleDetailsHistoryMissingHighlights({ vin = false, firstRegistrationDate = false } = {}) {
  getVehicleDetailsFieldElements("vin").item?.classList.toggle("vehicle-details-item--missing", vin);
  getVehicleDetailsFieldElements("firstRegistrationDate").item?.classList.toggle("vehicle-details-item--missing", firstRegistrationDate);
}



async function fetchVehicleDetailsHistory() {
  if (vehicleDetailsSaving || vehicleDetailsHistoryBusy || !vehicleDetailsPolicyId) return;
  if (vehicleDetailsEditingField) {
    showToast("Najpierw zapisz albo anuluj edycję pola", "warning");
    return;
  }
  const policy = policies.find((item) => item.id === vehicleDetailsPolicyId);
  if (!policy) return;
  const registration = normalizeVehicleIdentifier(policy.registration);
  const vin = normalizeVehicleIdentifier(policy.vin);
  const firstRegistrationDate = normalizeFirstRegistrationDate(policy.firstRegistrationDate);
  setVehicleDetailsHistoryMissingHighlights({ vin: !vin, firstRegistrationDate: !firstRegistrationDate });
  if (!registration || !vin || !firstRegistrationDate) {
    showToast(buildVehicleHistoryMissingMessage({ registration, vin, firstRegistrationDate }), "error");
    return;
  }
  setVehicleDetailsHistoryBusy(true);
  setVehicleDetailsSaving(true);
  let vehicleData = null;
  try {
    vehicleData = await requestVehicleHistoryData(policy);
  } catch (error) {
    setVehicleDetailsSaving(false);
    setVehicleDetailsHistoryBusy(false);
    showToast(error?.message || "Nie udało się pobrać danych z HistoriaPojazdu.gov.", "error");
    return;
  }
  const nextValues = buildVehicleHistoryValues(policy, vehicleData);
  if (Object.keys(nextValues).length === 0) {
    setVehicleDetailsSaving(false);
    setVehicleDetailsHistoryBusy(false);
    showToast("Dane pojazdu są już zgodne z HistoriaPojazdu.gov");
    return;
  }
  
  
  const groupPolicies = getSameClientVehiclePolicies(policy);
  const policyIds = (groupPolicies.length > 0 ? groupPolicies : [policy]).map((item) => item.id);
  let mutationSnapshots = new Map();
  const applyVehicleHistoryValues = () => {
    const currentPolicies = policyIds
      .map((policyId) => policies.find((item) => item.id === policyId))
      .filter(Boolean);
    if (currentPolicies.length === 0) return false;
    mutationSnapshots = captureClientProfilePolicySnapshots(currentPolicies.map((item) => item.id));
    currentPolicies.forEach((item) => {
      Object.assign(item, nextValues);
      item.updatedAt = Date.now();
    });
    return true;
  };
  try {
    if (!(await ensureWritableDataFile({ deferFreshnessCheck: true }))) return;
    if (!applyVehicleHistoryValues()) {
      showToast("Nie znaleziono polis pojazdu w bazie", "error");
      return;
    }
    saveStatusPopupSuccessText = "Dane pojazdu z HistoriaPojazdu.gov zapisane";
    if (!(await persistPolicies({
      reapplyAfterConflict: applyVehicleHistoryValues,
      reapplyFailureMessage: "Polisy pojazdu zmieniły się w nowszej bazie. Dane z HistoriaPojazdu.gov nie zostały zapisane.",
    }))) {
      restoreClientProfilePolicySnapshots(mutationSnapshots);
      markPoliciesRolledBack();
      render();
      return;
    }
    render();
    if (elements.clientProfileDialog.open) renderClientProfile();
    refreshVehicleDetailsFieldsFromPolicy();
    showToast(`Pojazd ${policy.registration}: dane uzupełnione z HistoriaPojazdu.gov`);
  } catch (error) {
    restoreClientProfilePolicySnapshots(mutationSnapshots);
    markPoliciesRolledBack();
    render();
    showToast(error?.message || "Nie udało się zapisać danych z HistoriaPojazdu.gov.", "error");
  } finally {
    setVehicleDetailsHistoryBusy(false);
    if (elements.vehicleDetailsDialog.open) setVehicleDetailsSaving(false);
  }
}

function getVehicleDetailsFieldValidationError(fieldName, rawValue, normalizedValue, storedValue) {
  const config = VEHICLE_DETAILS_FIELD_CONFIG[fieldName];
  const trimmedValue = String(rawValue ?? "").trim();
  if (!normalizedValue) {
    if (trimmedValue) return `Wpisz prawidłową wartość pola „${config.title}”`;
    if (!storedValue || config.allowClear === false) return `Uzupełnij pole „${config.title}”`;
    return "";
  }

  
  if (fieldName === "registration" && getPolicyTypeIndex(normalizedValue) >= 0) {
    return "Wpisz numer rejestracyjny pojazdu, a nie rodzaj polisy";
  }

  if (fieldName === "firstRegistrationDate") {
    const parsedDate = parseLocalDate(normalizedValue);
    const today = parseLocalDate(formatDateForInput(new Date()));
    if (!parsedDate || parsedDate > today) return "Wybierz prawidłową datę pierwszej rejestracji";
  }

  return "";
}

async function saveVehicleDetails(event) {
  event.preventDefault();
  if (vehicleDetailsSaving || !vehicleDetailsEditingField || !vehicleDetailsPolicyId) return;

  const policyId = vehicleDetailsPolicyId;
  const editedField = vehicleDetailsEditingField;
  const existingPolicy = policies.find((item) => item.id === policyId);
  if (!existingPolicy) {
    closeVehicleDetailsDialog(true);
    showToast("Nie znaleziono edytowanego rekordu", "error");
    return;
  }
  const config = VEHICLE_DETAILS_FIELD_CONFIG[editedField];
  const fieldElements = getVehicleDetailsFieldElements(editedField);
  
  
  const rawValue = mergeVehicleNumericEditValue(editedField, fieldElements.input.value, existingPolicy[editedField]);
  const nextValue = normalizeVehicleDetailsFieldValue(editedField, rawValue);
  const storedValue = normalizeVehicleDetailsFieldValue(editedField, existingPolicy[editedField]);
  const validationError = getVehicleDetailsFieldValidationError(editedField, rawValue, nextValue, storedValue);
  if (validationError) {
    showToast(validationError, "error");
    fieldElements.input.focus();
    return;
  }
  fieldElements.input.value = nextValue;
  const changedFieldValues = { [editedField]: nextValue };
  const hasChangedValue = Object.entries(changedFieldValues).some(([fieldName, value]) => (
    normalizeVehicleDetailsFieldValue(fieldName, existingPolicy[fieldName]) !== value
  ));
  if (!hasChangedValue) {
    cancelVehicleDetailsEditing();
    return;
  }
  
  if (editedField === "registration") changedFieldValues.registrationManuallyEdited = true;

  setVehicleDetailsSaving(true);
  try {
    if (!(await ensureWritableDataFile({ deferFreshnessCheck: true }))) return;

    let mutationState = null;
    const applyVehicleDetailsChange = () => {
      const currentPolicy = policies.find((item) => item.id === policyId);
      if (!currentPolicy) return false;
      mutationState = {
        policy: currentPolicy,
        fields: Object.fromEntries(Object.keys(changedFieldValues).map((fieldName) => [
          fieldName,
          {
            exists: Object.prototype.hasOwnProperty.call(currentPolicy, fieldName),
            value: currentPolicy[fieldName],
          },
        ])),
        importedPolicyTracking: captureImportedPolicyTrackingRollbackState(currentPolicy),
        updatedAt: {
          exists: Object.prototype.hasOwnProperty.call(currentPolicy, "updatedAt"),
          value: currentPolicy.updatedAt,
        },
      };
      markImportedPolicyFieldsManuallyEdited(currentPolicy, {
        [editedField]: nextValue,
      });
      Object.assign(currentPolicy, changedFieldValues);
      currentPolicy.updatedAt = Date.now();
      return true;
    };

    if (!applyVehicleDetailsChange()) {
      closeVehicleDetailsDialog(true);
      showToast("Nie znaleziono edytowanego rekordu", "error");
      return;
    }

    saveStatusPopupSuccessText = `${config.title} - zapisano`;
    if (!(await persistPolicies({
      reapplyAfterConflict: applyVehicleDetailsChange,
      reapplyFailureMessage: `Edytowany rekord został usunięty w nowszej wersji bazy. Nie udało się zapisać pola „${config.title}”.`,
    }))) {
      if (mutationState && policies.includes(mutationState.policy)) {
        Object.entries(mutationState.fields).forEach(([fieldName, fieldState]) => {
          if (fieldState.exists) mutationState.policy[fieldName] = fieldState.value;
          else delete mutationState.policy[fieldName];
        });
        restoreImportedPolicyTrackingRollbackState(
          mutationState.policy,
          mutationState.importedPolicyTracking,
        );
        if (mutationState.updatedAt.exists) mutationState.policy.updatedAt = mutationState.updatedAt.value;
        else delete mutationState.policy.updatedAt;
      }
      markPoliciesRolledBack();
      render();
      return;
    }

    closeVehicleDetailsDialog(true);
    render();
    showToast(`${config.title} - zapisano`);
  } finally {
    if (elements.vehicleDetailsDialog.open) setVehicleDetailsSaving(false);
  }
}

async function saveContactDetails(event) {
  event.preventDefault();
  if (contactDetailsSaving || !contactDetailsPolicyId) return;

  const policyId = contactDetailsPolicyId;
  const nextContact = elements.contactDetailsText.value.trim();
  setContactDetailsSaving(true);
  try {
    if (!(await ensureWritableDataFile({ deferFreshnessCheck: true }))) return;

    let mutationStates = new Map();
    const applyContactDetails = () => {
      const currentPolicy = policies.find((item) => item.id === policyId);
      if (!currentPolicy) return false;
      mutationStates = new Map();
      capturePolicyMutationState(mutationStates, currentPolicy);
      markImportedPolicyFieldsManuallyEdited(currentPolicy, { contact: nextContact });
      currentPolicy.contact = nextContact;
      currentPolicy.updatedAt = Date.now();
      return true;
    };

    if (!applyContactDetails()) {
      closeContactDetailsDialog(true);
      showToast("Nie znaleziono edytowanego rekordu", "error");
      return;
    }

    saveStatusPopupSuccessText = "Opis rekordu zapisany";
    if (!(await persistPolicies({
      reapplyAfterConflict: applyContactDetails,
      reapplyFailureMessage: "Edytowany rekord został usunięty w nowszej wersji bazy. Opis nie został zapisany.",
    }))) {
      restorePolicyMutationStates(mutationStates);
      markPoliciesRolledBack();
      render();
      return;
    }

    closeContactDetailsDialog(true);
    render();
    showToast("Opis i informacje kontaktowe zostały zapisane");
  } finally {
    if (elements.contactDetailsDialog.open) setContactDetailsSaving(false);
  }
}

function showAppBusyOverlay(label) {
  const overlay = document.querySelector("#appBusyOverlay");
  if (!overlay) return;
  const labelElement = document.querySelector("#appBusyOverlayLabel");
  if (labelElement && label) labelElement.textContent = label;
  overlay.dataset.hidden = "false";
  
  
  
  if (document.querySelector("dialog[open]") && typeof overlay.showPopover === "function") {
    try {
      if (!overlay.hasAttribute("popover")) overlay.setAttribute("popover", "manual");
      if (!overlay.matches(":popover-open")) overlay.showPopover();
      
      if (elements.notificationDock?.matches?.(":popover-open")) bringNotificationDockToFront();
    } catch {
    }
  }
}

function hideAppBusyOverlay() {
  const overlay = document.querySelector("#appBusyOverlay");
  if (!overlay) return;
  overlay.dataset.hidden = "true";
  if (typeof overlay.hidePopover === "function") {
    try {
      if (overlay.matches(":popover-open")) overlay.hidePopover();
    } catch {
    }
    overlay.removeAttribute("popover");
  }
}










function yieldToUi() {
  if (document.hidden) return yieldViaMessagePort();
  return new Promise((resolve) => {
    requestAnimationFrame(() => setTimeout(resolve, 0));
  });
}

function yieldViaMessagePort() {
  return new Promise((resolve) => {
    const channel = new MessageChannel();
    channel.port1.onmessage = () => {
      channel.port1.close();
      channel.port2.close();
      resolve();
    };
    channel.port2.postMessage(null);
  });
}

function showToast(message, type = null) {
  const stack = elements.toastStack;
  if (!stack) return;
  const messageText = String(message);
  const resolvedType = type || (
    /nie udało|brak zgody|błąd|zatrzyman|nie można|nie pozwala/i.test(messageText)
      ? "error"
      : /\bale\b|pozostał|nie odnaleziono|część plików/i.test(messageText)
        ? "warning"
        : "success"
  );
  
  
  const existing = [...stack.children].find((node) => node.dataset.type === resolvedType
    && node.classList.contains("toast--visible")
    && node.querySelector(".toast-message")?.textContent === messageText);
  if (existing) {
    scheduleToastDismiss(existing);
    bringNotificationDockToFront();
    return;
  }
  const toast = document.createElement("div");
  toast.className = "toast";
  toast.dataset.type = resolvedType;
  const icon = document.createElement("span");
  icon.setAttribute("aria-hidden", "true");
  icon.textContent = resolvedType === "success" ? "✓" : resolvedType === "music" ? "♪" : "!";
  const text = document.createElement("span");
  text.className = "toast-message";
  text.textContent = messageText;
  toast.append(icon, text);
  stack.append(toast);
  while (stack.children.length > TOAST_STACK_LIMIT) removeToastNow(stack.firstElementChild);
  bringNotificationDockToFront();
  
  
  void toast.offsetWidth;
  toast.classList.add("toast--visible");
  scheduleToastDismiss(toast);
}

function scheduleToastDismiss(toast) {
  clearTimeout(toastDismissTimers.get(toast));
  toastDismissTimers.set(toast, setTimeout(() => {
    toast.classList.remove("toast--visible");
    toastDismissTimers.set(toast, setTimeout(() => removeToastNow(toast), TOAST_EXIT_MS));
  }, TOAST_DISMISS_AFTER_MS));
}

function removeToastNow(toast) {
  if (!toast) return;
  clearTimeout(toastDismissTimers.get(toast));
  toastDismissTimers.delete(toast);
  toast.remove();
  updateNotificationDockVisibility();
}



function updateNotificationDockVisibility() {
  const dock = elements.notificationDock;
  if (!dock) return;
  const hasContent = (elements.toastStack?.childElementCount || 0) > 0
    || (elements.saveStatusPopup && !elements.saveStatusPopup.hidden);
  if (typeof dock.showPopover !== "function") {
    dock.classList.toggle("notification-dock--fixed", Boolean(hasContent));
    return;
  }
  try {
    if (hasContent) {
      if (!dock.matches(":popover-open")) dock.showPopover();
    } else if (dock.matches(":popover-open")) {
      dock.hidePopover();
    }
  } catch {}
}




function bringNotificationDockToFront() {
  const dock = elements.notificationDock;
  if (!dock) return;
  if (typeof dock.showPopover !== "function") {
    dock.classList.add("notification-dock--fixed");
    return;
  }
  try {
    if (dock.matches(":popover-open")) dock.hidePopover();
    dock.showPopover();
  } catch {}
}

let copyValueTooltipElement = null;
let copyValueTooltipTimer = null;

async function copyTextToClipboard(text) {
  try {
    await navigator.clipboard.writeText(text);
    return true;
  } catch {}
  const helper = document.createElement("textarea");
  helper.value = text;
  helper.setAttribute("readonly", "");
  helper.style.position = "fixed";
  helper.style.opacity = "0";
  document.body.append(helper);
  helper.select();
  let copied = false;
  try {
    copied = document.execCommand("copy");
  } catch {
    copied = false;
  }
  helper.remove();
  return copied;
}

function showCopyValueTooltip(anchor, message) {
  if (!copyValueTooltipElement) {
    copyValueTooltipElement = document.createElement("div");
    copyValueTooltipElement.className = "copy-value-tooltip";
    if (typeof copyValueTooltipElement.showPopover === "function") {
      copyValueTooltipElement.setAttribute("popover", "manual");
    }
    document.body.append(copyValueTooltipElement);
  }
  const tooltip = copyValueTooltipElement;
  const supportsPopover = typeof tooltip.showPopover === "function";
  clearTimeout(copyValueTooltipTimer);
  tooltip.textContent = message;
  if (supportsPopover) {
    if (tooltip.matches(":popover-open")) tooltip.hidePopover();
    tooltip.showPopover();
  } else {
    tooltip.hidden = false;
  }
  const anchorRect = anchor.getBoundingClientRect();
  const tooltipRect = tooltip.getBoundingClientRect();
  const left = Math.max(
    8,
    Math.min(
      anchorRect.left + (anchorRect.width - tooltipRect.width) / 2,
      window.innerWidth - tooltipRect.width - 8,
    ),
  );
  const top = anchorRect.top - tooltipRect.height - 7;
  tooltip.style.left = `${Math.round(left)}px`;
  tooltip.style.top = `${Math.round(top >= 8 ? top : anchorRect.bottom + 7)}px`;
  copyValueTooltipTimer = setTimeout(() => {
    if (supportsPopover) {
      if (tooltip.matches(":popover-open")) tooltip.hidePopover();
    } else {
      tooltip.hidden = true;
    }
  }, 1500);
}

async function handleCopyValueClick(button) {
  const value = String(button?.dataset?.copyValue || "").trim();
  if (!value) return;
  const copied = await copyTextToClipboard(value);
  showCopyValueTooltip(button, copied ? "Skopiowano" : "Nie udało się skopiować");
}

async function setRenewalStatus(policyId, status) {
  if (!(await ensureWritableDataFile({ deferFreshnessCheck: true }))) return;
  const policy = policies.find((item) => item.id === policyId);
  if (!policy) return;
  if (POLICY_BUYER_TRANSFER_FEATURE_ENABLED && policy.transferredToBuyer === true) {
    showToast("Dla zbytego pojazdu status odnowienia nie ma zastosowania", "warning");
    return;
  }
  const nextStatus = policy.renewalStatus === status ? null : status;
  let mutationStates = new Map();
  let linkedSuccessor = null;
  const applyRenewalStatus = () => {
    const currentPolicy = policies.find((item) => item.id === policyId);
    if (!currentPolicy) return false;
    mutationStates = new Map();
    capturePolicyMutationState(mutationStates, currentPolicy);
    setPolicyRenewalStatusValue(currentPolicy, nextStatus, true);
    currentPolicy.updatedAt = Date.now();
    linkedSuccessor = null;
    if (nextStatus === "renewed") {
      linkedSuccessor = linkRenewalSuccessor(currentPolicy, mutationStates);
    } else {
      unlinkRenewalSuccessors(currentPolicy, mutationStates);
    }
    return true;
  };
  applyRenewalStatus();
  if (!(await persistPolicies({
    reapplyAfterConflict: applyRenewalStatus,
    reapplyFailureMessage: "Rekord został usunięty w nowszej wersji bazy. Status odnowienia nie został zapisany.",
  }))) {
    restorePolicyMutationStates(mutationStates);
    markPoliciesRolledBack();
    render();
    return;
  }
  render();
  if (nextStatus === "renewed") {
    showToast(
      linkedSuccessor?.policyNumber
        ? `Połączono ze wznowieniem ${linkedSuccessor.policyNumber}`
        : "Polisa oznaczona jako odnowiona. Nie znaleziono jeszcze nowej polisy.",
      linkedSuccessor ? "success" : "warning",
    );
  }
}



async function markPolicyRenewedWithSuccessor(policyId, successorId) {
  if (!(await ensureWritableDataFile({ deferFreshnessCheck: true }))) return false;
  const policy = policies.find((item) => item.id === policyId);
  const successorPolicy = policies.find((item) => item.id === successorId);
  if (!policy || !successorPolicy || policy.id === successorPolicy.id) return false;
  if (POLICY_BUYER_TRANSFER_FEATURE_ENABLED && policy.transferredToBuyer === true) {
    showToast("Dla zbytego pojazdu status odnowienia nie ma zastosowania", "warning");
    return false;
  }
  let mutationStates = new Map();
  const applyManualRenewal = () => {
    const currentPolicy = policies.find((item) => item.id === policyId);
    const currentSuccessor = policies.find((item) => item.id === successorId);
    if (!currentPolicy || !currentSuccessor) return false;
    mutationStates = new Map();
    capturePolicyMutationState(mutationStates, currentPolicy);
    setPolicyRenewalStatusValue(currentPolicy, "renewed", true);
    currentPolicy.updatedAt = Date.now();
    unlinkRenewalSuccessors(currentPolicy, mutationStates);
    capturePolicyMutationState(mutationStates, currentSuccessor);
    setPolicyRenewalPredecessor(currentSuccessor, currentPolicy.id, true);
    currentSuccessor.updatedAt = Date.now();
    return true;
  };
  applyManualRenewal();
  if (!(await persistPolicies({
    reapplyAfterConflict: applyManualRenewal,
    reapplyFailureMessage: "Rekord zmienił się w nowszej wersji bazy. Wznowienie nie zostało zapisane.",
  }))) {
    restorePolicyMutationStates(mutationStates);
    markPoliciesRolledBack();
    render();
    renderCalendar();
    return false;
  }
  render();
  renderCalendar();
  showToast(successorPolicy.policyNumber
    ? `Połączono ze wznowieniem ${successorPolicy.policyNumber}`
    : "Polisa oznaczona jako odnowiona");
  return true;
}

async function hideCalendarRenewalPolicy(policyId) {
  if (!(await ensureWritableDataFile({ deferFreshnessCheck: true }))) return;
  if (!policies.some((item) => item.id === policyId)) return;
  let mutatedPolicy = null;
  const applyHide = () => {
    const currentPolicy = policies.find((item) => item.id === policyId);
    if (!currentPolicy) return false;
    mutatedPolicy = currentPolicy;
    currentPolicy.calendarHidden = true;
    currentPolicy.updatedAt = Date.now();
    return true;
  };
  applyHide();
  if (!(await persistPolicies({
    reapplyAfterConflict: applyHide,
    reapplyFailureMessage: "Rekord został usunięty w nowszej wersji bazy. Polisa nie została ukryta.",
  }))) {
    if (mutatedPolicy && policies.includes(mutatedPolicy)) delete mutatedPolicy.calendarHidden;
    markPoliciesRolledBack();
    renderCalendar();
    return;
  }
  renderCalendar();
  showToast("Polisa ukryta w kalendarzu");
}

async function restoreHiddenCalendarRenewals(dateKey) {
  if (!(await ensureWritableDataFile({ deferFreshnessCheck: true }))) return;
  const selectedDate = parseLocalDate(dateKey);
  if (!selectedDate) return;
  const selectedDateKey = formatDateForInput(selectedDate);
  const matchesHiddenRenewal = (policy) => {
    if (policy?.calendarHidden !== true || isTravelPolicy(policy) || policy?.renewalStatus === "renewed") return false;
    const endDate = parseLocalDate(policy?.validUntil);
    return Boolean(endDate && formatDateForInput(endDate) === selectedDateKey);
  };
  let mutatedPolicies = [];
  const applyRestore = () => {
    mutatedPolicies = [];
    policies.forEach((policy) => {
      if (!matchesHiddenRenewal(policy)) return;
      mutatedPolicies.push(policy);
      delete policy.calendarHidden;
      policy.updatedAt = Date.now();
    });
    return true;
  };
  applyRestore();
  if (mutatedPolicies.length === 0) {
    renderCalendar();
    return;
  }
  if (!(await persistPolicies({ reapplyAfterConflict: applyRestore }))) {
    mutatedPolicies.forEach((policy) => {
      if (policies.includes(policy)) policy.calendarHidden = true;
    });
    markPoliciesRolledBack();
    renderCalendar();
    return;
  }
  renderCalendar();
  showToast("Przywrócono ukryte polisy w kalendarzu");
}

async function deletePolicy(policyId) {
  if (!(await ensureWritableDataFile({ deferFreshnessCheck: true }))) return;
  const policy = policies.find((item) => item.id === policyId);
  if (!policy) return;
  const recordName = policy.clientName || policy.registration || "ten rekord";
  const confirmed = await requestDeleteConfirmation({
    title: "Usunięcie rekordu",
    message: `Przenieść „${recordName}” do usuniętych rekordów? Rekord i jego załączniki będzie można przywrócić przez 30 dni.`,
    confirmLabel: "Przenieś do usuniętych",
  });
  if (!confirmed) return;

  let rollbackPolicies = policies;
  let rollbackDeletedPolicies = deletedPolicies;
  let relationshipMutationStates = new Map();
  const applyMoveToTrash = () => {
    rollbackPolicies = policies;
    rollbackDeletedPolicies = deletedPolicies;
    relationshipMutationStates = new Map();
    const currentPolicy = policies.find((item) => item.id === policyId);
    if (!currentPolicy) return deletedPolicies.some((item) => item.id === policyId);
    const deletedPolicy = { ...currentPolicy, deletedAt: Date.now() };
    detachRemovedPolicyRenewalRelationships(currentPolicy, relationshipMutationStates);
    policies = policies.filter((item) => item.id !== policyId);
    deletedPolicies = [
      ...deletedPolicies.filter((item) => item.id !== policyId),
      deletedPolicy,
    ];
    return true;
  };
  applyMoveToTrash();
  if (editingPolicyId === policyId) {
    editingPolicyId = null;
    editingPolicyDraft = null;
  }
  if (expandedPolicyId === policyId) expandedPolicyId = null;
  saveStatusPopupSuccessText = "Rekord przeniesiony do kosza";
  if (!(await persistPolicies({ reapplyAfterConflict: applyMoveToTrash }))) {
    restorePolicyMutationStates(relationshipMutationStates);
    policies = rollbackPolicies;
    deletedPolicies = rollbackDeletedPolicies;
    markPoliciesRolledBack();
    render();
    return;
  }
  render();
  updateDeletedRecordsSettingsSummary();
  showToast("Rekord przeniesiono do usuniętych. Można go przywrócić przez 30 dni.");
}

elements.form.addEventListener("keydown", handleAddFormEnter);

elements.form.addEventListener("submit", async (event) => {
  event.preventDefault();
  if (addPolicySubmitting || attachmentOperationActive) return;
  if (!elements.clientNameInput.value.trim()) {
    showToast("Wpisz imię i nazwisko / nazwę klienta, aby dodać rekord", "error");
    elements.clientNameInput.focus();
    return;
  }
  addPolicySubmitting = true;
  updateAddPolicyButtonState();
  try {
    if (!(await ensureWritableDataFile({ deferFreshnessCheck: true }))) return;
  const formData = new FormData(elements.form);
  const validUntil = String(formData.get("validUntil") ?? "");
  const importedValidFrom = String(elements.form.dataset.importedValidFrom ?? "");
  const enteredValidFrom = String(formData.get("validFrom") ?? "") || importedValidFrom;
  const selectedPolicyType = formData.get("registration");
  const startDateWasManual = Boolean(importedValidFrom) || (
    (uiSettings.showStartDateInput || shouldShowStartDateForPolicyType(selectedPolicyType))
      && elements.startDateFormField.dataset.manuallyEdited === "true"
      && Boolean(enteredValidFrom)
  );
  const clientName = String(formData.get("clientName") ?? "").trim();
  const policyNumber = String(formData.get("policyNumber") ?? "").trim();
  let storedAttachments = [];
  const hasPendingAttachments = pendingAttachments.length > 0;
  if (hasPendingAttachments) startAttachmentOperation(pendingAttachments.length, "Zapisywanie załączników");
  try {
    if (hasPendingAttachments) {
      storedAttachments = await writeAttachmentsToFolder(
        clientName,
        policyNumber,
        pendingAttachments,
        updateAttachmentOperation,
      );
    }
  } catch (error) {
    if (hasPendingAttachments) finishAttachmentOperation();
    showToast(error?.name === "AbortError" ? "Nie wybrano folderu Baza Polis" : (error?.message || "Nie udało się zapisać załączników"));
    return;
  }

  const newPolicy = {
    id: globalThis.crypto?.randomUUID?.() ?? `${Date.now()}-${Math.random()}`,
    ownerId: currentAccount?.id || "",
    clientName,
    identityNumber: String(formData.get("identityNumber") ?? "").trim(),
    secondaryIdentityNumber: "",
    contact: String(formData.get("contact") ?? "").trim(),
    insurer: String(formData.get("insurer") ?? "").trim(),
    policyNumber,
    registration: normalizeRegistration(formData.get("registration")),
    vehicleMake: "",
    vehicleModel: "",
    vin: "",
    firstRegistrationDate: "",
    clientAddress: "",
    clientPostalCode: "",
    clientPhone: "",
    clientEmail: "",
    validFrom: startDateWasManual
      ? enteredValidFrom
      : formatDateForInput(
          normalize(selectedPolicyType) === normalize("Podróż")
            ? calculateTravelStartDate(validUntil)
            : calculateStartDate(validUntil),
        ),
    validFromManuallyEdited: startDateWasManual,
    validUntil,
    premium: String(formData.get("premium") ?? "").trim(),
    renewalStatus: null,
    attachments: storedAttachments,
    createdAt: Date.now(),
  };
  const manuallyEnteredImportedValues = { ...newPolicy };
  if (!startDateWasManual) delete manuallyEnteredImportedValues.validFrom;
  markImportedPolicyFieldsManuallyEdited(
    newPolicy,
    manuallyEnteredImportedValues,
    { markNonEmpty: true },
  );
  let renewalMutationStates = new Map();
  let detectedPreviousPolicy = null;
  const reapplyNewPolicy = () => {
    if (!policies.some((policy) => policy.id === newPolicy.id)) policies.push(newPolicy);
    renewalMutationStates = new Map();
    detectedPreviousPolicy = linkPolicyToBestRenewalPredecessor(newPolicy, renewalMutationStates);
    return true;
  };
  reapplyNewPolicy();

  if (hasPendingAttachments) {
    updateAttachmentOperation("Zapisywanie zmian w bazie", pendingAttachments.length, pendingAttachments.length);
  }
  saveStatusPopupSuccessText = "Polisa dodana do bazy";
  if (!(await persistPolicies({ reapplyAfterConflict: reapplyNewPolicy }))) {
    restorePolicyMutationStates(renewalMutationStates);
    policies = policies.filter((policy) => policy.id !== newPolicy.id);
    await deleteExternalAttachmentFiles(storedAttachments);
    markPoliciesRolledBack();
    if (hasPendingAttachments) finishAttachmentOperation();
    render();
    return;
  }
  if (hasPendingAttachments) finishAttachmentOperation();
  elements.form.reset();
  clearNewPolicyAttachments();
  delete elements.form.dataset.importedValidFrom;
  addFormAutoFilledIdentity = "";
  elements.startDateFormField.dataset.manuallyEdited = "false";
  delete elements.validUntilInput.dataset.travelDerived;
  refreshAddFormStartDateVisibility();
  updateAddFormStartDateFromEnd();
  updateAddPolicyButtonState();
  currentPage = 1;
  pageJumpOpen = false;
  render();
  flashRecordCounterPlusOne();
  if (detectedPreviousPolicy?.policyNumber) {
    showToast(`Wykryto wznowienie polisy ${detectedPreviousPolicy.policyNumber}`);
  }
  elements.form.querySelector("input")?.focus();
  } finally {
    addPolicySubmitting = false;
    updateAddPolicyButtonState();
  }
});

elements.rows.addEventListener("submit", async (event) => {
  event.preventDefault();
  const editForm = event.target.closest("[data-edit-form]");
  if (!editForm) return;
  const policyId = editForm.dataset.editForm;
  const formData = new FormData(editForm);
  const editRegistration = normalizeRegistration(formData.get("registration"));
  const editValidUntil = String(formData.get("validUntil") ?? "");
  const enteredEditValidFrom = String(formData.get("validFrom") ?? "");
  const editStartDateWasManual = editForm.dataset.startDateManual === "true" && Boolean(enteredEditValidFrom);
  const nextValues = {
    clientName: String(formData.get("clientName") ?? "").trim(),
    identityNumber: String(formData.get("identityNumber") ?? "").trim(),
    contact: String(formData.get("contact") ?? "").trim(),
    insurer: String(formData.get("insurer") ?? "").trim(),
    policyNumber: String(formData.get("policyNumber") ?? "").trim(),
    registration: editRegistration,
    validFrom: editStartDateWasManual
      ? enteredEditValidFrom
      : formatDateForInput(
          normalize(editRegistration) === normalize("Podróż")
            ? calculateTravelStartDate(editValidUntil)
            : calculateStartDate(editValidUntil),
        ),
    validUntil: editValidUntil,
    premium: String(formData.get("premium") ?? "").trim(),
  };
  captureEditingPolicyDraft(editForm);
  if (!(await ensureWritableDataFile({ deferFreshnessCheck: true }))) return;
  const policy = policies.find((item) => item.id === policyId);
  if (!policy) return;

  const previousPolicy = { ...policy, attachments: policy.attachments };
  let activeEditedPolicy = policy;
  let rollbackPolicy = previousPolicy;
  let rollbackImportedTracking = captureImportedPolicyTrackingRollbackState(policy);
  let relocation = {
    nextAttachments: normalizePolicyAttachments(policy.attachments),
    copiedAttachments: [],
    sourceAttachments: [],
    missingAttachments: [],
  };
  const targetDirectoryPath = getPolicyAttachmentDirectoryPath(nextValues.clientName, nextValues.policyNumber);
  const attachmentsToRelocate = normalizePolicyAttachments(policy.attachments).filter((attachment) => {
    if (!isExternalAttachment(attachment)) return false;
    return JSON.stringify(attachment.relativePath.slice(0, -1)) !== JSON.stringify(targetDirectoryPath);
  });
  if (attachmentsToRelocate.length > 0) startAttachmentOperation(attachmentsToRelocate.length, "Przenoszenie załączników");

  try {
    if (attachmentsToRelocate.length > 0) {
      relocation = await prepareRelocatedPolicyAttachments(
        policy,
        nextValues.clientName,
        nextValues.policyNumber,
        updateAttachmentOperation,
      );
    }
    const applyEditedValues = () => {
      const currentPolicy = policies.find((item) => item.id === policyId);
      if (!currentPolicy) return false;
      if (currentPolicy !== activeEditedPolicy) {
        activeEditedPolicy = currentPolicy;
        rollbackPolicy = { ...currentPolicy, attachments: currentPolicy.attachments };
        rollbackImportedTracking = captureImportedPolicyTrackingRollbackState(currentPolicy);
      }
      const desiredAttachments = normalizePolicyAttachments(relocation.nextAttachments);
      const desiredAttachmentIds = new Set(desiredAttachments.map((attachment) => attachment.id));
      const currentOnlyAttachments = normalizePolicyAttachments(currentPolicy.attachments)
        .filter((attachment) => !desiredAttachmentIds.has(attachment.id));
      const manuallyEditedValues = { ...nextValues };
      
      if (!editStartDateWasManual) delete manuallyEditedValues.validFrom;
      markImportedPolicyFieldsManuallyEdited(currentPolicy, manuallyEditedValues);
      Object.assign(currentPolicy, nextValues, {
        registrationManuallyEdited: currentPolicy.registrationManuallyEdited === true,
        premiumManuallyEdited: currentPolicy.premiumManuallyEdited === true,
        validFromManuallyEdited: currentPolicy.validFromManuallyEdited === true,
        attachments: [...desiredAttachments, ...currentOnlyAttachments],
        updatedAt: Date.now(),
      });
      return true;
    };
    applyEditedValues();
    if (!(await persistPolicies({
      reapplyAfterConflict: applyEditedValues,
      reapplyFailureMessage: "Edytowany rekord został usunięty w nowszej wersji bazy. Zmiany nie zostały zapisane.",
    }))) {
      if (policies.includes(activeEditedPolicy)) {
        Object.assign(activeEditedPolicy, rollbackPolicy);
        restoreImportedPolicyTrackingRollbackState(activeEditedPolicy, rollbackImportedTracking);
      }
      await deleteExternalAttachmentFiles(relocation.copiedAttachments);
      markPoliciesRolledBack();
      editingPolicyId = policies.some((item) => item.id === policyId) ? policyId : null;
      render();
      return;
    }

    const removedOldFiles = await deleteExternalAttachmentFiles(
      getUnsharedAttachmentsForDeletion(relocation.sourceAttachments),
    );
    editingPolicyId = null;
    editingPolicyDraft = null;
    render();
    if (relocation.missingAttachments.length > 0) {
      showToast(`Zmiany zapisano, ale nie odnaleziono ${pluralizeAttachments(relocation.missingAttachments.length)} do przeniesienia`, "warning");
    } else if (!removedOldFiles) {
      showToast("Zmiany zapisano, ale część starych plików pozostała w poprzednim folderze", "warning");
    }
  } catch (error) {
    if (policies.includes(activeEditedPolicy)) {
      Object.assign(activeEditedPolicy, rollbackPolicy);
      restoreImportedPolicyTrackingRollbackState(activeEditedPolicy, rollbackImportedTracking);
    }
    await deleteExternalAttachmentFiles(relocation.copiedAttachments);
    markPoliciesRolledBack();
    editingPolicyId = policies.some((item) => item.id === policyId) ? policyId : null;
    render();
    showToast(error?.message || "Nie udało się zapisać zmian");
  } finally {
    if (attachmentOperationActive) finishAttachmentOperation();
  }
});

elements.rows.addEventListener("click", async (event) => {
  const actionElement = event.target.closest("[data-action]");
  if (!actionElement) return;
  const policyId = actionElement.dataset.policyId;
  const action = actionElement.dataset.action;

  if (action === "copy-value") {
    await handleCopyValueClick(actionElement);
  } else if (action === "search-related-policy") {
    showRelatedPolicyInSearch(actionElement.dataset.policyNumber);
  } else if (action === "toggle-attachments") {
    await togglePolicyAttachments(policyId);
  } else if (action === "add-attachments") {
    recordAttachmentPolicyId = policyId;
    elements.recordAttachmentInput.click();
  } else if (action === "download-attachments") {
    await downloadPolicyAttachments(policyId);
  } else if (action === "open-attachment") {
    await openPolicyAttachment(policyId, actionElement.dataset.attachmentId);
  } else if (action === "remove-attachment") {
    await removePolicyAttachment(policyId, actionElement.dataset.attachmentId);
  } else if (action === "open-contact-details") {
    openContactDetailsDialog(policyId);
  } else if (action === "open-client-profile") {
    openClientProfileDialog(policyId);
  } else if (action === "open-vehicle-details") {
    openVehicleDetailsDialog(policyId);
  } else if (action === "open-premium-details") {
    openPremiumDetailsDialog(policyId);
  } else if (action === "calculate-quote") {
    const policy = policies.find((item) => item.id === policyId);
    if (!policy) return;
    openQuoteCalculatorDialog({
      registration: policy.registration,
      pesel: resolveQuotePeselForPolicy(policy),
    });
  } else if (action === "edit") {
    const policy = policies.find((item) => item.id === policyId);
    if (!policy) return;
    expandedPolicyId = null;
    editingPolicyId = policyId;
    editingPolicyDraft = createEditingPolicyDraft(policy);
    render();
    elements.rows.querySelector('[data-edit-form] input[name="clientName"]')?.focus();
  } else if (action === "cancel-edit") {
    editingPolicyId = null;
    editingPolicyDraft = null;
    render();
  } else if (action === "delete") {
    await deletePolicy(policyId);
  } else if (action === "open-termination") {
    await openTerminationNotice(policyId);
  } else if (action === "renewed" || action === "not-renewed") {
    await setRenewalStatus(policyId, action);
  }
});

function isAttachmentFileDrag(event) {
  return [...(event.dataTransfer?.types ?? [])].includes("Files");
}

document.addEventListener("dragover", (event) => {
  if (event.target?.closest?.('input[type="file"]')) return;
  if (isAttachmentFileDrag(event)) event.preventDefault();
});

document.addEventListener("drop", (event) => {
  if (event.target?.closest?.('input[type="file"]')) return;
  if (isAttachmentFileDrag(event)) event.preventDefault();
});

function showAttachmentDropTarget(panel) {
  if (activeAttachmentDropPanel && activeAttachmentDropPanel !== panel) {
    activeAttachmentDropPanel.classList.remove("attachments-panel--dragover");
  }
  activeAttachmentDropPanel = panel;
  panel.classList.add("attachments-panel--dragover");
}

function clearAttachmentDropTarget(panel = activeAttachmentDropPanel) {
  panel?.classList.remove("attachments-panel--dragover");
  if (!panel || activeAttachmentDropPanel === panel) activeAttachmentDropPanel = null;
}

elements.rows.addEventListener("dragenter", (event) => {
  const panel = event.target.closest?.("[data-attachment-drop-policy-id]");
  if (!panel || !isAttachmentFileDrag(event)) return;
  event.preventDefault();
  if (!attachmentOperationActive) showAttachmentDropTarget(panel);
});

elements.rows.addEventListener("dragover", (event) => {
  const panel = event.target.closest?.("[data-attachment-drop-policy-id]");
  if (!panel || !isAttachmentFileDrag(event)) return;
  event.preventDefault();
  event.dataTransfer.dropEffect = attachmentOperationActive ? "none" : "copy";
  if (!attachmentOperationActive) showAttachmentDropTarget(panel);
});

elements.rows.addEventListener("dragleave", (event) => {
  const panel = event.target.closest?.("[data-attachment-drop-policy-id]");
  if (!panel) return;
  const nextTarget = event.relatedTarget;
  if (!(nextTarget instanceof Node) || !panel.contains(nextTarget)) clearAttachmentDropTarget(panel);
});

elements.rows.addEventListener("drop", async (event) => {
  const panel = event.target.closest?.("[data-attachment-drop-policy-id]");
  
  
  const droppedFiles = [...(event.dataTransfer?.files ?? [])];
  if (!panel || droppedFiles.length === 0) return;
  event.preventDefault();
  event.stopPropagation();
  clearAttachmentDropTarget(panel);
  if (attachmentOperationActive) {
    showToast("Poczekaj na zakończenie zapisywania załączników");
    return;
  }
  const category = await requestAttachmentCategory(droppedFiles);
  if (category === null) return;
  await addAttachmentsToPolicy(panel.dataset.attachmentDropPolicyId, droppedFiles, category);
});

elements.rows.addEventListener("input", (event) => {
  if (event.target?.dataset?.autoGrow === "true") {
    resizeAutoGrowingTextarea(event.target);
  }
  const editForm = event.target.closest("[data-edit-form]");
  if (!editForm) return;

  if (event.target.name === "validFrom") {
    const hasManualStartDate = Boolean(event.target.value);
    editForm.dataset.startDateManual = hasManualStartDate ? "true" : "false";
    if (!hasManualStartDate) {
      const validUntilInput = editForm.querySelector('[name="validUntil"]');
      const isTravel = normalize(editForm.querySelector('[name="registration"]')?.value) === normalize("Podróż");
      event.target.value = formatDateForInput(
        isTravel ? calculateTravelStartDate(validUntilInput?.value) : calculateStartDate(validUntilInput?.value),
      );
    }
  } else if (event.target.name === "validUntil" && editForm.dataset.startDateManual !== "true") {
    const startDateInput = editForm.querySelector('[name="validFrom"]');
    if (startDateInput) {
      const isTravel = normalize(editForm.querySelector('[name="registration"]')?.value) === normalize("Podróż");
      startDateInput.value = formatDateForInput(
        isTravel ? calculateTravelStartDate(event.target.value) : calculateStartDate(event.target.value),
      );
    }
  }
  captureEditingPolicyDraft(editForm);
});

function toggleDateRangeFilter() {
  const willOpen = elements.dateRangeFilter.hidden;
  elements.dateRangeFilter.hidden = !willOpen;
  elements.dateFilterToggle.setAttribute("aria-expanded", String(willOpen));
  if (willOpen) elements.dateFilterFrom.focus();
}

function clearSearchFilters() {
  elements.search.value = "";
  elements.dateFilterFrom.value = "";
  elements.dateFilterTo.value = "";
  elements.dateRangeFilter.hidden = true;
  elements.dateFilterToggle.setAttribute("aria-expanded", "false");
  resetPaginationAndRender();
}

function showHomeView(event) {
  event?.preventDefault();

  if (searchRenderTimeoutId !== null) {
    clearTimeout(searchRenderTimeoutId);
    searchRenderTimeoutId = null;
  }

  elements.search.value = "";
  elements.dateFilterFrom.value = "";
  elements.dateFilterTo.value = "";
  elements.dateRangeFilter.hidden = true;
  elements.dateFilterToggle.setAttribute("aria-expanded", "false");

  activeProfileFilter = "";
  renewalsOnly = false;
  renewalWindowDays = RENEWAL_WINDOW_DAYS;
  renewalOwnerExclusions.clear();
  hideRenewedPolicies = false;
  hideInactivePolicies = false;
  sortMode = null;
  sortDirection = "asc";
  insurerSortSelection = null;
  policyTypeSortIndex = -1;

  try {
    globalThis.sessionStorage?.removeItem(PROFILE_FILTER_SESSION_KEY);
  } catch {
  }
  saveRenewalOwnerExclusions();
  refreshProfileSwitcher();
  closeProfileSwitcherMenu();
  resetPaginationAndRender();

  globalThis.requestAnimationFrame(() => {
    globalThis.scrollTo({ top: 0, left: 0, behavior: "auto" });
  });
}

function showRelatedPolicyInSearch(policyNumber) {
  const normalizedPolicyNumber = String(policyNumber ?? "").trim();
  if (!normalizedPolicyNumber) return;
  elements.search.value = normalizedPolicyNumber;
  elements.dateFilterFrom.value = "";
  elements.dateFilterTo.value = "";
  elements.dateRangeFilter.hidden = true;
  elements.dateFilterToggle.setAttribute("aria-expanded", "false");
  renewalsOnly = false;
  expandedPolicyId = null;
  resetPaginationAndRender();
  requestAnimationFrame(() => {
    elements.search.focus();
    elements.search.setSelectionRange?.(normalizedPolicyNumber.length, normalizedPolicyNumber.length);
    elements.search.scrollIntoView({
      behavior: globalThis.matchMedia?.("(prefers-reduced-motion: reduce)").matches ? "auto" : "smooth",
      block: "center",
    });
  });
}

const SEARCH_RENDER_DEBOUNCE_MS = 150;
let searchRenderTimeoutId = null;
elements.search.addEventListener("input", () => {
  if (searchRenderTimeoutId !== null) clearTimeout(searchRenderTimeoutId);
  searchRenderTimeoutId = setTimeout(() => {
    searchRenderTimeoutId = null;
    resetPaginationAndRender();
  }, SEARCH_RENDER_DEBOUNCE_MS);
});
elements.dateFilterToggle.addEventListener("click", toggleDateRangeFilter);
elements.dateFilterFrom.addEventListener("input", resetPaginationAndRender);
elements.dateFilterTo.addEventListener("input", resetPaginationAndRender);
elements.clearSearchFilters.addEventListener("click", clearSearchFilters);
elements.brandLogo.closest(".brand")?.addEventListener("click", showHomeView);
elements.usageGuideButton.addEventListener("click", toggleUsageGuide);
elements.todayDate.addEventListener("click", openCalendarDialog);
elements.closeCalendar.addEventListener("click", closeCalendarDialog);
elements.closeCalendarFooter.addEventListener("click", closeCalendarDialog);
elements.calendarPreviousMonth.addEventListener("click", () => changeCalendarMonth(-1));
elements.calendarNextMonth.addEventListener("click", () => changeCalendarMonth(1));
elements.calendarGoToToday.addEventListener("click", () => selectCalendarDate(formatDateForInput(new Date())));
elements.calendarDays.addEventListener("click", (event) => {
  const dayButton = event.target.closest?.("[data-calendar-date]");
  if (dayButton) selectCalendarDate(dayButton.dataset.calendarDate);
});
elements.calendarTaskForm.addEventListener("submit", addCalendarTasks);
elements.calendarTaskList.addEventListener("click", (event) => {
  const actionButton = event.target.closest?.("[data-calendar-action]");
  if (!actionButton) return;
  if (actionButton.dataset.calendarAction === "toggle") {
    void toggleCalendarTask(actionButton.dataset.calendarTaskId);
  } else if (actionButton.dataset.calendarAction === "delete") {
    void deleteCalendarTask(actionButton.dataset.calendarTaskId);
  }
});
elements.calendarRenewalList.addEventListener("click", (event) => {
  const renewalRow = event.target.closest?.("[data-calendar-renewal-policy-id]");
  if (!renewalRow) return;
  const policyId = renewalRow.dataset.calendarRenewalPolicyId;
  if (!elements.calendarRenewalMenu.hidden && calendarRenewalMenuPolicyId === policyId) {
    closeCalendarRenewalMenu();
    return;
  }
  openCalendarRenewalMenu(renewalRow, policyId);
});
elements.calendarRenewalList.addEventListener("scroll", closeCalendarRenewalMenu, { passive: true });
elements.calendarRenewalMenu.addEventListener("click", (event) => {
  const actionButton = event.target.closest?.("[data-renewal-menu-action]");
  if (!actionButton || actionButton.disabled) return;
  const policy = policies.find((item) => item.id === calendarRenewalMenuPolicyId);
  closeCalendarRenewalMenu();
  if (!policy) return;
  const action = actionButton.dataset.renewalMenuAction;
  if (action === "open") {
    if (!policy.policyNumber) return;
    closeCalendarDialog();
    showRelatedPolicyInSearch(policy.policyNumber);
  } else if (action === "renewed") {
    openCalendarRenewedDialog(policy.id);
  } else if (action === "hide") {
    void hideCalendarRenewalPolicy(policy.id);
  }
});


document.addEventListener("pointerdown", (event) => {
  if (elements.calendarRenewalMenu.hidden) return;
  if (event.target.closest?.("#calendarRenewalMenu") || event.target.closest?.("#calendarRenewalList")) return;
  closeCalendarRenewalMenu();
});
elements.calendarRenewalsHiddenRestore.addEventListener("click", () => {
  void restoreHiddenCalendarRenewals(calendarSelectedDate);
});
elements.calendarRenewedSearch.addEventListener("input", renderCalendarRenewedResults);
elements.calendarRenewedResults.addEventListener("click", (event) => {
  const resultRow = event.target.closest?.("[data-calendar-renewed-successor-id]");
  if (!resultRow) return;
  const policyId = calendarRenewedPolicyId;
  const successorId = resultRow.dataset.calendarRenewedSuccessorId;
  closeCalendarRenewedDialog();
  void markPolicyRenewedWithSuccessor(policyId, successorId);
});
elements.calendarRenewedLater.addEventListener("click", async () => {
  const policyId = calendarRenewedPolicyId;
  closeCalendarRenewedDialog();
  if (!policyId) return;
  await setRenewalStatus(policyId, "renewed");
  renderCalendar();
});
elements.closeCalendarRenewed.addEventListener("click", closeCalendarRenewedDialog);
elements.cancelCalendarRenewed.addEventListener("click", closeCalendarRenewedDialog);
elements.calendarRenewedDialog.addEventListener("close", () => {
  calendarRenewedPolicyId = null;
});
elements.calendarDialog.addEventListener("cancel", (event) => {
  event.preventDefault();
  if (!elements.calendarRenewalMenu.hidden) {
    closeCalendarRenewalMenu();
    return;
  }
  closeCalendarDialog();
});
elements.acceptConfirmDelete.addEventListener("click", () => {
  finishDeleteConfirmation(true);
  elements.confirmDeleteDialog.close();
});
elements.cancelConfirmDelete.addEventListener("click", () => elements.confirmDeleteDialog.close());
elements.closeConfirmDelete.addEventListener("click", () => elements.confirmDeleteDialog.close());
elements.confirmDeleteDialog.addEventListener("close", () => finishDeleteConfirmation(false));
elements.acceptPortfolioPathRepair.addEventListener("click", () => {
  finishPortfolioPathRepairConfirmation(true);
  elements.portfolioPathRepairDialog.close();
});
elements.cancelPortfolioPathRepair.addEventListener("click", () => elements.portfolioPathRepairDialog.close());
elements.closePortfolioPathRepair.addEventListener("click", () => elements.portfolioPathRepairDialog.close());
elements.portfolioPathRepairDialog.addEventListener("close", () => finishPortfolioPathRepairConfirmation(false));
elements.quoteCalculatorButton.addEventListener("click", openQuoteCalculatorDialog);
elements.closeQuoteCalculator.addEventListener("click", closeQuoteCalculatorDialog);
elements.cancelQuoteCalculator.addEventListener("click", closeQuoteCalculatorDialog);
elements.stopQuoteCalculation.addEventListener("click", () => {
  void stopQuoteBatch();
});
elements.startManualQuoteCalculation.addEventListener("click", (event) => {
  void startQuoteCalculation(event, { manualMode: true });
});
elements.quoteCalculatorForm.addEventListener("submit", startQuoteCalculation);
elements.quoteResultsList.addEventListener("click", handleQuoteResultCardActivation);
elements.quoteResultsList.addEventListener("keydown", handleQuoteResultCardActivation);
elements.quotePrintOffer.addEventListener("click", openQuotePrintDialog);
elements.closeQuotePrint.addEventListener("click", closeQuotePrintDialog);
elements.cancelQuotePrint.addEventListener("click", closeQuotePrintDialog);
elements.confirmQuotePrint.addEventListener("click", () => void createQuoteOfferPdf());
elements.quotePrintAgencyEdit.addEventListener("click", openAgencyPrintDetailsSettings);
elements.quotePrintSelectAll.addEventListener("click", () => setAllQuotePrintVariants(true));
elements.quotePrintClearAll.addEventListener("click", () => setAllQuotePrintVariants(false));
elements.quotePrintOptionsList.addEventListener("change", handleQuotePrintOptionChange);
elements.quotePrintDialog.addEventListener("cancel", (event) => {
  event.preventDefault();
  closeQuotePrintDialog();
});
elements.quoteArchiveList.addEventListener("click", handleQuoteArchiveActivation);
elements.quoteWartaManualRepair.addEventListener("click", repairQuoteJobManually);
elements.quoteMtuManualRepair.addEventListener("click", repairQuoteJobManually);
elements.quoteGeneraliManualRepair.addEventListener("click", repairQuoteJobManually);
elements.quoteTrastiManualRepair.addEventListener("click", repairQuoteJobManually);
elements.quoteWienerManualRepair.addEventListener("click", repairQuoteJobManually);
elements.quoteCompensaManualRepair.addEventListener("click", repairQuoteJobManually);
elements.quoteAllianzManualRepair.addEventListener("click", repairQuoteJobManually);
elements.quoteClientInfoList.addEventListener("click", copyQuoteClientInfoValue);
elements.quoteClientInfoHistory.addEventListener("click", () => void fetchQuoteClientInfoVehicleHistory());
elements.quoteClientInfoEdit.addEventListener("click", openQuoteClientInfoVehicleEdit);
elements.quoteClientCardAdd.addEventListener("click", () => void addQuoteClientCardRecord());
elements.quoteClientCardName.addEventListener("keydown", (event) => {
  if (event.key !== "Enter") return;
  
  event.preventDefault();
  void addQuoteClientCardRecord();
});
elements.quoteRegistration.addEventListener("input", () => {
  if (quoteCalculationActive || quoteCancellationPending) return;
  elements.quoteRegistration.value = normalizeQuoteRegistration(elements.quoteRegistration.value);
  clearQuoteDisplayedContext();
  renderQuoteClientInfo();
  setQuoteCalculatorError();
  renderQuoteArchiveList().catch(() => {});
});
elements.quotePesel.addEventListener("input", () => {
  if (quoteCalculationActive || quoteCancellationPending) return;
  elements.quotePesel.value = normalizeQuotePesel(elements.quotePesel.value);
  clearQuoteDisplayedContext();
  renderQuoteClientInfo();
  setQuoteCalculatorError();
});
elements.quoteCalculatorDialog.addEventListener("cancel", (event) => {
  event.preventDefault();
  closeQuoteCalculatorDialog();
});
elements.settingsGear.addEventListener("click", openSettingsDialog);
elements.screenLockButton.addEventListener("click", () => void lockApplicationScreen());
elements.downloadApplicationUpdate.addEventListener("click", () => {
  if (elements.applicationUpdateRow.dataset.state === "error") void refreshApplicationUpdateStatus();
  else void downloadApplicationUpdate();
});
elements.licenseBannerAction.addEventListener("click", () => {
  if (licenseGuardState.stan === "brak") {
    openSettingsDialog();
    setSettingsTab("agency");
    setLicenseFormVisible(true, { focus: true });
    return;
  }
  void forceLicenseRefresh();
});
elements.licenseToggleForm.addEventListener("click", () => setLicenseFormVisible(true, { focus: true }));
elements.licenseCancel.addEventListener("click", () => setLicenseFormVisible(false));
elements.licenseForm.addEventListener("submit", (event) => {
  event.preventDefault();
  void saveLicenseCredentials();
});
elements.licenseRemove.addEventListener("click", () => void removeLicenseCredentials());
elements.closeSettings.addEventListener("click", closeSettingsDialog);
elements.cancelSettings.addEventListener("click", closeSettingsDialog);
elements.saveSettings.addEventListener("click", saveSettingsChanges);
elements.settingsApplicationTab.addEventListener("click", () => setSettingsTab("application"));
elements.settingsUserTab.addEventListener("click", () => setSettingsTab("user"));
elements.settingsInterfaceTab.addEventListener("click", () => setSettingsTab("interface"));
elements.settingsPrintDetailsTab.addEventListener("click", () => setSettingsTab("print-details"));
elements.settingsAgencyTab.addEventListener("click", () => setSettingsTab("agency"));
elements.settingsApplicationTab.addEventListener("keydown", handleSettingsTabKeydown);
elements.settingsUserTab.addEventListener("keydown", handleSettingsTabKeydown);
elements.settingsInterfaceTab.addEventListener("keydown", handleSettingsTabKeydown);
elements.settingsPrintDetailsTab.addEventListener("keydown", handleSettingsTabKeydown);
elements.settingsAgencyTab.addEventListener("keydown", handleSettingsTabKeydown);
elements.addInsurerForm.addEventListener("submit", addInsurerSetting);
elements.insurerSettingsList.addEventListener("input", updateInsurerSetting);
elements.insurerSettingsList.addEventListener("click", handleInsurerSettingsAction);
elements.startEntryOrganizer.addEventListener("click", startEntryOrganizerReview);
elements.openDeletedRecords.addEventListener("click", openDeletedRecordsDialog);
elements.closeDeletedRecords.addEventListener("click", closeDeletedRecordsDialog);
elements.closeDeletedRecordsFooter.addEventListener("click", closeDeletedRecordsDialog);
elements.deleteAllDeletedRecords.addEventListener("click", deleteAllDeletedPolicies);
elements.deletedRecordsList.addEventListener("click", async (event) => {
  const actionButton = event.target.closest?.("[data-deleted-action]");
  if (!actionButton) return;
  if (actionButton.dataset.deletedAction === "restore") {
    await restoreDeletedPolicy(actionButton.dataset.policyId);
  } else if (actionButton.dataset.deletedAction === "delete-permanently") {
    await permanentlyDeleteDeletedPolicy(actionButton.dataset.policyId);
  }
});
elements.deletedRecordsDialog.addEventListener("cancel", (event) => {
  event.preventDefault();
  closeDeletedRecordsDialog();
});
elements.closeEntryOrganizer.addEventListener("click", () => void finishEntryOrganizerReview(false));
elements.skipEntryOrganizerManualStage.addEventListener("click", skipEntryOrganizerManualStage);
elements.rejectEntryOrganizerMatch.addEventListener("click", rejectCurrentEntryOrganizerAction);
elements.confirmEntryOrganizerMatch.addEventListener("click", confirmCurrentEntryOrganizerAction);
elements.entryOrganizerManualPesel.addEventListener("input", normalizeEntryOrganizerManualPeselInput);
elements.entryOrganizerManualPesel.addEventListener("keydown", (event) => {
  if (event.key !== "Enter" || event.isComposing) return;
  event.preventDefault();
  confirmCurrentEntryOrganizerAction();
});
elements.entryOrganizerDialog.addEventListener("cancel", (event) => {
  event.preventDefault();
  if (!entryOrganizerBusy) void finishEntryOrganizerReview(false);
});
elements.lightThemeChoice.addEventListener("click", () => chooseSettingsTheme("light"));
elements.darkThemeChoice.addEventListener("click", () => chooseSettingsTheme("dark"));
elements.standardFontSizeChoice.addEventListener("click", () => chooseSettingsFontSize("standard"));
elements.mediumFontSizeChoice.addEventListener("click", () => chooseSettingsFontSize("medium"));
elements.largeFontSizeChoice.addEventListener("click", () => chooseSettingsFontSize("large"));
elements.showAppearanceDockSetting.addEventListener("change", chooseAppearanceDockSetting);
elements.showStartDateInputSetting.addEventListener("change", chooseStartDateInputSetting);
elements.showUsageGuideSetting.addEventListener("change", chooseUsageGuideSetting);
globalThis.addEventListener("sekagent-radio-settings-change", (event) => {
  void persistRadioSettings(event);
});
elements.collapseAppearanceDock.addEventListener("click", () => {
  setAppearanceDockCollapsed(true);
});
elements.expandAppearanceDock.addEventListener("click", () => {
  setAppearanceDockCollapsed(false);
});
elements.closeAppearanceDock.addEventListener("click", () => {
  void updateQuickAppearance({ showAppearanceDock: false });
});
elements.appearanceThemeToggle.addEventListener("click", () => {
  void updateQuickAppearance({ theme: uiSettings.theme === "dark" ? "light" : "dark" });
});
elements.appearanceFontSizeChoices.forEach((button) => {
  button.addEventListener("click", () => {
    void updateQuickAppearance({ fontSize: button.dataset.appearanceFontSize });
  });
});
elements.toggleWartaPassword.addEventListener("click", toggleWartaPasswordVisibility);
elements.clearWartaCredentials.addEventListener("click", clearWartaSavedPassword);
elements.clearWartaNavigationPath.addEventListener("click", clearWartaSavedNavigationPath);
elements.importWartaNavigationPath.addEventListener("click", () => elements.wartaNavigationPathInput.click());
elements.wartaNavigationPathInput.addEventListener("change", importWartaNavigationPath);
elements.restoreWartaNavigationPath.addEventListener("click", () => restoreSavedNavigationPath({
  insurer: "warta",
  label: "Warty",
  buttonKey: "restoreWartaNavigationPath",
  onRestored: () => {
    wartaPathSaved = true;
    updateWartaNavigationHint();
  },
}));
elements.wartaPasswordSetting.addEventListener("focus", beginEditingWartaPassword);
elements.wartaPasswordSetting.addEventListener("blur", restoreWartaPasswordMask);
elements.wartaPasswordSetting.addEventListener("input", () => {
  if (isWartaPasswordMaskActive() && elements.wartaPasswordSetting.value !== SAVED_CALCULATOR_PASSWORD_MASK) {
    delete elements.wartaPasswordSetting.dataset.savedPasswordMask;
    resetWartaPasswordToggle();
  }
  if (elements.wartaPasswordSetting.value.length > MAX_CALCULATOR_PASSWORD_LENGTH) {
    elements.wartaPasswordSetting.value = elements.wartaPasswordSetting.value.slice(0, MAX_CALCULATOR_PASSWORD_LENGTH);
  }
});
elements.toggleGeneraliPassword.addEventListener("click", toggleGeneraliPasswordVisibility);
elements.clearGeneraliCredentials.addEventListener("click", clearGeneraliSavedPassword);
elements.clearGeneraliNavigationPath.addEventListener("click", clearGeneraliSavedNavigationPath);
elements.importGeneraliNavigationPath.addEventListener("click", () => elements.generaliNavigationPathInput.click());
elements.generaliNavigationPathInput.addEventListener("change", importGeneraliNavigationPath);
elements.restoreGeneraliNavigationPath.addEventListener("click", () => restoreSavedNavigationPath({
  insurer: "generali",
  label: "Generali",
  buttonKey: "restoreGeneraliNavigationPath",
  onRestored: () => {
    generaliPathSaved = true;
    updateGeneraliNavigationHint();
  },
}));
elements.generaliPasswordSetting.addEventListener("focus", beginEditingGeneraliPassword);
elements.generaliPasswordSetting.addEventListener("blur", restoreGeneraliPasswordMask);
elements.generaliPasswordSetting.addEventListener("input", () => {
  if (isGeneraliPasswordMaskActive() && elements.generaliPasswordSetting.value !== SAVED_CALCULATOR_PASSWORD_MASK) {
    delete elements.generaliPasswordSetting.dataset.savedPasswordMask;
    resetGeneraliPasswordToggle();
  }
  if (elements.generaliPasswordSetting.value.length > MAX_CALCULATOR_PASSWORD_LENGTH) {
    elements.generaliPasswordSetting.value = elements.generaliPasswordSetting.value.slice(0, MAX_CALCULATOR_PASSWORD_LENGTH);
  }
});
elements.toggleMtuPassword.addEventListener("click", toggleMtuPasswordVisibility);
elements.clearMtuCredentials.addEventListener("click", clearMtuSavedPassword);
elements.clearMtuNavigationPath.addEventListener("click", clearMtuSavedNavigationPath);
elements.importMtuNavigationPath.addEventListener("click", () => elements.mtuNavigationPathInput.click());
elements.mtuNavigationPathInput.addEventListener("change", importMtuNavigationPath);
elements.restoreMtuNavigationPath.addEventListener("click", () => restoreSavedNavigationPath({
  insurer: "mtu",
  label: "MTU",
  buttonKey: "restoreMtuNavigationPath",
  onRestored: () => {
    mtuPathSaved = true;
    updateMtuNavigationHint();
  },
}));
elements.mtuPasswordSetting.addEventListener("focus", beginEditingMtuPassword);
elements.mtuPasswordSetting.addEventListener("blur", restoreMtuPasswordMask);
elements.mtuPasswordSetting.addEventListener("input", () => {
  if (isMtuPasswordMaskActive() && elements.mtuPasswordSetting.value !== SAVED_CALCULATOR_PASSWORD_MASK) {
    delete elements.mtuPasswordSetting.dataset.savedPasswordMask;
    resetMtuPasswordToggle();
  }
  if (elements.mtuPasswordSetting.value.length > MAX_CALCULATOR_PASSWORD_LENGTH) {
    elements.mtuPasswordSetting.value = elements.mtuPasswordSetting.value.slice(0, MAX_CALCULATOR_PASSWORD_LENGTH);
  }
});
elements.toggleInslyPassword.addEventListener("click", toggleInslyPasswordVisibility);
elements.clearInslyCredentials.addEventListener("click", clearInslySavedPassword);
elements.inslyPasswordSetting.addEventListener("focus", beginEditingInslyPassword);
elements.inslyPasswordSetting.addEventListener("blur", restoreInslyPasswordMask);
elements.inslyPasswordSetting.addEventListener("input", () => {
  if (isInslyPasswordMaskActive() && elements.inslyPasswordSetting.value !== SAVED_CALCULATOR_PASSWORD_MASK) {
    delete elements.inslyPasswordSetting.dataset.savedPasswordMask;
    resetInslyPasswordToggle();
  }
  if (elements.inslyPasswordSetting.value.length > MAX_CALCULATOR_PASSWORD_LENGTH) {
    elements.inslyPasswordSetting.value = elements.inslyPasswordSetting.value.slice(0, MAX_CALCULATOR_PASSWORD_LENGTH);
  }
});
elements.togglePzuPassword.addEventListener("click", togglePzuPasswordVisibility);
elements.clearPzuCredentials.addEventListener("click", clearPzuSavedPassword);
elements.pzuPasswordSetting.addEventListener("focus", beginEditingPzuPassword);
elements.pzuPasswordSetting.addEventListener("blur", restorePzuPasswordMask);
elements.pzuPasswordSetting.addEventListener("input", () => {
  if (isPzuPasswordMaskActive() && elements.pzuPasswordSetting.value !== SAVED_CALCULATOR_PASSWORD_MASK) {
    delete elements.pzuPasswordSetting.dataset.savedPasswordMask;
    resetPzuPasswordToggle();
  }
  if (elements.pzuPasswordSetting.value.length > MAX_CALCULATOR_PASSWORD_LENGTH) {
    elements.pzuPasswordSetting.value = elements.pzuPasswordSetting.value.slice(0, MAX_CALCULATOR_PASSWORD_LENGTH);
  }
});

let mtuPortfolioImportActive = false;


let mtuPortfolioChainTotals = { added: 0, enriched: 0, attached: 0, pdfFailed: 0, pdfEnriched: 0, transferred: 0 };
let mtuPortfolioImportJobId = "";
let mtuPortfolioImportPollTimer = 0;

function setMtuPortfolioImportStatus(message, state = "running") {
  if (!elements.mtuPortfolioImportStatus) return;
  elements.mtuPortfolioImportStatus.hidden = !message;
  elements.mtuPortfolioImportStatus.textContent = message || "";
  elements.mtuPortfolioImportStatus.dataset.state = state;
}

function finishMtuPortfolioImportPolling() {
  mtuPortfolioImportActive = false;
  globalThis.clearTimeout(mtuPortfolioImportPollTimer);
  if (elements.mtuPortfolioImportButton) elements.mtuPortfolioImportButton.disabled = false;
}

function normalizeImportedMtuPortfolioPolicy(entry) {
  
  
  const importedInsurerId = normalizeInsurerId(entry?.insurer);
  const importedInsurer = importedInsurerId === "hestia"
    ? "Hestia"
    : (importedInsurerId === "mtu" ? "MTU" : "");
  return {
    clientName: String(entry?.clientName || "").trim(),
    identityNumber: String(entry?.identityNumber || "").trim(),
    contact: String(entry?.contact || "").trim(),
    riskSummary: String(entry?.riskSummary || "").trim(),
    insurer: importedInsurer,
    policyNumber: String(entry?.policyNumber || "").trim(),
    registration: String(entry?.registration || "").trim() || "Inne",
    vehicleMake: String(entry?.vehicleMake || "").trim(),
    vehicleModel: String(entry?.vehicleModel || "").trim(),
    vin: String(entry?.vin || "").trim(),
    issueDate: String(entry?.issueDate || "").trim(),
    validFrom: String(entry?.validFrom || "").trim(),
    validUntil: String(entry?.validUntil || "").trim(),
    premium: String(entry?.premium || "").trim(),
  };
}

function addPolicyToPortfolioMergeIndex(index, policy) {
  const mergeKey = getPolicyNumberKey(policy);
  if (!mergeKey) return;
  const candidates = index.get(mergeKey) || [];
  candidates.push(policy);
  index.set(mergeKey, candidates);
}

function getPortfolioInsurerKey(policy) {
  return normalizeInsurerId(policy?.insurer);
}

function isMtuHestiaInsurerKey(insurerKey) {
  return insurerKey === "mtu" || insurerKey === "hestia";
}

function arePolicyInsurersCompatibleForEnrichment(existingPolicy, importedPolicy) {
  const existingInsurerKey = getPortfolioInsurerKey(existingPolicy);
  const importedInsurerKey = getPortfolioInsurerKey(importedPolicy);
  if (!importedInsurerKey) return false;
  if (!existingInsurerKey || existingInsurerKey === importedInsurerKey) return true;
  return isMtuHestiaInsurerKey(existingInsurerKey) && isMtuHestiaInsurerKey(importedInsurerKey);
}




function getPolicyPeriodRange(policy) {
  const endDate = parseLocalDate(policy?.validUntil);
  if (!endDate) return null;
  const startDate = getPolicyStartDate(policy);
  if (!startDate || startDate > endDate) return null;
  return { start: startDate.getTime(), end: endDate.getTime() };
}




function policyPeriodsAreDisjoint(firstPolicy, secondPolicy) {
  const firstRange = getPolicyPeriodRange(firstPolicy);
  const secondRange = getPolicyPeriodRange(secondPolicy);
  if (!firstRange || !secondRange) return false;
  return firstRange.end < secondRange.start || secondRange.end < firstRange.start;
}

function policiesHaveCompatibleIdentity(existingPolicy, importedPolicy) {
  if (!existingPolicy || getPolicyNumberKey(existingPolicy) !== getPolicyNumberKey(importedPolicy)) return false;
  if (policyPeriodsAreDisjoint(existingPolicy, importedPolicy)) return false;
  const existingInsurerKey = getPortfolioInsurerKey(existingPolicy);
  const importedInsurerKey = getPortfolioInsurerKey(importedPolicy);
  return Boolean(importedInsurerKey && (!existingInsurerKey || existingInsurerKey === importedInsurerKey));
}



function buildPortfolioMergeKeyIndex(policyRecords = policies) {
  const policiesByMergeKey = new Map();
  for (const policy of policyRecords) addPolicyToPortfolioMergeIndex(policiesByMergeKey, policy);
  return policiesByMergeKey;
}

function resolvePortfolioMergeTarget(policiesByMergeKey, importedPolicy, { allowMtuHestiaCorrection = false } = {}) {
  const mergeKey = getPolicyNumberKey(importedPolicy);
  const candidates = mergeKey ? (policiesByMergeKey.get(mergeKey) || []) : [];
  if (candidates.length === 0) return { mergeKey, status: "new", policy: null, correctInsurer: false };

  const importedInsurerKey = getPortfolioInsurerKey(importedPolicy);
  
  
  
  const samePeriod = (policy) => !policyPeriodsAreDisjoint(policy, importedPolicy);
  const sameInsurer = candidates.filter((policy) => getPortfolioInsurerKey(policy) === importedInsurerKey);
  const sameInsurerSamePeriod = sameInsurer.filter(samePeriod);
  if (sameInsurerSamePeriod.length === 1) {
    return { mergeKey, status: "match", policy: sameInsurerSamePeriod[0], correctInsurer: false };
  }
  if (sameInsurerSamePeriod.length > 1) {
    return { mergeKey, status: "ambiguous", policy: null, correctInsurer: false };
  }
  if (sameInsurer.length > 0) {
    return { mergeKey, status: "new", policy: null, correctInsurer: false };
  }

  const blankInsurer = candidates.filter((policy) => !getPortfolioInsurerKey(policy));
  if (importedInsurerKey && blankInsurer.length === 1 && candidates.length === 1) {
    if (!samePeriod(blankInsurer[0])) {
      return { mergeKey, status: "new", policy: null, correctInsurer: false };
    }
    return {
      mergeKey,
      status: "match",
      policy: blankInsurer[0],
      correctInsurer: allowMtuHestiaCorrection,
    };
  }

  if (allowMtuHestiaCorrection && isMtuHestiaInsurerKey(importedInsurerKey)) {
    const mtuHestiaCandidates = candidates.filter((policy) => isMtuHestiaInsurerKey(getPortfolioInsurerKey(policy)));
    const mtuHestiaSamePeriod = mtuHestiaCandidates.filter(samePeriod);
    if (mtuHestiaSamePeriod.length === 1) {
      return { mergeKey, status: "match", policy: mtuHestiaSamePeriod[0], correctInsurer: true };
    }
    if (mtuHestiaSamePeriod.length > 1) {
      return { mergeKey, status: "ambiguous", policy: null, correctInsurer: false };
    }
    if (mtuHestiaCandidates.length > 0) {
      return { mergeKey, status: "new", policy: null, correctInsurer: false };
    }
  }

  return { mergeKey, status: "cross-insurer", policy: null, correctInsurer: false };
}

function getPortfolioPdfFileKey(policyOrNumber) {
  const key = getPolicyNumberKey(policyOrNumber);
  return key.length >= 4 && key.length <= 64 ? key : "";
}

function hasExternalPolicyPdf(policy) {
  return normalizePolicyAttachments(policy?.attachments).some((attachment) => (
    isExternalAttachment(attachment)
    && attachment.type === "application/pdf"
  ));
}

function createPortfolioPdfIdentity(policy, fallbackInsurer = "") {
  const policyNumber = String(policy?.policyNumber || "").trim();
  if (!policyNumber) return null;
  return {
    insurer: String(policy?.insurer || fallbackInsurer || "").trim(),
    policyNumber,
    validFrom: String(policy?.validFrom || "").trim(),
    validUntil: String(policy?.validUntil || "").trim(),
  };
}

function getPortfolioPdfIdentityKey(identity) {
  if (!identity || typeof identity !== "object") return "";
  const policyNumber = getPolicyNumberKey(identity);
  if (!policyNumber) return "";
  return [
    normalizeInsurerId(identity.insurer),
    policyNumber,
    normalizeMergePolicyEndDate(identity.validFrom),
    normalizeMergePolicyEndDate(identity.validUntil),
  ].join("\u0000");
}

function normalizePortfolioPdfIdentityTransport(value, fallbackInsurer = "") {
  if (typeof value === "string") {
    const legacyPolicyNumber = value.trim();
    return legacyPolicyNumber || null;
  }
  return createPortfolioPdfIdentity(value, fallbackInsurer);
}

function getKnownPortfolioPdfIdentities(policyList) {
  const identities = new Map();
  for (const policy of Array.isArray(policyList) ? policyList : []) {
    const identity = createPortfolioPdfIdentity(policy);
    const key = getPortfolioPdfIdentityKey(identity);
    if (key && !identities.has(key)) identities.set(key, identity);
  }
  return [...identities.values()];
}

function getPortfolioFullReimportRequestFields(options = {}) {
  return options?.fullReimport === true ? { fullReimport: true } : {};
}

function limitPortfolioPdfRequestPayload(payload, maximumBytes = 240 * 1024) {
  const collectionFields = [
    "pdfBacklogPolicyNumbers",
    "knownPolicyNumbers",
    "knownPdfPolicyKeys",
    "skipPdfPolicyNumbers",
    "skipPdfPolicyKeys",
  ];
  const sourceCollections = new Map(collectionFields.map((fieldName) => [
    fieldName,
    Array.isArray(payload?.[fieldName]) ? payload[fieldName] : null,
  ]));
  const limitedPayload = { ...payload };
  collectionFields.forEach((fieldName) => {
    if (sourceCollections.get(fieldName)) limitedPayload[fieldName] = [];
  });
  const byteLength = () => new TextEncoder()
    .encode(JSON.stringify(limitedPayload))
    .byteLength;
  for (const fieldName of collectionFields) {
    const values = sourceCollections.get(fieldName);
    if (!values) continue;
    let low = 0;
    let high = values.length;
    while (low < high) {
      const middle = Math.ceil((low + high) / 2);
      limitedPayload[fieldName] = values.slice(0, middle);
      if (byteLength() <= maximumBytes) low = middle;
      else high = middle - 1;
    }
    limitedPayload[fieldName] = values.slice(0, low);
  }
  return limitedPayload;
}



function getPortfolioPdfSkipKeys(policyList) {
  const withAttachment = new Map();
  const withoutAttachment = new Set();
  for (const policy of policyList) {
    const identity = createPortfolioPdfIdentity(policy);
    const key = getPortfolioPdfIdentityKey(identity);
    if (!key) continue;
    if (hasExternalPolicyPdf(policy)) withAttachment.set(key, identity);
    else withoutAttachment.add(key);
  }
  return [...withAttachment.entries()]
    .filter(([key]) => !withoutAttachment.has(key))
    .map(([, identity]) => identity);
}

function createPortfolioReviewIssue(
  sourceEntry,
  importedPolicy,
  code = "AMBIGUOUS_MERGE",
) {
  const insurer = String(importedPolicy?.insurer || sourceEntry?.insurer || "")
    .trim()
    .slice(0, 120);
  const policyNumber = String(importedPolicy?.policyNumber || sourceEntry?.policyNumber || "")
    .trim()
    .slice(0, 160);
  const sourceId = String(
    sourceEntry?.sourceId
    || sourceEntry?.policyId
    || sourceEntry?.id
    || "",
  ).trim().slice(0, 160);
  const validFrom = String(importedPolicy?.validFrom || sourceEntry?.validFrom || "")
    .trim()
    .slice(0, 40);
  const validUntil = String(importedPolicy?.validUntil || sourceEntry?.validUntil || "")
    .trim()
    .slice(0, 40);
  return {
    code,
    ...(insurer ? { insurer } : {}),
    policyNumber,
    ...(sourceId ? { sourceId } : {}),
    ...(validFrom ? { validFrom } : {}),
    ...(validUntil ? { validUntil } : {}),
  };
}

function getPortfolioMergeConfiguration(insurerKey) {
  switch (insurerKey) {
    case "mtu":
    case "hestia":
      return {
        normalizeEntry: normalizeImportedMtuPortfolioPolicy,
        allowMtuHestiaCorrection: true,
        trackInsurerCorrection: true,
        validateBatch: (entries) => {
          if (entries.some(({ imported }) => !imported.insurer)) {
            throw new Error("Import MTU/Hestia zawiera polisę bez rozpoznanej marki. Nie zapisano żadnych zmian.");
          }
        },
      };
    case "wiener":
      return { normalizeEntry: normalizeImportedWienerPortfolioPolicy };
    case "generali":
      return { normalizeEntry: normalizeImportedGeneraliPortfolioPolicy };
    case "compensa":
      return { normalizeEntry: normalizeImportedCompensaPortfolioPolicy };
    case "allianz":
      return {
        normalizeEntry: normalizeImportedAllianzPortfolioPolicy,
        enrichCreated: (record, sourceEntry) => {
          const secondaryIdentity = String(sourceEntry?.secondaryIdentityNumber || "").trim();
          if (secondaryIdentity) record.secondaryIdentityNumber = secondaryIdentity;
        },
        enrichExisting: (policy, imported, sourceEntry) => {
          const changed = [];
          const secondaryIdentity = String(sourceEntry?.secondaryIdentityNumber || "").trim();
          if (!String(policy?.secondaryIdentityNumber || "").trim() && secondaryIdentity) {
            policy.secondaryIdentityNumber = secondaryIdentity;
            changed.push("secondaryIdentityNumber");
          }
          
          
          
          
          const hasLegacyProductCode = /^(?:MG|GLB)$/i.test(String(policy?.registration || "").trim());
          const nextSnapshot = {
            ...(policy?.lastImportedFieldValues && typeof policy.lastImportedFieldValues === "object"
              ? policy.lastImportedFieldValues
              : {}),
          };
          let snapshotChanged = false;
          if (
            hasLegacyProductCode
            && !isImportedPolicyFieldManuallyProtected(policy, "registration")
          ) {
            policy.registration = "";
            delete nextSnapshot.registration;
            snapshotChanged = true;
            changed.push("registration");
          }
          const importedPremium = normalizeImportedPolicyFieldValue("premium", imported?.premium);
          if (
            hasLegacyProductCode
            && !isImportedPolicyFieldMissing(importedPremium)
            && !isImportedPolicyFieldManuallyProtected(policy, "premium")
            && !areImportedPolicyFieldValuesEqual("premium", policy?.premium, importedPremium)
          ) {
            policy.premium = importedPremium;
            nextSnapshot.premium = importedPremium;
            snapshotChanged = true;
            changed.push("premium");
          }
          if (snapshotChanged) policy.lastImportedFieldValues = nextSnapshot;
          return changed;
        },
      };
    case "trasti":
      return { normalizeEntry: normalizeImportedTrastiPortfolioPolicy };
    case "warta":
      return {
        normalizeEntry: normalizeImportedWartaPortfolioPolicy,
        enrichExisting: (policy, imported) => applyKnownWartaTravelFields(policy, imported),
      };
    case "pzu":
      return {
        normalizeEntry: normalizeImportedPzuPortfolioPolicy,
        enrichCreated: (record, sourceEntry) => {
          const secondaryIdentity = resolvePzuSecondaryIdentity(sourceEntry);
          if (secondaryIdentity) record.secondaryIdentityNumber = secondaryIdentity;
        },
      };
    case "insly":
      return {
        normalizeEntry: normalizeImportedInslyPortfolioPolicy,
        allowMtuHestiaCorrection: true,
        trackInsurerCorrection: true,
        requireCompleteEntry: true,
      };
    default:
      throw new Error(`Brak konfiguracji scalania importu: ${insurerKey}`);
  }
}

function applyConfiguredPortfolioMerge(
  importedEntries,
  configuration,
  { sourceEntries = importedEntries } = {},
) {
  const counts = {
    added: 0,
    enriched: 0,
    unchanged: 0,
    skipped: 0,
    insurerFixed: 0,
    conflicts: 0,
    ambiguous: 0,
  };
  const reviewIssues = [];
  const addedPolicies = [];
  const policiesByMergeKey = buildPortfolioMergeKeyIndex();
  const preparedEntries = (Array.isArray(importedEntries) ? importedEntries : []).map((entry, index) => ({
    sourceEntry: sourceEntries?.[index] || entry,
    imported: configuration.normalizeEntry(entry),
  }));
  configuration.validateBatch?.(preparedEntries);
  preparedEntries.forEach(({ sourceEntry, imported }, index) => {
    if (configuration.documentOnly === true && !imported.clientName) {
      counts.skipped += 1;
      return;
    }
    if (!imported.policyNumber || !imported.clientName || (configuration.requireCompleteEntry && !imported.insurer)) {
      if (configuration.requireCompleteEntry) {
        throw new Error("Import z Superpolisy zawiera niepełny rekord.");
      }
      const reviewIssue = createPortfolioReviewIssue(
        sourceEntry,
        imported,
        "MERGE_REJECTED",
      );
      if (
        !reviewIssue.insurer
        || (!reviewIssue.sourceId && !reviewIssue.policyNumber)
      ) {
        throw new Error(
          "Import zawiera niepełny rekord bez bezpiecznej tożsamości. Nie zapisano żadnych zmian.",
        );
      }
      reviewIssues.push(reviewIssue);
      counts.conflicts += 1;
      counts.skipped += 1;
      return;
    }
    const resolution = resolvePortfolioMergeTarget(
      policiesByMergeKey,
      imported,
      { allowMtuHestiaCorrection: configuration.allowMtuHestiaCorrection === true },
    );
    if (resolution.status === "ambiguous") {
      counts.conflicts += 1;
      counts.ambiguous += 1;
      counts.skipped += 1;
      reviewIssues.push(createPortfolioReviewIssue(sourceEntry, imported));
      return;
    }
    if (resolution.status === "cross-insurer") counts.conflicts += 1;
    const existingPolicy = resolution.policy;
    if (existingPolicy) {
      const insurerCorrectionNeeded = configuration.trackInsurerCorrection === true
        && resolution.correctInsurer
        && getPortfolioInsurerKey(existingPolicy) !== getPortfolioInsurerKey(imported);
      const appliedFieldNames = applyMissingImportedPolicyFields(existingPolicy, imported);
      const additionallyApplied = configuration.enrichExisting?.(
        existingPolicy,
        imported,
        sourceEntry,
      ) || [];
      const uniqueAppliedFieldNames = [...new Set([
        ...appliedFieldNames,
        ...additionallyApplied,
      ])];
      const insurerCorrected = insurerCorrectionNeeded
        && uniqueAppliedFieldNames.includes("insurer")
        && getPortfolioInsurerKey(existingPolicy) === getPortfolioInsurerKey(imported);
      if (insurerCorrected) counts.insurerFixed += 1;
      if (uniqueAppliedFieldNames.length > 0) {
        existingPolicy.updatedAt = Date.now();
        counts.enriched += 1;
      } else {
        counts.unchanged += 1;
      }
      return;
    }
    const importedRecord = createImportedPolicyRecord(imported, [], Date.now() + index);
    configuration.enrichCreated?.(importedRecord, sourceEntry, imported);
    policies.push(importedRecord);
    addPolicyToPortfolioMergeIndex(policiesByMergeKey, importedRecord);
    addedPolicies.push(importedRecord);
    counts.added += 1;
  });
  const linkStates = new Map();
  const linkContext = createRenewalLinkContext();
  addedPolicies
    .sort((first, second) => {
      const firstDate = parseLocalDate(first.validUntil)?.getTime() || 0;
      const secondDate = parseLocalDate(second.validUntil)?.getTime() || 0;
      return firstDate - secondDate;
    })
    .forEach((policy) => linkPolicyToBestRenewalPredecessor(policy, linkStates, linkContext));
  Object.defineProperty(counts, "reviewIssues", {
    value: reviewIssues,
    configurable: true,
    enumerable: false,
  });
  return counts;
}

function applyMtuPortfolioMerge(importedEntries) {
  return applyConfiguredPortfolioMerge(importedEntries, getPortfolioMergeConfiguration("mtu"));
}

const portfolioPdfBatchTransactions = new WeakMap();
const PORTFOLIO_PDF_RECOVERY_JOURNAL_STORAGE_KEY = "iseca-portfolio-pdf-recovery-v1";
const PORTFOLIO_PDF_RECOVERY_JOURNAL_MAX_PATHS = 5000;
const PORTFOLIO_PDF_RECOVERY_JOURNAL_MAX_PATH_LENGTH = 180;
const PORTFOLIO_PDF_RECOVERY_BLOCKED_CODE = "PORTFOLIO_PDF_RECOVERY_BLOCKED";

function createPortfolioPdfRecoveryBlockedError(message = "") {
  const error = new Error(
    message
      || "Nie można bezpiecznie przygotować zapisu plików PDF. Przywróć dostęp do folderu bazy i uruchom import ponownie.",
  );
  error.code = PORTFOLIO_PDF_RECOVERY_BLOCKED_CODE;
  return error;
}

function normalizePortfolioPdfRecoveryPath(relativePath) {
  if (!Array.isArray(relativePath) || relativePath.length !== 4) {
    throw createPortfolioPdfRecoveryBlockedError(
      "Dziennik odzyskiwania PDF zawiera nieprawidłową ścieżkę. Nowe pliki PDF nie zostały zapisane.",
    );
  }
  const normalizedPath = relativePath.map((segment) => String(segment ?? "").trim());
  const containsUnsafeSegment = normalizedPath.some((segment) => (
    !segment
    || segment === "."
    || segment === ".."
    || /[<>:"/\\|?*\u0000-\u001F]/.test(segment)
  ));
  if (
    containsUnsafeSegment
    || normalizedPath[0] !== "Zalaczniki"
    || !/\.pdf$/i.test(normalizedPath.at(-1))
    || normalizedPath.join("\\").length > PORTFOLIO_PDF_RECOVERY_JOURNAL_MAX_PATH_LENGTH
  ) {
    throw createPortfolioPdfRecoveryBlockedError(
      "Dziennik odzyskiwania PDF zawiera nieprawidłową ścieżkę. Nowe pliki PDF nie zostały zapisane.",
    );
  }
  return normalizedPath;
}

function getPortfolioPdfRecoveryPathKey(relativePath) {
  return normalizePortfolioPdfRecoveryPath(relativePath)
    .map((segment) => segment.normalize("NFKC").toLocaleLowerCase("pl"))
    .join("\u0000");
}

function normalizePortfolioPdfRecoveryJournal(paths) {
  if (!Array.isArray(paths)) {
    throw createPortfolioPdfRecoveryBlockedError(
      "Dziennik odzyskiwania PDF jest zbyt duży albo uszkodzony. Nowe pliki PDF nie zostały zapisane.",
    );
  }
  const uniquePaths = new Map();
  for (const path of paths) {
    const normalizedPath = normalizePortfolioPdfRecoveryPath(path);
    uniquePaths.set(getPortfolioPdfRecoveryPathKey(normalizedPath), normalizedPath);
    if (uniquePaths.size > PORTFOLIO_PDF_RECOVERY_JOURNAL_MAX_PATHS) {
      throw createPortfolioPdfRecoveryBlockedError(
        "Dziennik odzyskiwania PDF jest zbyt duży. Najpierw dokończ odzyskiwanie poprzedniego importu.",
      );
    }
  }
  return [...uniquePaths.values()];
}

function getPortfolioPdfRecoveryStorage() {
  let storage = null;
  try {
    storage = globalThis.localStorage;
  } catch {
  }
  if (
    !storage
    || typeof storage.getItem !== "function"
    || typeof storage.setItem !== "function"
  ) {
    throw createPortfolioPdfRecoveryBlockedError(
      "Przeglądarka nie udostępnia trwałego dziennika odzyskiwania PDF. Nowe pliki PDF nie zostały zapisane.",
    );
  }
  return storage;
}

function readPortfolioPdfRecoveryJournal() {
  try {
    const rawJournal = getPortfolioPdfRecoveryStorage().getItem(
      PORTFOLIO_PDF_RECOVERY_JOURNAL_STORAGE_KEY,
    );
    if (rawJournal === null) return [];
    return normalizePortfolioPdfRecoveryJournal(JSON.parse(rawJournal));
  } catch (error) {
    if (error?.code === PORTFOLIO_PDF_RECOVERY_BLOCKED_CODE) throw error;
    throw createPortfolioPdfRecoveryBlockedError(
      "Nie można bezpiecznie odczytać dziennika odzyskiwania PDF. Nowe pliki PDF nie zostały zapisane.",
    );
  }
}

function writePortfolioPdfRecoveryJournal(paths) {
  const normalizedPaths = normalizePortfolioPdfRecoveryJournal(paths);
  const serializedJournal = JSON.stringify(normalizedPaths);
  try {
    const storage = getPortfolioPdfRecoveryStorage();
    storage.setItem(PORTFOLIO_PDF_RECOVERY_JOURNAL_STORAGE_KEY, serializedJournal);
    if (storage.getItem(PORTFOLIO_PDF_RECOVERY_JOURNAL_STORAGE_KEY) !== serializedJournal) {
      throw new Error("Dziennik odzyskiwania PDF nie przeszedł weryfikacji zapisu.");
    }
  } catch (error) {
    if (error?.code === PORTFOLIO_PDF_RECOVERY_BLOCKED_CODE) throw error;
    throw createPortfolioPdfRecoveryBlockedError(
      "Nie można trwale zapisać dziennika odzyskiwania PDF. Nowe pliki PDF nie zostały zapisane.",
    );
  }
  return normalizedPaths;
}

function getPortfolioPdfRecoveryPathsFromAttachments(attachments) {
  if (!Array.isArray(attachments)) {
    throw createPortfolioPdfRecoveryBlockedError(
      "Nie można zarejestrować plików PDF tej transakcji w dzienniku odzyskiwania.",
    );
  }
  return normalizePortfolioPdfRecoveryJournal(attachments.map((attachment) => {
    if (attachment?.storage !== "file") {
      throw createPortfolioPdfRecoveryBlockedError(
        "Nie można zarejestrować plików PDF tej transakcji w dzienniku odzyskiwania.",
      );
    }
    return attachment.relativePath;
  }));
}

function addPortfolioPdfRecoveryAttachments(attachments) {
  const newPaths = getPortfolioPdfRecoveryPathsFromAttachments(attachments);
  const currentPaths = readPortfolioPdfRecoveryJournal();
  return writePortfolioPdfRecoveryJournal([...currentPaths, ...newPaths]);
}

function removePortfolioPdfRecoveryAttachments(attachments) {
  const removedPathKeys = new Set(
    getPortfolioPdfRecoveryPathsFromAttachments(attachments).map(getPortfolioPdfRecoveryPathKey),
  );
  const currentPaths = readPortfolioPdfRecoveryJournal();
  return writePortfolioPdfRecoveryJournal(
    currentPaths.filter((path) => !removedPathKeys.has(getPortfolioPdfRecoveryPathKey(path))),
  );
}

function isPortfolioPdfRecoveryPathReferenced(relativePath, policyRecords = policies) {
  const recoveryPathKey = getPortfolioPdfRecoveryPathKey(relativePath);
  return (Array.isArray(policyRecords) ? policyRecords : []).some((policy) => (
    (Array.isArray(policy?.attachments) ? policy.attachments : []).some((attachment) => {
      try {
        return getPortfolioPdfRecoveryPathKey(attachment?.relativePath) === recoveryPathKey;
      } catch {
        return false;
      }
    })
  ));
}

function createPortfolioPdfRecoveryAttachment(relativePath) {
  const normalizedPath = normalizePortfolioPdfRecoveryPath(relativePath);
  return {
    storage: "file",
    relativePath: normalizedPath,
  };
}

async function readPortfolioPdfRecoveryPersistedPolicies() {
  const activeDataFileHandle = (
    typeof dataFileHandle !== "undefined"
    && dataFileHandle?.getFile
  )
    ? dataFileHandle
    : (
        typeof rememberedDataFileHandle !== "undefined"
        && rememberedDataFileHandle?.getFile
      )
      ? rememberedDataFileHandle
      : null;
  if (!activeDataFileHandle || typeof inspectPoliciesFile !== "function") {
    throw createPortfolioPdfRecoveryBlockedError(
      "Nie można zweryfikować aktualnego pliku bazy przed odzyskaniem PDF. Połącz ponownie plik bazy i uruchom import ponownie.",
    );
  }
  try {
    const inspection = await inspectPoliciesFile(await activeDataFileHandle.getFile());
    if (!Array.isArray(inspection?.documentData?.policies)) {
      throw new Error("Plik bazy nie zawiera listy polis.");
    }
    return inspection.documentData.policies;
  } catch {
    throw createPortfolioPdfRecoveryBlockedError(
      "Nie można bezpiecznie odczytać aktualnego pliku bazy przed odzyskaniem PDF. Przywróć dostęp do pliku i uruchom import ponownie.",
    );
  }
}

function getPortfolioPdfRecoveryReferencedPathKeys(policyRecords) {
  const referencedPathKeys = new Set();
  for (const policy of Array.isArray(policyRecords) ? policyRecords : []) {
    for (const attachment of Array.isArray(policy?.attachments) ? policy.attachments : []) {
      try {
        referencedPathKeys.add(getPortfolioPdfRecoveryPathKey(attachment?.relativePath));
      } catch {
      }
    }
  }
  return referencedPathKeys;
}

function assertPortfolioPdfRecoveryPoliciesCurrent(policyRecords, persistedPolicyRecords) {
  const currentPathKeys = getPortfolioPdfRecoveryReferencedPathKeys(policyRecords);
  if (policyRecords !== policies) {
    for (const pathKey of getPortfolioPdfRecoveryReferencedPathKeys(policies)) {
      currentPathKeys.add(pathKey);
    }
  }
  for (const persistedPathKey of getPortfolioPdfRecoveryReferencedPathKeys(persistedPolicyRecords)) {
    if (!currentPathKeys.has(persistedPathKey)) {
      throw createPortfolioPdfRecoveryBlockedError(
        "Plik bazy na dysku zawiera nowsze odwołanie do PDF niż dane w aplikacji. Dla bezpieczeństwa nie usunięto żadnego pliku. Wczytaj ponownie bieżący plik bazy i uruchom import jeszcze raz.",
      );
    }
  }
}

async function deletePortfolioPdfRecoveryAttachment(
  relativePath,
  policyRecords = policies,
  persistedPolicyRecords = policyRecords,
) {
  if (
    isPortfolioPdfRecoveryPathReferenced(relativePath, policyRecords)
    || (policyRecords !== policies && isPortfolioPdfRecoveryPathReferenced(relativePath, policies))
    || isPortfolioPdfRecoveryPathReferenced(relativePath, persistedPolicyRecords)
  ) {
    return "referenced";
  }
  const attachment = createPortfolioPdfRecoveryAttachment(relativePath);
  let deleted = false;
  try {
    deleted = await deleteExternalAttachmentFiles([attachment]);
  } catch {
    deleted = false;
  }
  if (!deleted) return "failed";
  return "deleted";
}

async function reconcilePortfolioPdfRecoveryJournal(policyRecords = policies) {
  const pendingPaths = readPortfolioPdfRecoveryJournal();
  
  
  
  writePortfolioPdfRecoveryJournal(pendingPaths);
  const persistedPolicyRecords = await readPortfolioPdfRecoveryPersistedPolicies();
  assertPortfolioPdfRecoveryPoliciesCurrent(policyRecords, persistedPolicyRecords);
  for (const relativePath of pendingPaths) {
    const outcome = await deletePortfolioPdfRecoveryAttachment(
      relativePath,
      policyRecords,
      persistedPolicyRecords,
    );
    if (outcome === "failed") {
      throw createPortfolioPdfRecoveryBlockedError(
        "Poprzedni import pozostawił niezatwierdzony plik PDF, którego nie udało się bezpiecznie usunąć. Przywróć dostęp do folderu bazy i uruchom import ponownie.",
      );
    }
    
    
    removePortfolioPdfRecoveryAttachments([
      createPortfolioPdfRecoveryAttachment(relativePath),
    ]);
  }
  return true;
}

async function cleanupPortfolioPdfRecoveryAttachments(attachments, policyRecords = policies) {
  let recoveryAttachments;
  try {
    recoveryAttachments = getPortfolioPdfRecoveryPathsFromAttachments(attachments)
      .map(createPortfolioPdfRecoveryAttachment);
  } catch {
    return false;
  }
  let persistedPolicyRecords;
  try {
    persistedPolicyRecords = await readPortfolioPdfRecoveryPersistedPolicies();
    assertPortfolioPdfRecoveryPoliciesCurrent(policyRecords, persistedPolicyRecords);
  } catch {
    return false;
  }
  let cleanedAll = true;
  for (const attachment of recoveryAttachments) {
    const outcome = await deletePortfolioPdfRecoveryAttachment(
      attachment.relativePath,
      policyRecords,
      persistedPolicyRecords,
    );
    if (outcome === "failed") {
      cleanedAll = false;
      continue;
    }
    try {
      removePortfolioPdfRecoveryAttachments([attachment]);
    } catch {
      
      
      cleanedAll = false;
    }
  }
  return cleanedAll;
}

function capturePortfolioPdfPolicyMutation(policy, policyRecords = policies) {
  return {
    policy,
    policyRecords,
    importedFields: captureImportedPolicyFieldRollbackState(policy),
    buyerTransfer: captureBuyerTransferRollbackState(policy, policyRecords),
    hasAttachments: Object.prototype.hasOwnProperty.call(policy, "attachments"),
    attachments: policy.attachments,
    hasUpdatedAt: Object.prototype.hasOwnProperty.call(policy, "updatedAt"),
    updatedAt: policy.updatedAt,
    hasEnrichmentKey: Object.prototype.hasOwnProperty.call(policy, "attachmentEnrichmentKey"),
    enrichmentKey: policy.attachmentEnrichmentKey,
  };
}

function restorePortfolioPdfPolicyMutation(mutation) {
  const policy = mutation?.policy;
  const policyRecords = Array.isArray(mutation?.policyRecords)
    ? mutation.policyRecords
    : policies;
  
  
  if (!policy || !policyRecords.includes(policy)) return;
  restoreImportedPolicyFieldRollbackState(policy, mutation.importedFields);
  if (POLICY_BUYER_TRANSFER_FEATURE_ENABLED) {
    restoreBuyerTransferRollbackState(policy, mutation.buyerTransfer);
  }
  if (mutation.hasAttachments) policy.attachments = mutation.attachments;
  else delete policy.attachments;
  if (mutation.hasUpdatedAt) policy.updatedAt = mutation.updatedAt;
  else delete policy.updatedAt;
  if (mutation.hasEnrichmentKey) {
    policy.attachmentEnrichmentKey = mutation.enrichmentKey;
  } else {
    delete policy.attachmentEnrichmentKey;
  }
}

async function rollbackPortfolioPdfBatch(pdfResult, { clearUnsavedState = true } = {}) {
  const transaction = portfolioPdfBatchTransactions.get(pdfResult);
  if (!transaction) return true;
  
  
  portfolioPdfBatchTransactions.delete(pdfResult);
  [...transaction.mutations].reverse().forEach(restorePortfolioPdfPolicyMutation);
  const deletedAll = await cleanupPortfolioPdfRecoveryAttachments(transaction.attachments);
  const rolledBackCount = transaction.mutations.length;
  pdfResult.rolledBack = rolledBackCount;
  pdfResult.rollbackCleanupFailed = !deletedAll;
  pdfResult.failed = (Number(pdfResult.failed) || 0) + rolledBackCount;
  pdfResult.attached = 0;
  pdfResult.enriched = 0;
  pdfResult.transferred = 0;
  if (clearUnsavedState && rolledBackCount > 0) markPoliciesRolledBack();
  return deletedAll;
}

async function persistPortfolioPdfBatch(pdfResult, options = {}) {
  if (!pdfResult || pdfResult.attached <= 0) return true;
  let saved = false;
  try {
    saved = await persistPolicies();
  } catch {
    saved = false;
  }
  if (saved) {
    commitPortfolioPdfBatch(pdfResult);
    return true;
  }
  await rollbackPortfolioPdfBatch(pdfResult, options);
  return false;
}

function commitPortfolioPdfBatch(pdfResult) {
  if (!pdfResult || typeof pdfResult !== "object") return true;
  const transaction = portfolioPdfBatchTransactions.get(pdfResult);
  if (!transaction) return true;
  let journalCleared = true;
  try {
    removePortfolioPdfRecoveryAttachments(transaction.attachments);
  } catch {
    
    
    journalCleared = false;
    pdfResult.recoveryJournalCleanupFailed = true;
  }
  portfolioPdfBatchTransactions.delete(pdfResult);
  return journalCleared;
}

function clonePolicyForPortfolioImportPlan(policy) {
  return {
    ...policy,
    ...(Array.isArray(policy?.attachments) ? { attachments: [...policy.attachments] } : {}),
    ...(policy?.lastImportedFieldValues && typeof policy.lastImportedFieldValues === "object"
      ? { lastImportedFieldValues: { ...policy.lastImportedFieldValues } }
      : {}),
    ...(Array.isArray(policy?.manuallyEditedImportedFields)
      ? { manuallyEditedImportedFields: [...policy.manuallyEditedImportedFields] }
      : {}),
    ...(policy?.buyerSnapshot && typeof policy.buyerSnapshot === "object"
      ? { buyerSnapshot: { ...policy.buyerSnapshot } }
      : {}),
  };
}

function createPortfolioImportPlan(
  importedEntries,
  configuration,
  {
    basePolicies = policies,
    sourceEntries = importedEntries,
    documentOnly = false,
  } = {},
) {
  const productionPolicies = policies;
  const baseFingerprint = getPoliciesFingerprint(basePolicies);
  const plannedPolicies = basePolicies.map(clonePolicyForPortfolioImportPlan);
  policies = plannedPolicies;
  try {
    const counts = applyConfiguredPortfolioMerge(
      importedEntries,
      {
        ...configuration.mergeConfiguration,
        documentOnly: documentOnly === true,
      },
      { sourceEntries },
    );
    return {
      basePolicies,
      baseFingerprint,
      nextPolicies: policies,
      counts,
      reviewIssues: Array.isArray(counts.reviewIssues) ? [...counts.reviewIssues] : [],
      changed: counts.added > 0 || counts.enriched > 0,
    };
  } finally {
    policies = productionPolicies;
  }
}

function getPortfolioImportJobId(job) {
  const jobId = String(job?.id || "");
  return /^[a-f0-9]{8}-[a-f0-9]{4}-[1-5][a-f0-9]{3}-[89ab][a-f0-9]{3}-[a-f0-9]{12}$/i.test(jobId)
    ? jobId
    : "";
}

function isPortfolioPdfBacklogOnlyJob(job, insurerKey) {
  return (insurerKey === "mtu" || insurerKey === "hestia")
    && (
      job?.pdfBacklogOnly === true
      || job?.mappingReport?.coverage === "pdf_backlog_only"
    );
}

function createEmptyPortfolioPdfResult() {
  return {
    attached: 0,
    enriched: 0,
    transferred: 0,
    failed: 0,
    total: 0,
    folderUnavailable: false,
    reviewIssues: [],
  };
}

function combinePortfolioReviewIssues(...groups) {
  const issuesByKey = new Map();
  groups.flatMap((group) => (Array.isArray(group) ? group : [])).forEach((issue) => {
    const key = [
      String(issue?.code || ""),
      normalizeInsurerId(issue?.insurer),
      String(issue?.sourceId || issue?.policyId || ""),
      getPolicyNumberKey(issue),
      String(issue?.validFrom || ""),
      String(issue?.validUntil || ""),
    ].join("\u0000");
    issuesByKey.set(key, issue);
  });
  return [...issuesByKey.values()];
}

function getPortfolioImportCoreConfiguration(insurerKey) {
  const shared = {
    insurerKey,
    mergeConfiguration: getPortfolioMergeConfiguration(insurerKey),
    noNewMessage: "Brak nowych polis do pobrania.",
  };
  switch (insurerKey) {
    case "mtu":
      return {
        ...shared,
        displayName: "MTU",
        summarySource: "MTU",
        setStatus: setMtuPortfolioImportStatus,
        pdfEndpoint: "mtu",
        downloadCheckbox: elements.mtuPortfolioDownloadPdfs,
        getChainTotals: () => mtuPortfolioChainTotals,
        setChainTotals: (value) => { mtuPortfolioChainTotals = value; },
        reportMode: "chain-end",
        showReport: showMtuPortfolioReport,
      };
    case "hestia":
      return {
        ...shared,
        displayName: "Ergo Hestia",
        summarySource: "Ergo Hestii",
        setStatus: setHestiaPortfolioImportStatus,
        pdfEndpoint: "hestia",
        downloadCheckbox: elements.hestiaPortfolioDownloadPdfs,
        getChainTotals: () => hestiaPortfolioChainTotals,
        setChainTotals: (value) => { hestiaPortfolioChainTotals = value; },
        reportMode: "chain-end",
        showReport: showHestiaPortfolioReport,
      };
    case "wiener":
      return {
        ...shared,
        displayName: "Wiener",
        summarySource: "Wiener",
        setStatus: setWienerPortfolioImportStatus,
        pdfEndpoint: "wiener",
        downloadCheckbox: elements.wienerPortfolioDownloadPdfs,
        getChainTotals: () => wienerPortfolioChainTotals,
        setChainTotals: (value) => { wienerPortfolioChainTotals = value; },
        reportMode: "chain-end",
        showReport: showWienerPortfolioReport,
      };
    case "generali":
      return {
        ...shared,
        displayName: "Generali",
        summarySource: "Generali",
        setStatus: setGeneraliPortfolioImportStatus,
        pdfEndpoint: "generali",
        downloadCheckbox: elements.generaliPortfolioDownloadPdfs,
        getChainTotals: () => generaliPortfolioChainTotals,
        setChainTotals: (value) => { generaliPortfolioChainTotals = value; },
        reportMode: "chain-end",
        showReport: showGeneraliPortfolioReport,
      };
    case "compensa":
      return {
        ...shared,
        displayName: "Compensa",
        summarySource: "Compensy",
        setStatus: setCompensaPortfolioImportStatus,
        pdfEndpoint: "compensa",
        downloadCheckbox: elements.compensaPortfolioDownloadPdfs,
        getChainTotals: () => compensaPortfolioChainTotals,
        setChainTotals: (value) => { compensaPortfolioChainTotals = value; },
        reportMode: "always",
        showReport: showCompensaPortfolioReport,
      };
    case "allianz":
      return {
        ...shared,
        displayName: "Allianz",
        summarySource: "Allianz",
        setStatus: setAllianzPortfolioImportStatus,
        pdfEndpoint: "allianz",
        downloadCheckbox: elements.allianzPortfolioDownloadPdfs,
        getChainTotals: () => allianzPortfolioChainTotals,
        setChainTotals: (value) => { allianzPortfolioChainTotals = value; },
        reportMode: "always",
        showReport: showAllianzPortfolioReport,
      };
    case "trasti":
      return {
        ...shared,
        displayName: "Trasti",
        summarySource: "Trasti",
        setStatus: setTrastiPortfolioImportStatus,
        pdfEndpoint: "trasti",
        downloadCheckbox: elements.trastiPortfolioDownloadPdfs,
        getChainTotals: () => trastiPortfolioChainTotals,
        setChainTotals: (value) => { trastiPortfolioChainTotals = value; },
        reportMode: "chain-end",
        showReport: showTrastiPortfolioReport,
      };
    case "warta":
      return {
        ...shared,
        displayName: "Warta",
        summarySource: "Warty",
        setStatus: setWartaPortfolioImportStatus,
        pdfEndpoint: "warta",
        downloadCheckbox: elements.wartaPortfolioDownloadPdfs,
        totalsAccumulate: true,
        showToastAfterFinalize: true,
        persistFailureMessage: "Nie udało się zapisać importu Warty. Wszystkie zmiany tej partii zostały cofnięte.",
      };
    case "pzu":
      return {
        ...shared,
        displayName: "PZU",
        summarySource: "PZU",
        setStatus: setPzuPortfolioImportStatus,
        pdfEndpoint: "pzu",
        downloadCheckbox: elements.pzuPortfolioDownloadPdfs,
        totalsAccumulate: true,
        showToastAfterFinalize: true,
        persistFailureMessage: "Nie udało się zapisać importu PZU. Wszystkie zmiany tej partii zostały cofnięte.",
      };
    case "insly":
      return {
        ...shared,
        displayName: "Superpolisa",
        summarySource: "Superpolisy",
        setStatus: setInslyPortfolioImportStatus,
        pdfEndpoint: "insly",
        downloadCheckbox: elements.inslyPortfolioDownloadPdfs,
        totalsAccumulate: true,
        showToastAfterFinalize: true,
        prepareEntries: prepareInslyPortfolioImport,
        getJobBlocker: getInslyPortfolioJobBlocker,
        persistFailureMessage: "Nie udało się zapisać importu z Superpolisy. Wszystkie zmiany tej partii zostały cofnięte.",
      };
    default:
      throw new Error(`Brak konfiguracji rdzenia importu: ${insurerKey}`);
  }
}

async function executePortfolioImportTransaction(
  sourceEntries,
  preparedEntries,
  job,
  configuration,
) {
  let rollbackPolicies = policies;
  let activePlan = null;
  let pdfResult = null;

  const rollbackActiveTransaction = async () => {
    const planWasPublished = policies === activePlan?.nextPolicies;
    if (planWasPublished) policies = rollbackPolicies;
    if (pdfResult) {
      await rollbackPortfolioPdfBatch(pdfResult, { clearUnsavedState: false });
    }
    if (planWasPublished) markPoliciesRolledBack();
  };

  const prepareTransactionPlan = async (basePolicies) => {
    if (pdfResult) {
      await rollbackPortfolioPdfBatch(pdfResult, { clearUnsavedState: false });
    }
    rollbackPolicies = basePolicies;
    const pdfCandidates = configuration.pdfEndpoint
      ? sourceEntries.filter((entry) => entry?.pdfAvailable === true)
      : [];
    if (pdfCandidates.length > 0) {
      configuration.setStatus("Sprawdzanie bezpieczeństwa poprzednich zapisów PDF…");
      await reconcilePortfolioPdfRecoveryJournal(basePolicies);
    }
    activePlan = createPortfolioImportPlan(preparedEntries, configuration, {
      basePolicies,
      sourceEntries,
      documentOnly: isPortfolioPdfBacklogOnlyJob(job, configuration.insurerKey),
    });
    pdfResult = createEmptyPortfolioPdfResult();

    if (pdfCandidates.length > 0) {
      configuration.setStatus(`Podpinanie plików PDF do rekordów… 0/${pdfCandidates.length}`);
      const attachPdfs = configuration.attachPdfs || attachMtuPortfolioPdfs;
      const jobId = getPortfolioImportJobId(job);
      pdfResult = await attachPdfs(
        sourceEntries,
        (done, total, attached) => {
          configuration.setStatus(
            `Podpinanie plików PDF do rekordów… ${done}/${total} (zapisano ${attached})`,
          );
        },
        `/api/${configuration.pdfEndpoint}/portfolio/pdf/${encodeURIComponent(jobId)}`,
        configuration.resolvePdfFileKey || getOpaquePortfolioPdfFileKey,
        activePlan.nextPolicies,
      );
    }
    return true;
  };

  
  
  
  const prepareStableTransactionPlan = async () => {
    for (let attempt = 0; attempt < 3; attempt += 1) {
      const basePolicies = policies;
      await prepareTransactionPlan(basePolicies);
      if (
        policies === basePolicies
        && getPoliciesFingerprint(basePolicies) === activePlan.baseFingerprint
      ) {
        return true;
      }
    }
    throw new Error(
      "Baza zmieniła się podczas przygotowywania importu. Nie zapisano tej partii; uruchom ją ponownie.",
    );
  };

  try {
    await prepareStableTransactionPlan();
  } catch (error) {
    await rollbackActiveTransaction();
    return {
      persisted: false,
      error,
      counts: activePlan?.counts || null,
      reviewIssues: combinePortfolioReviewIssues(
        activePlan?.reviewIssues,
        pdfResult?.reviewIssues,
      ),
      pdfResult: pdfResult || createEmptyPortfolioPdfResult(),
    };
  }

  const hasChanges = activePlan.changed || pdfResult.attached > 0;
  if (!hasChanges) {
    commitPortfolioPdfBatch(pdfResult);
    return {
      persisted: true,
      counts: activePlan.counts,
      reviewIssues: combinePortfolioReviewIssues(
        activePlan.reviewIssues,
        pdfResult.reviewIssues,
      ),
      pdfResult,
    };
  }

  const persist = configuration.persistPolicies || persistPolicies;
  let persisted = false;
  try {
    
    
    
    policies = activePlan.nextPolicies;
    persisted = await persist({
      reapplyAfterConflict: async () => {
        await prepareStableTransactionPlan();
        policies = activePlan.nextPolicies;
        return true;
      },
      reapplyFailureMessage: "Nie udało się ponownie nałożyć całej transakcji importu na nowszą bazę.",
    });
  } catch (error) {
    await rollbackActiveTransaction();
    return {
      persisted: false,
      error,
      counts: activePlan.counts,
      reviewIssues: combinePortfolioReviewIssues(
        activePlan.reviewIssues,
        pdfResult.reviewIssues,
      ),
      pdfResult,
    };
  }
  if (!persisted) {
    await rollbackActiveTransaction();
    return {
      persisted: false,
      counts: activePlan.counts,
      reviewIssues: combinePortfolioReviewIssues(
        activePlan.reviewIssues,
        pdfResult.reviewIssues,
      ),
      pdfResult,
    };
  }

  commitPortfolioPdfBatch(pdfResult);
  return {
    persisted: true,
    counts: activePlan.counts,
    reviewIssues: combinePortfolioReviewIssues(
      activePlan.reviewIssues,
      pdfResult.reviewIssues,
    ),
    pdfResult,
  };
}

function addPortfolioChainTotals(totals, counts, pdfResult) {
  const additions = {
    added: counts.added,
    enriched: counts.enriched,
    attached: pdfResult.attached,
    pdfFailed: pdfResult.failed,
    pdfEnriched: Number(pdfResult.enriched) || 0,
    transferred: Number(pdfResult.transferred) || 0,
  };
  Object.entries(additions).forEach(([fieldName, value]) => {
    if (Object.prototype.hasOwnProperty.call(totals, fieldName)) {
      totals[fieldName] += Number(value) || 0;
    }
  });
  return totals;
}

function resetPortfolioChainTotals(totals) {
  return Object.fromEntries(Object.keys(totals).map((fieldName) => [fieldName, 0]));
}

function reportPortfolioImportCoreResult(
  importedEntries,
  pdfQueueRemaining,
  job,
  configuration,
  result,
) {
  const counts = result.counts || {
    added: 0,
    enriched: 0,
    conflicts: 0,
    ambiguous: 0,
  };
  const pdfResult = result.pdfResult || createEmptyPortfolioPdfResult();
  const persistFailed = result.persisted !== true;
  const recoveryFailureMessage = result.error?.code === PORTFOLIO_PDF_RECOVERY_BLOCKED_CODE
    ? String(result.error.message || "")
    : "";
  const failureMessage = recoveryFailureMessage
    || configuration.persistFailureMessage
    || `Nie udało się zapisać importu ${configuration.displayName}. Wszystkie zmiany tej partii zostały cofnięte.`;
  const pdfSummaryPart = pdfResult.attached > 0
    ? ` Podpięto plików PDF: ${pdfResult.attached}.`
    : "";
  const summary = `Import z ${configuration.summarySource} zakończony. Zaimportowano: ${counts.added}, zaktualizowano: ${counts.enriched}.${pdfSummaryPart}${describePortfolioMergeConflicts(counts)}`;
  const pdfReport = buildPortfolioPdfReport(
    importedEntries,
    pdfResult,
    configuration.downloadCheckbox,
    pdfQueueRemaining,
  );
  const pdfHint = configuration.pdfEndpoint ? describePortfolioPdfReport(pdfReport) : "";
  const retryHint = describePortfolioPdfRetryStatus(job?.pdfRetry);
  const warning = counts.conflicts > 0
    || job?.pdfRetry?.circuitOpen === true
    || job?.pdfRetry?.manualRetryAvailable === true;
  configuration.setStatus(
    persistFailed
      ? failureMessage
      : `${summary}${pdfHint ? ` ${pdfHint}` : ""}${retryHint ? ` ${retryHint}` : ""}`,
    persistFailed ? "error" : (warning ? "warning" : "success"),
  );
  reportDiagnosticsEvent("scalanie-importu", {
    zrodlo: configuration.insurerKey,
    dodane: result.persisted ? counts.added : 0,
    zaktualizowane: result.persisted ? counts.enriched : 0,
    pdfPodpiete: result.persisted ? pdfResult.attached : 0,
    pdfNieudane: pdfResult.failed,
    niejednoznaczne: counts.ambiguous || 0,
    zapisNieudany: persistFailed,
  });

  if (result.persisted) {
    if (typeof configuration.getChainTotals === "function") {
      const totals = addPortfolioChainTotals(
        configuration.getChainTotals(),
        counts,
        pdfResult,
      );
      configuration.setChainTotals(totals);
      notePortfolioImportTotals(configuration.insurerKey, totals);
      const chainWillContinue = configuration.downloadCheckbox?.checked === true
        && Number(pdfQueueRemaining) > 0
        && job?.pdfRetry?.circuitOpen !== true
        && Number(job?.pdfRetry?.succeeded) > 0;
      if (
        configuration.reportMode === "always"
        || (configuration.reportMode === "chain-end" && !chainWillContinue)
      ) {
        configuration.showReport?.(
          { ...counts, added: totals.added, enriched: totals.enriched },
          false,
          {
            ...pdfReport,
            attached: totals.attached || 0,
            failed: totals.pdfFailed || 0,
            enriched: totals.pdfEnriched || 0,
            transferred: totals.transferred || 0,
          },
          job?.pdfRetry,
        );
        configuration.setChainTotals(resetPortfolioChainTotals(totals));
      }
    } else {
      notePortfolioImportTotals(
        configuration.insurerKey,
        { added: counts.added, enriched: counts.enriched, attached: pdfResult.attached },
        { accumulate: configuration.totalsAccumulate === true },
      );
    }
  } else {
    configuration.showReport?.(counts, true, pdfReport, job?.pdfRetry);
  }

  if (configuration.showToastAfterFinalize) {
    showToast(
      persistFailed
        ? failureMessage
        : summary,
      persistFailed ? "error" : (warning ? "warning" : "success"),
    );
  }
}

async function runPortfolioImportCore(
  importedEntries,
  pdfQueueRemaining = null,
  job = null,
  configuration,
) {
  if (!Array.isArray(importedEntries) || importedEntries.length === 0) {
    const message = `Import zakończył się, ale lista polis z ${configuration.summarySource} była pusta.`;
    configuration.setStatus(message, "error");
    showToast(`Import ${configuration.displayName} nie zwrócił żadnych polis`, "error");
    return false;
  }
  const blocker = configuration.getJobBlocker?.(job);
  if (blocker) {
    configuration.setStatus(blocker, "error");
    showToast(blocker, "error");
    return false;
  }

  let preparedEntries;
  try {
    preparedEntries = configuration.prepareEntries
      ? configuration.prepareEntries(importedEntries)
      : importedEntries;
  } catch (error) {
    const message = error?.message || `Nie można potwierdzić kompletności importu ${configuration.displayName}.`;
    configuration.setStatus(message, "error");
    showToast(message, "error");
    return false;
  }

  const result = await executePortfolioImportTransaction(
    importedEntries,
    preparedEntries,
    job,
    configuration,
  );
  (configuration.renderApp || render)();
  reportPortfolioImportCoreResult(
    importedEntries,
    pdfQueueRemaining,
    job,
    configuration,
    result,
  );
  return result.persisted ? result : false;
}

function normalizeAllianzClientNameKey(value) {
  return String(value || "")
    .normalize("NFD")
    .replace(/[\u0300-\u036f]/g, "")
    .toLocaleLowerCase("pl")
    .replace(/[^a-z0-9]+/g, "");
}

function applyAllianzClientNameFromPdf(policy, parsedPolicy) {
  if (
    getPortfolioInsurerKey(policy) !== "allianz"
    || getPortfolioInsurerKey(parsedPolicy) !== "allianz"
  ) {
    return [];
  }
  const currentName = String(policy?.clientName || "").replace(/\s+/g, " ").trim();
  const parsedName = String(parsedPolicy?.clientName || "").replace(/\s+/g, " ").trim();
  if (
    !currentName
    || currentName.split(/\s+/).length !== 1
    || parsedName.split(/\s+/).length < 2
  ) {
    return [];
  }
  const currentKey = normalizeAllianzClientNameKey(currentName);
  const parsedKey = normalizeAllianzClientNameKey(parsedName);
  if (!currentKey || !parsedKey.includes(currentKey)) return [];
  policy.clientName = parsedName.slice(0, 160);
  return ["clientName"];
}

function applyAllianzLegacyRegistrationFromPdf(policy, parsedPolicy) {
  if (
    getPortfolioInsurerKey(policy) !== "allianz"
    || getPortfolioInsurerKey(parsedPolicy) !== "allianz"
    || isImportedPolicyFieldManuallyProtected(policy, "registration")
  ) {
    return [];
  }
  const currentRegistration = normalizeRegistration(policy?.registration);
  const parsedRegistration = normalizeRegistration(parsedPolicy?.registration);
  if (
    !/^(?:MG|GLB)$/i.test(currentRegistration)
    || !parsedRegistration
    || /^(?:MG|GLB)$/i.test(parsedRegistration)
  ) {
    return [];
  }
  policy.registration = parsedRegistration;
  policy.lastImportedFieldValues = {
    ...(policy?.lastImportedFieldValues && typeof policy.lastImportedFieldValues === "object"
      ? policy.lastImportedFieldValues
      : {}),
    registration: parsedRegistration,
  };
  return ["registration"];
}

async function attachMtuPortfolioPdfs(
  importedEntries,
  onProgress,
  pdfEndpointBase = "/api/mtu/portfolio/pdf",
  resolvePdfFileKey = getPortfolioPdfFileKey,
  targetPolicies = policies,
) {
  const candidates = importedEntries.filter((entry) => entry.pdfAvailable);
  const result = {
    attached: 0,
    enriched: 0,
    transferred: 0,
    failed: 0,
    total: candidates.length,
    folderUnavailable: false,
    reviewIssues: [],
  };
  if (candidates.length === 0) return result;
  const transaction = { mutations: [], attachments: [] };
  portfolioPdfBatchTransactions.set(result, transaction);
  const policiesByMergeKey = buildPortfolioMergeKeyIndex(targetPolicies);
  try {
    await ensureAttachmentsBaseDirectory();
  } catch {
    result.folderUnavailable = true;
    return result;
  }
  for (let index = 0; index < candidates.length; index += 1) {
    const entry = candidates[index];
    onProgress?.(index + 1, candidates.length, result.attached);
    const resolution = resolvePortfolioMergeTarget(
      policiesByMergeKey,
      entry,
      { allowMtuHestiaCorrection: true },
    );
    if (resolution.status === "ambiguous") {
      result.reviewIssues.push(
        createPortfolioReviewIssue(entry, entry, "AMBIGUOUS_MERGE"),
      );
      result.failed += 1;
      continue;
    }
    const policy = resolution.status === "match" ? resolution.policy : null;
    const pdfFileKey = resolvePdfFileKey(entry);
    if (!pdfFileKey) {
      result.reviewIssues.push(
        createPortfolioReviewIssue(entry, policy || entry, "MERGE_REJECTED"),
      );
      result.failed += 1;
      continue;
    }
    if (!policy) {
      result.failed += 1;
      continue;
    }
    if (hasExternalPolicyPdf(policy)) continue;
    let storedAttachments = [];
    let mutationRollback = null;
    let recoveryRegistered = false;
    try {
      const response = await apiFetch(`${pdfEndpointBase}/${pdfFileKey}`, { cache: "no-store" });
      if (!response.ok) {
        result.failed += 1;
        continue;
      }
      const blob = await response.blob();
      if (blob.size < 1000) {
        result.failed += 1;
        continue;
      }
      let parsedPolicy = null;
      let buyerTransfer = null;
      if (globalThis.PolicyPdfImporter?.importPolicyPdf) {
        try {
          const parsed = await globalThis.PolicyPdfImporter.importPolicyPdf(blob);
          const parsedNumberKey = getPolicyNumberKey(parsed?.policy);
          const parsedNumberMismatch = Boolean(
            parsedNumberKey
            && parsedNumberKey !== getPolicyNumberKey(policy),
          );
          const parsedInsurerKey = getPortfolioInsurerKey(parsed?.policy);
          const parsedInsurerMismatch = Boolean(
            parsedNumberKey
            && parsedInsurerKey
            && !arePolicyInsurersCompatibleForEnrichment(policy, parsed.policy),
          );
          
          
          const parsedPeriodMismatch = Boolean(
            parsedNumberKey
            && !parsedNumberMismatch
            && !parsedInsurerMismatch
            && policyPeriodsAreDisjoint(policy, parsed.policy),
          );
          if (
            !parsedNumberKey
            || !parsedInsurerKey
            || parsedNumberMismatch
            || parsedInsurerMismatch
            || parsedPeriodMismatch
          ) {
            if (parsedPeriodMismatch) {
              result.reviewIssues.push(
                createPortfolioReviewIssue(entry, policy, "PDF_PERIOD_MISMATCH"),
              );
            } else {
              result.reviewIssues.push(
                createPortfolioReviewIssue(entry, policy, "MERGE_REJECTED"),
              );
            }
            result.failed += 1;
            continue;
          }
          parsedPolicy = parsed.policy;
          buyerTransfer = POLICY_BUYER_TRANSFER_FEATURE_ENABLED
            ? detectPolicyBuyerTransfer(policy, parsedPolicy)
            : null;
        } catch {
          
          
        }
      }
      
      
      
      if (hasExternalPolicyPdf(policy)) continue;
      const attachment = {
        id: globalThis.crypto?.randomUUID?.() ?? `${Date.now()}-${Math.random()}`,
        name: `Polisa ${entry.policyNumber}.pdf`,
        type: "application/pdf",
        size: blob.size,
        sourceFile: blob,
        createdAt: Date.now(),
      };
      let transferApplied = false;
      if (buyerTransfer) {
        mutationRollback = capturePortfolioPdfPolicyMutation(policy, targetPolicies);
        transferApplied = applyPolicyBuyerTransfer(policy, buyerTransfer, targetPolicies);
        if (!transferApplied) {
          result.failed += 1;
          continue;
        }
      }
      
      
      const attachmentClientName = String(
        buyerTransfer?.ownerValues?.clientName || policy.clientName || "",
      ).trim();
      storedAttachments = await writeAttachmentsToFolder(
        attachmentClientName,
        policy.policyNumber,
        [attachment],
        null,
        {
          beforeWrite: (pendingAttachment) => {
            addPortfolioPdfRecoveryAttachments([pendingAttachment]);
            recoveryRegistered = true;
          },
        },
      );
      
      
      
      addPortfolioPdfRecoveryAttachments(storedAttachments);
      recoveryRegistered = true;
      if (!mutationRollback) {
        mutationRollback = capturePortfolioPdfPolicyMutation(policy, targetPolicies);
      }
      policy.attachments = normalizePolicyAttachments([...(policy.attachments || []), ...storedAttachments]);
      policy.updatedAt = Date.now();
      
      
      let enriched = false;
      if (parsedPolicy) {
        const enrichedFields = [
          ...applyAttachmentImportedPolicyFields(policy, parsedPolicy),
          ...applyAllianzClientNameFromPdf(policy, parsedPolicy),
          ...applyAllianzLegacyRegistrationFromPdf(policy, parsedPolicy),
        ];
        enriched = new Set(enrichedFields).size > 0;
      }
      if (globalThis.PolicyPdfImporter?.importPolicyPdf) {
        policy.attachmentEnrichmentKey = getPolicyAttachmentEnrichmentKey(policy);
      }
      result.attached += 1;
      if (transferApplied) result.transferred += 1;
      if (enriched) result.enriched += 1;
      transaction.mutations.push(mutationRollback);
      transaction.attachments.push(...storedAttachments);
    } catch (error) {
      if (mutationRollback) restorePortfolioPdfPolicyMutation(mutationRollback);
      const recoveryAttachments = storedAttachments.length > 0
        ? storedAttachments
        : (Array.isArray(error?.portfolioPdfRecoveryAttachments)
          ? error.portfolioPdfRecoveryAttachments
          : []);
      if (recoveryAttachments.length > 0) {
        
        
        
        if (!recoveryRegistered) {
          try {
            addPortfolioPdfRecoveryAttachments(recoveryAttachments);
            recoveryRegistered = true;
          } catch {
          }
        }
        const cleaned = await cleanupPortfolioPdfRecoveryAttachments(recoveryAttachments);
        if (!cleaned) {
          throw createPortfolioPdfRecoveryBlockedError(
            "Nie udało się bezpiecznie cofnąć lokalnego zapisu PDF. Kolejne pliki zostały zablokowane do czasu odzyskania poprzedniej transakcji.",
          );
        }
      }
      if (error?.code === PORTFOLIO_PDF_RECOVERY_BLOCKED_CODE) {
        throw error;
      }
      result.failed += 1;
    }
  }
  return result;
}




function reportDiagnosticsEvent(rodzaj, dane) {
  try {
    void apiFetch("/api/diagnostyka/zdarzenie", {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({ rodzaj, dane }),
    }).catch(() => {});
  } catch {
  }
}

const PORTFOLIO_POLL_TRANSIENT_FAILURE_LIMIT = 4;
const portfolioImportPollFailures = new Map();

function markPortfolioImportPollSuccessful(jobId) {
  portfolioImportPollFailures.delete(String(jobId || ""));
}

function retryPortfolioImportPoll({ jobId, error, setStatus, schedule }) {
  const normalizedJobId = String(jobId || "");
  const failures = (portfolioImportPollFailures.get(normalizedJobId) || 0) + 1;
  portfolioImportPollFailures.set(normalizedJobId, failures);
  if (failures > PORTFOLIO_POLL_TRANSIENT_FAILURE_LIMIT) {
    portfolioImportPollFailures.delete(normalizedJobId);
    return false;
  }
  const delay = Math.min(4_000, 700 * (2 ** (failures - 1)));
  setStatus(
    `${error?.message || "Chwilowo utracono połączenie z lokalnym serwerem."} Ponawianie odczytu (${failures}/${PORTFOLIO_POLL_TRANSIENT_FAILURE_LIMIT})…`,
    "running",
  );
  schedule(delay);
  return true;
}

function normalizePortfolioReviewIssues(reviewIssues) {
  const allowedCodes = new Set([
    "AMBIGUOUS_MERGE",
    "MERGE_REJECTED",
    "PDF_PERIOD_MISMATCH",
  ]);
  return (Array.isArray(reviewIssues) ? reviewIssues : [])
    .map((issue) => {
      const code = String(issue.code || "").trim().toUpperCase();
      if (!allowedCodes.has(code)) {
        throw new Error("Raport importu zawiera nieobsługiwany kod rekordu do wyjaśnienia.");
      }
      const insurer = String(issue.insurer || "").trim().slice(0, 120);
      const policyNumber = String(issue.policyNumber || "").trim().slice(0, 160);
      const sourceId = String(issue.sourceId || issue.policyId || "").trim().slice(0, 160);
      const validFrom = String(issue.validFrom || "").trim().slice(0, 40);
      const validUntil = String(issue.validUntil || "").trim().slice(0, 40);
      if (!insurer || (!sourceId && !policyNumber)) {
        throw new Error("Raport importu zawiera rekord bez bezpiecznej tożsamości.");
      }
      return {
        code,
        ...(insurer ? { insurer } : {}),
        policyNumber,
        ...(sourceId ? { sourceId } : {}),
        ...(validFrom ? { validFrom } : {}),
        ...(validUntil ? { validUntil } : {}),
      };
    });
}

function createPortfolioAckPayload(reviewIssues) {
  const payload = {
    reviewIssues: normalizePortfolioReviewIssues(reviewIssues),
  };
  const body = JSON.stringify(payload);
  if (new TextEncoder().encode(body).byteLength > 240 * 1024) {
    throw new Error(
      "Raport rekordów wymagających wyjaśnienia jest zbyt duży do bezpiecznego potwierdzenia importu.",
    );
  }
  return body;
}

async function acknowledgePortfolioImportJob(jobId, reviewIssues = []) {
  let lastError = null;
  const body = createPortfolioAckPayload(reviewIssues);
  
  
  for (let attempt = 0; attempt <= PORTFOLIO_POLL_TRANSIENT_FAILURE_LIMIT; attempt += 1) {
    try {
      const response = await apiFetch(`/api/automation/jobs/${encodeURIComponent(jobId)}/consumed`, {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body,
      }, { replayAfterPin: true });
      const data = await response.json();
      if (!response.ok) throw new Error(data?.error || "Serwer odrzucił potwierdzenie zapisu importu.");
      if (data?.job?.status !== "consumed") throw new Error("Serwer nie potwierdził checkpointu importu.");
      return data.job;
    } catch (error) {
      lastError = error;
      if (attempt >= PORTFOLIO_POLL_TRANSIENT_FAILURE_LIMIT) break;
      await new Promise((resolve) => globalThis.setTimeout(resolve, Math.min(2_000, 250 * (2 ** attempt))));
    }
  }
  throw lastError || new Error("Nie udało się potwierdzić zapisu importu.");
}






const portfolioPdfAutoRunCounters = new Map();
const PORTFOLIO_PDF_AUTO_RUN_LIMIT = 60;

function scheduleNextPortfolioPdfRun({
  insurerKey,
  job,
  downloadCheckbox,
  continueImport,
  setStatus,
}) {
  if (typeof continueImport !== "function" || !insurerKey) return false;
  const queueRemaining = Number.isFinite(job?.pdfQueueRemaining) ? job.pdfQueueRemaining : 0;
  const succeeded = Number.isFinite(job?.pdfRetry?.succeeded) ? job.pdfRetry.succeeded : 0;
  if (
    downloadCheckbox?.checked !== true
    || queueRemaining <= 0
    || succeeded <= 0
    || job?.pdfRetry?.circuitOpen === true
  ) {
    
    
    portfolioPdfAutoRunCounters.delete(insurerKey);
    return false;
  }
  const runs = (portfolioPdfAutoRunCounters.get(insurerKey) || 0) + 1;
  if (runs > PORTFOLIO_PDF_AUTO_RUN_LIMIT) {
    portfolioPdfAutoRunCounters.delete(insurerKey);
    return false;
  }
  portfolioPdfAutoRunCounters.set(insurerKey, runs);
  setStatus(`Partia plików zapisana. W kolejce zostało ${queueRemaining} plików - za chwilę pobiorę kolejną partię…`);
  globalThis.setTimeout(() => {
    Promise.resolve(continueImport()).catch(() => {});
  }, 4000);
  return true;
}





let portfolioFinalizeQueue = Promise.resolve();

function finishCompletedPortfolioImport(request) {
  const task = portfolioFinalizeQueue.then(() => finishCompletedPortfolioImportExclusive(request));
  portfolioFinalizeQueue = task.then(() => {}, () => {});
  return task;
}

async function finishCompletedPortfolioImportExclusive({
  job,
  finalizeImport,
  setStatus,
  noNewMessage,
  insurerKey,
  downloadCheckbox,
  continueImport,
}) {
  let reviewIssues = [];
  if (job.noNewPolicies === true) {
    setStatus(job.detail ? `${noNewMessage} ${job.detail}` : noNewMessage, "success");
  } else {
    setStatus("Zapisywanie pobranych polis w bazie…");
    const finalizeResult = await finalizeImport(job.policies, job.pdfQueueRemaining, job);
    const persisted = finalizeResult === true || finalizeResult?.persisted === true;
    if (!persisted) return false;
    reviewIssues = Array.isArray(finalizeResult?.reviewIssues)
      ? finalizeResult.reviewIssues
      : [];
  }
  try {
    await acknowledgePortfolioImportJob(job.id, reviewIssues);
    markPortfolioImportPollSuccessful(job.id);
    notePortfolioImportChain(insurerKey, scheduleNextPortfolioPdfRun({
      insurerKey,
      job,
      downloadCheckbox,
      continueImport,
      setStatus,
    }));
    return true;
  } catch (error) {
    setStatus(
      `Polisy są zapisane, ale serwer nie potwierdził zakończenia importu. Nie uruchamiaj kolejnego importu - aplikacja spróbuje odzyskać wynik po odświeżeniu. ${error?.message || ""}`.trim(),
      "error",
    );
    
    
    
    notePortfolioImportAckFailure(insurerKey, error?.message || "");
    return false;
  }
}

function getPortfolioImportRuntimeConfiguration(insurerKey) {
  const common = {
    insurerKey,
    noNewMessage: "Brak nowych polis do pobrania.",
  };
  switch (insurerKey) {
    case "mtu":
      return {
        ...common,
        displayName: "MTU",
        isActive: () => mtuPortfolioImportActive,
        getJobId: () => mtuPortfolioImportJobId,
        setPollTimer: (timer) => { mtuPortfolioImportPollTimer = timer; },
        pollJob: pollMtuPortfolioImportJob,
        finishPolling: finishMtuPortfolioImportPolling,
        finalizeImport: finalizeMtuPortfolioImport,
        setStatus: setMtuPortfolioImportStatus,
        manualRepair: elements.mtuPortfolioManualRepair,
        downloadCheckbox: elements.mtuPortfolioDownloadPdfs,
        createContinuation: (job) => () => startMtuPortfolioImport({
          pdfBacklogOnly: true,
          pdfBacklogPolicyNumbers: Array.isArray(job.pdfQueuePolicyNumbers)
            ? job.pdfQueuePolicyNumbers
            : [],
        }),
      };
    case "hestia":
      return {
        ...common,
        displayName: "Ergo Hestii",
        isActive: () => hestiaPortfolioImportActive,
        getJobId: () => hestiaPortfolioImportJobId,
        setPollTimer: (timer) => { hestiaPortfolioImportPollTimer = timer; },
        pollJob: pollHestiaPortfolioImportJob,
        finishPolling: finishHestiaPortfolioImportPolling,
        finalizeImport: finalizeHestiaPortfolioImport,
        setStatus: setHestiaPortfolioImportStatus,
        manualRepair: elements.hestiaPortfolioManualRepair,
        downloadCheckbox: elements.hestiaPortfolioDownloadPdfs,
        createContinuation: (job) => () => startHestiaPortfolioImport({
          pdfBacklogOnly: true,
          pdfBacklogPolicyNumbers: Array.isArray(job.pdfQueuePolicyNumbers)
            ? job.pdfQueuePolicyNumbers
            : [],
        }),
      };
    case "wiener":
      return {
        ...common,
        displayName: "Wiener",
        isActive: () => wienerPortfolioImportActive,
        getJobId: () => wienerPortfolioImportJobId,
        setPollTimer: (timer) => { wienerPortfolioImportPollTimer = timer; },
        pollJob: pollWienerPortfolioImportJob,
        finishPolling: finishWienerPortfolioImportPolling,
        finalizeImport: finalizeWienerPortfolioImport,
        setStatus: setWienerPortfolioImportStatus,
        manualRepair: elements.wienerPortfolioManualRepair,
        downloadCheckbox: elements.wienerPortfolioDownloadPdfs,
        createContinuation: () => () => startWienerPortfolioImport({ autoContinuation: true }),
      };
    case "generali":
      return {
        ...common,
        displayName: "Generali",
        isActive: () => generaliPortfolioImportActive,
        getJobId: () => generaliPortfolioImportJobId,
        setPollTimer: (timer) => { generaliPortfolioImportPollTimer = timer; },
        pollJob: pollGeneraliPortfolioImportJob,
        finishPolling: finishGeneraliPortfolioImportPolling,
        finalizeImport: finalizeGeneraliPortfolioImport,
        setStatus: setGeneraliPortfolioImportStatus,
        manualRepair: elements.generaliPortfolioManualRepair,
        downloadCheckbox: elements.generaliPortfolioDownloadPdfs,
        createContinuation: () => () => startGeneraliPortfolioImport({ autoContinuation: true }),
      };
    case "compensa":
      return {
        ...common,
        displayName: "Compensa",
        isActive: () => compensaPortfolioImportActive,
        getJobId: () => compensaPortfolioImportJobId,
        setPollTimer: (timer) => { compensaPortfolioImportPollTimer = timer; },
        pollJob: pollCompensaPortfolioImportJob,
        finishPolling: finishCompensaPortfolioImportPolling,
        finalizeImport: finalizeCompensaPortfolioImport,
        setStatus: setCompensaPortfolioImportStatus,
        manualRepair: elements.compensaPortfolioManualRepair,
        downloadCheckbox: elements.compensaPortfolioDownloadPdfs,
        createContinuation: () => () => startCompensaPortfolioImport({ autoContinuation: true }),
      };
    case "allianz":
      return {
        ...common,
        displayName: "Allianz",
        isActive: () => allianzPortfolioImportActive,
        getJobId: () => allianzPortfolioImportJobId,
        setPollTimer: (timer) => { allianzPortfolioImportPollTimer = timer; },
        pollJob: pollAllianzPortfolioImportJob,
        finishPolling: finishAllianzPortfolioImportPolling,
        finalizeImport: finalizeAllianzPortfolioImport,
        setStatus: setAllianzPortfolioImportStatus,
        manualRepair: elements.allianzPortfolioManualRepair,
        downloadCheckbox: null,
        createContinuation: () => () => startAllianzPortfolioImport({ autoContinuation: true }),
      };
    case "trasti":
      return {
        ...common,
        displayName: "Trasti",
        isActive: () => trastiPortfolioImportActive,
        getJobId: () => trastiPortfolioImportJobId,
        setPollTimer: (timer) => { trastiPortfolioImportPollTimer = timer; },
        pollJob: pollTrastiPortfolioImportJob,
        finishPolling: finishTrastiPortfolioImportPolling,
        finalizeImport: finalizeTrastiPortfolioImport,
        setStatus: setTrastiPortfolioImportStatus,
        manualRepair: elements.trastiPortfolioManualRepair,
        downloadCheckbox: elements.trastiPortfolioDownloadPdfs,
        createContinuation: () => () => startTrastiPortfolioImport({ autoContinuation: true }),
      };
    case "warta":
      return {
        ...common,
        displayName: "Warty",
        isActive: () => wartaPortfolioImportActive,
        getJobId: () => wartaPortfolioImportJobId,
        setPollTimer: (timer) => { wartaPortfolioImportPollTimer = timer; },
        pollJob: pollWartaPortfolioImportJob,
        finishPolling: finishWartaPortfolioImportPolling,
        finalizeImport: finalizeWartaPortfolioImport,
        setStatus: setWartaPortfolioImportStatus,
        downloadCheckbox: elements.wartaPortfolioDownloadPdfs,
        createContinuation: () => () => startWartaPortfolioImport(),
      };
    case "pzu":
      return {
        ...common,
        displayName: "PZU",
        isActive: () => pzuPortfolioImportActive,
        getJobId: () => pzuPortfolioImportJobId,
        setPollTimer: (timer) => { pzuPortfolioImportPollTimer = timer; },
        pollJob: pollPzuPortfolioImportJob,
        finishPolling: finishPzuPortfolioImportPolling,
        finalizeImport: finalizePzuPortfolioImport,
        setStatus: setPzuPortfolioImportStatus,
        downloadCheckbox: elements.pzuPortfolioDownloadPdfs,
        createContinuation: () => () => startPzuPortfolioImport(),
      };
    case "insly":
      return {
        ...common,
        displayName: "Superpolisy",
        isActive: () => inslyPortfolioImportActive,
        getJobId: () => inslyPortfolioImportJobId,
        setPollTimer: (timer) => { inslyPortfolioImportPollTimer = timer; },
        pollJob: pollInslyPortfolioImportJob,
        finishPolling: finishInslyPortfolioImportPolling,
        finalizeImport: finalizeInslyPortfolioImport,
        setStatus: setInslyPortfolioImportStatus,
        downloadCheckbox: elements.inslyPortfolioDownloadPdfs,
        createContinuation: () => () => startInslyPortfolioImport(),
        getJobBlocker: getInslyPortfolioJobBlocker,
      };
    default:
      throw new Error(`Brak konfiguracji obsługi importu: ${insurerKey}`);
  }
}

async function applyConfiguredPortfolioImportJobState(job, configuration) {
  if (!job || job.id !== configuration.getJobId()) return;
  notePortfolioImportJob(configuration.insurerKey, job);
  if (job.status === "completed") {
    const blocker = configuration.getJobBlocker?.(job);
    if (blocker) {
      configuration.finishPolling();
      configuration.setStatus(blocker, "error");
      showToast(blocker, "error");
      return false;
    }
    if (configuration.manualRepair) configuration.manualRepair.hidden = true;
    try {
      return await finishCompletedPortfolioImport({
        job,
        finalizeImport: configuration.finalizeImport,
        setStatus: configuration.setStatus,
        noNewMessage: configuration.noNewMessage,
        insurerKey: configuration.insurerKey,
        downloadCheckbox: configuration.downloadCheckbox,
        continueImport: configuration.createContinuation?.(job),
      });
    } catch {
      configuration.setStatus(
        `Nie udało się bezpiecznie zakończyć zapisu importu ${configuration.displayName}.`,
        "error",
      );
      return false;
    } finally {
      configuration.finishPolling();
    }
  }
  if (job.status === "manual_required" || job.status === "error") {
    configuration.finishPolling();
    if (configuration.manualRepair) {
      configuration.manualRepair.hidden = job.manualAvailable !== true;
    }
    configuration.setStatus(`${job.title}${job.detail ? ` - ${job.detail}` : ""}`, "error");
    return;
  }
  configuration.setStatus(`${job.title}${job.detail ? ` - ${job.detail}` : ""}`);
  configuration.setPollTimer(globalThis.setTimeout(configuration.pollJob, 900));
}

async function pollConfiguredPortfolioImportJob(configuration) {
  const jobId = configuration.getJobId();
  if (!configuration.isActive() || !jobId) return;
  try {
    const response = await apiFetch(
      `/api/automation/jobs/${encodeURIComponent(jobId)}`,
      { cache: "no-store" },
    );
    const data = await response.json();
    if (!response.ok) {
      throw new Error(
        data?.error
        || `Nie udało się odczytać stanu importu polis ${configuration.displayName}.`,
      );
    }
    markPortfolioImportPollSuccessful(jobId);
    await applyConfiguredPortfolioImportJobState(data.job, configuration);
  } catch (error) {
    if (retryPortfolioImportPoll({
      jobId,
      error,
      setStatus: configuration.setStatus,
      schedule: (delay) => {
        configuration.setPollTimer(globalThis.setTimeout(configuration.pollJob, delay));
      },
    })) return;
    configuration.finishPolling();
    configuration.setStatus(
      error?.message || "Utracono połączenie z lokalnym serwerem automatyzacji.",
      "error",
    );
  }
}






function buildPortfolioPdfReport(importedEntries, pdfResult, downloadCheckbox, queueRemaining = null) {
  const policiesByMergeKey = buildPortfolioMergeKeyIndex();
  const remaining = (Array.isArray(importedEntries) ? importedEntries : []).filter((entry) => {
    const resolution = resolvePortfolioMergeTarget(
      policiesByMergeKey,
      entry,
      { allowMtuHestiaCorrection: true },
    );
    const policy = resolution.status === "match" ? resolution.policy : null;
    return policy && !hasExternalPolicyPdf(policy);
  }).length;
  return {
    ...(pdfResult || { attached: 0, failed: 0, total: 0 }),
    remaining,
    queueRemaining: Number.isFinite(queueRemaining) ? queueRemaining : null,
    downloadEnabled: downloadCheckbox?.checked === true,
  };
}

function describePortfolioPdfReport(pdfReport) {
  if (!pdfReport || typeof pdfReport.remaining !== "number") return "";
  const transferredPart = POLICY_BUYER_TRANSFER_FEATURE_ENABLED && pdfReport.transferred > 0
    ? `${pdfReport.transferred === 1 ? "1 polisa dotyczy zbytego pojazdu - rekord pokazuje" : `${pdfReport.transferred} polis dotyczy zbytych pojazdów - rekordy pokazują`} pierwotnego właściciela zamiast nabywcy. `
    : "";
  const enrichedPart = `${transferredPart}${pdfReport.enriched > 0
    ? `Z ${pdfReport.enriched === 1 ? "1 pobranego pliku" : `${pdfReport.enriched} pobranych plików`} uzupełniono brakujące dane polis. `
    : ""}`;
  const queuePart = pdfReport.queueRemaining > 0
    ? ` W kolejce czeka jeszcze ${pdfReport.queueRemaining} plików starszych polis - kolejne importy pobiorą je partiami.`
    : "";
  if (pdfReport.remaining > 0 && pdfReport.downloadEnabled) {
    return `${enrichedPart}Bez pliku polisy zostało jeszcze ${pdfReport.remaining} polis z tego importu - uruchom import ponownie, aby pobrać kolejną partię PDF-ów.${queuePart}`;
  }
  if (pdfReport.remaining > 0) {
    return `${enrichedPart}${pdfReport.remaining} polis z tego importu nie ma podpiętego pliku polisy. Zaznacz „Pobieraj też pliki PDF polis” i uruchom import ponownie, aby je pobrać.${queuePart}`;
  }
  if (queuePart) return `${enrichedPart}${queuePart.trim()}`;
  return `${enrichedPart}Wszystkie polisy z tego importu mają podpięty plik polisy.`;
}

function describePortfolioPdfRetryStatus(pdfRetry) {
  if (!pdfRetry || typeof pdfRetry !== "object") return "";
  if (pdfRetry.circuitOpen === true) {
    return "Pobieranie dokumentów zostało bezpiecznie przerwane z powodu błędu sesji, portalu lub zapisu. Lista polis została zachowana; PDF-y można pobrać w kolejnym imporcie.";
  }
  const quarantined = Number.isFinite(pdfRetry.quarantined)
    ? Math.max(0, Math.trunc(pdfRetry.quarantined))
    : 0;
  const backoff = Number.isFinite(pdfRetry.backoff)
    ? Math.max(0, Math.trunc(pdfRetry.backoff))
    : 0;
  if (quarantined > 0) {
    return `${quarantined} ${quarantined === 1 ? "dokument wymaga" : "dokumenty wymagają"} ręcznego wznowienia przed kolejną próbą.`;
  }
  if (backoff > 0) {
    return `${backoff} ${backoff === 1 ? "dokument czeka" : "dokumenty czekają"} na termin bezpiecznej ponownej próby.`;
  }
  return "";
}

function fillPortfolioPdfReportElements(counterElement, infoElement, pdfReport) {
  if (counterElement) counterElement.textContent = String(pdfReport?.attached || 0);
  if (infoElement) {
    const info = describePortfolioPdfReport(pdfReport);
    infoElement.hidden = !info;
    infoElement.textContent = info;
  }
}

function appendPortfolioConflictWarnings(warnings, counts) {
  if (!counts?.conflicts) return;
  const ambiguousPart = counts.ambiguous > 0
    ? ` ${counts.ambiguous} niejednoznacznych rekordów pominięto.`
    : "";
  warnings.push(
    `${counts.conflicts} numerów polis występuje także w innym TU lub wielokrotnie w tym samym TU.`
    + `${ambiguousPart} Dane różnych towarzystw nie zostały ze sobą scalone.`,
  );
}

function describePortfolioMergeConflicts(counts) {
  if (!counts?.conflicts) return "";
  return ` Uwaga: wykryto ${counts.conflicts} konfliktów numeru polisy między TU lub duplikatów; dane nie zostały połączone automatycznie.`;
}

function showMtuPortfolioReport(counts, persistFailed, pdfResult, pdfRetry = null) {
  
  if (isPortfolioImportRunActive()) return;
  const dialog = elements.mtuPortfolioReportDialog;
  if (!dialog?.showModal) return;
  elements.mtuPortfolioReportAdded.textContent = String(counts.added);
  elements.mtuPortfolioReportEnriched.textContent = String(counts.enriched);
  fillPortfolioPdfReportElements(elements.mtuPortfolioReportPdfs, elements.mtuPortfolioReportPdfInfo, pdfResult);
  const warnings = [];
  appendPortfolioConflictWarnings(warnings, counts);
  if (persistFailed) warnings.push("Nie udało się zapisać pliku bazy - cała partia importu została cofnięta.");
  if (pdfResult?.folderUnavailable) warnings.push("Nie podpięto PDF-ów: brak dostępu do folderu bazy. Zezwól na dostęp i uruchom import ponownie.");
  else if (pdfResult?.failed > 0) warnings.push(`Nie udało się podpiąć ${pdfResult.failed} plików PDF (część polis nie ma dostępnego wydruku).`);
  const retryWarning = describePortfolioPdfRetryStatus(pdfRetry);
  if (retryWarning) warnings.push(retryWarning);
  elements.mtuPortfolioReportWarning.hidden = warnings.length === 0;
  elements.mtuPortfolioReportWarning.textContent = warnings.join(" ");
  if (!dialog.open) dialog.showModal();
}

async function finalizeMtuPortfolioImport(importedEntries, pdfQueueRemaining = null, job = null) {
  return runPortfolioImportCore(
    importedEntries,
    pdfQueueRemaining,
    job,
    getPortfolioImportCoreConfiguration("mtu"),
  );
}

async function applyMtuPortfolioImportJobState(job) {
  return applyConfiguredPortfolioImportJobState(
    job,
    getPortfolioImportRuntimeConfiguration("mtu"),
  );
}

async function pollMtuPortfolioImportJob() {
  return pollConfiguredPortfolioImportJob(
    getPortfolioImportRuntimeConfiguration("mtu"),
  );
}

function canUseAgencyInsurerFeature(insurerId, insurerName) {
  if (isInsurerServed(insurerId)) return true;
  showToast(`${insurerName} nie jest zaznaczone jako obsługiwane przez agencję.`, "warning");
  return false;
}

async function startMtuPortfolioImport(options = {}) {
  if (!canUseAgencyInsurerFeature("mtu", "MTU")) return;
  if (mtuPortfolioImportActive) return;
  elements.mtuPortfolioManualRepair.hidden = true;
  if (!(await checkWartaAutomationBridge())) {
    setMtuPortfolioImportStatus("Automatyzacja jest nieaktywna. Uruchom aplikację plikiem „Uruchom Baza Polis.cmd”.", "error");
    return;
  }
  if (!hasMtuCredentials()) {
    setMtuPortfolioImportStatus("Uzupełnij login i hasło MTU powyżej i zapisz ustawienia.", "error");
    return;
  }
  mtuPortfolioImportActive = true;
  elements.mtuPortfolioImportButton.disabled = true;
  const downloadPdfs = elements.mtuPortfolioDownloadPdfs?.checked === true;
  
  
  const mtuPolicies = policies.filter((policy) => policy.insurer === "MTU");
  const skipPolicyNumbers = downloadPdfs ? getPortfolioPdfSkipKeys(mtuPolicies) : [];
  
  
  const knownPolicyNumbers = downloadPdfs
    ? getKnownPortfolioPdfIdentities(mtuPolicies)
    : [];
  
  
  
  const pdfBacklogPolicyNumbers = downloadPdfs && options?.pdfBacklogOnly === true
    && Array.isArray(options?.pdfBacklogPolicyNumbers)
    ? options.pdfBacklogPolicyNumbers
      .map((value) => normalizePortfolioPdfIdentityTransport(value, "MTU"))
      .filter(Boolean)
    : [];
  const pdfBacklogOnly = pdfBacklogPolicyNumbers.length > 0;
  if (!pdfBacklogOnly) mtuPortfolioChainTotals = { added: 0, enriched: 0, attached: 0, pdfFailed: 0, pdfEnriched: 0, transferred: 0 };
  setMtuPortfolioImportStatus(pdfBacklogOnly
    ? "Pobieranie kolejnej partii zaległych PDF-ów z MTU…"
    : downloadPdfs
      ? "Rozpoczynanie importu polis z MTU (z pobieraniem PDF-ów)…"
      : "Rozpoczynanie importu polis z MTU…");
  try {
    const response = await apiFetch("/api/mtu/portfolio", {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify(limitPortfolioPdfRequestPayload({
        username: uiSettings.calculatorAccounts?.mtu?.username || "",
        downloadPdfs,
        ...getPortfolioFullReimportRequestFields(options),
        skipPdfPolicyNumbers: skipPolicyNumbers.slice(0, 5000),
        knownPolicyNumbers: knownPolicyNumbers.slice(0, 10000),
        ...(pdfBacklogOnly
          ? {
            pdfBacklogOnly: true,
            pdfBacklogPolicyNumbers: pdfBacklogPolicyNumbers.slice(0, 10000),
          }
          : {}),
      })),
    });
    const data = await response.json();
    if (!response.ok) throw new Error(data?.error || "Nie udało się rozpocząć importu polis MTU.");
    mtuPortfolioImportJobId = data.job.id;
    await applyMtuPortfolioImportJobState(data.job);
  } catch (error) {
    finishMtuPortfolioImportPolling();
    setMtuPortfolioImportStatus(error?.message || "Nie udało się rozpocząć importu polis MTU.", "error");
  }
}

async function repairMtuPortfolioImportManually() {
  if (mtuPortfolioImportActive || !mtuPortfolioImportJobId) return;
  mtuPortfolioImportActive = true;
  elements.mtuPortfolioImportButton.disabled = true;
  elements.mtuPortfolioManualRepair.hidden = true;
  setMtuPortfolioImportStatus("Otwieranie MTU do poprawienia ścieżki importu…");
  try {
    const response = await apiFetch(`/api/automation/jobs/${encodeURIComponent(mtuPortfolioImportJobId)}/manual`, {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: "{}",
    });
    const data = await response.json();
    if (!response.ok) throw new Error(data?.error || "Nie udało się uruchomić poprawiania ścieżki.");
    await applyMtuPortfolioImportJobState(data.job);
  } catch (error) {
    finishMtuPortfolioImportPolling();
    elements.mtuPortfolioManualRepair.hidden = false;
    setMtuPortfolioImportStatus(error?.message || "Nie udało się uruchomić poprawiania ścieżki.", "error");
  }
}

function updateMtuPortfolioPdfOptions() {
  const enabled = elements.mtuPortfolioDownloadPdfs?.checked === true;
  if (elements.mtuPortfolioPdfOptions) elements.mtuPortfolioPdfOptions.dataset.enabled = enabled ? "true" : "false";
}

elements.mtuPortfolioImportButton.addEventListener("click", startMtuPortfolioImport);
elements.mtuPortfolioManualRepair.addEventListener("click", () => {
  void runConfirmedPortfolioPathRepair("MTU", repairMtuPortfolioImportManually);
});
elements.mtuPortfolioDownloadPdfs?.addEventListener("change", updateMtuPortfolioPdfOptions);
updateMtuPortfolioPdfOptions();
elements.closeMtuPortfolioReport.addEventListener("click", () => elements.mtuPortfolioReportDialog.close());
elements.confirmMtuPortfolioReport.addEventListener("click", () => elements.mtuPortfolioReportDialog.close());
let hestiaPortfolioImportActive = false;


let hestiaPortfolioChainTotals = { added: 0, enriched: 0, attached: 0, pdfFailed: 0, pdfEnriched: 0, transferred: 0 };
let hestiaPortfolioImportJobId = "";
let hestiaPortfolioImportPollTimer = 0;

function setHestiaPortfolioImportStatus(message, state = "running") {
  if (!elements.hestiaPortfolioImportStatus) return;
  elements.hestiaPortfolioImportStatus.hidden = !message;
  elements.hestiaPortfolioImportStatus.textContent = message || "";
  elements.hestiaPortfolioImportStatus.dataset.state = state;
}

function finishHestiaPortfolioImportPolling() {
  hestiaPortfolioImportActive = false;
  globalThis.clearTimeout(hestiaPortfolioImportPollTimer);
  if (elements.hestiaPortfolioImportButton) elements.hestiaPortfolioImportButton.disabled = false;
}

function showHestiaPortfolioReport(counts, persistFailed, pdfResult, pdfRetry = null) {
  
  if (isPortfolioImportRunActive()) return;
  const dialog = elements.hestiaPortfolioReportDialog;
  if (!dialog?.showModal) return;
  elements.hestiaPortfolioReportAdded.textContent = String(counts.added);
  elements.hestiaPortfolioReportEnriched.textContent = String(counts.enriched);
  fillPortfolioPdfReportElements(elements.hestiaPortfolioReportPdfs, elements.hestiaPortfolioReportPdfInfo, pdfResult);
  const warnings = [];
  appendPortfolioConflictWarnings(warnings, counts);
  if (persistFailed) warnings.push("Nie udało się zapisać pliku bazy - cała partia importu została cofnięta.");
  if (pdfResult?.folderUnavailable) warnings.push("Nie podpięto PDF-ów: brak dostępu do folderu bazy. Zezwól na dostęp i uruchom import ponownie.");
  else if (pdfResult?.failed > 0) warnings.push(`Nie udało się podpiąć ${pdfResult.failed} plików PDF (część polis nie ma dostępnego wydruku).`);
  const retryWarning = describePortfolioPdfRetryStatus(pdfRetry);
  if (retryWarning) warnings.push(retryWarning);
  elements.hestiaPortfolioReportWarning.hidden = warnings.length === 0;
  elements.hestiaPortfolioReportWarning.textContent = warnings.join(" ");
  if (!dialog.open) dialog.showModal();
}

async function finalizeHestiaPortfolioImport(importedEntries, pdfQueueRemaining = null, job = null) {
  return runPortfolioImportCore(
    importedEntries,
    pdfQueueRemaining,
    job,
    getPortfolioImportCoreConfiguration("hestia"),
  );
}

async function applyHestiaPortfolioImportJobState(job) {
  return applyConfiguredPortfolioImportJobState(
    job,
    getPortfolioImportRuntimeConfiguration("hestia"),
  );
}

async function pollHestiaPortfolioImportJob() {
  return pollConfiguredPortfolioImportJob(
    getPortfolioImportRuntimeConfiguration("hestia"),
  );
}

async function startHestiaPortfolioImport(options = {}) {
  if (!canUseAgencyInsurerFeature("hestia", "Ergo Hestia")) return;
  if (hestiaPortfolioImportActive) return;
  elements.hestiaPortfolioManualRepair.hidden = true;
  if (!(await checkWartaAutomationBridge())) {
    setHestiaPortfolioImportStatus("Automatyzacja jest nieaktywna. Uruchom aplikację plikiem „Uruchom Baza Polis.cmd”.", "error");
    return;
  }
  if (!hasHestiaCredentials()) {
    setHestiaPortfolioImportStatus("Uzupełnij login i hasło Ergo Hestii powyżej i zapisz ustawienia.", "error");
    return;
  }
  hestiaPortfolioImportActive = true;
  elements.hestiaPortfolioImportButton.disabled = true;
  const downloadPdfs = elements.hestiaPortfolioDownloadPdfs?.checked === true;
  
  
  
  const hestiaPolicies = policies.filter((policy) => policy.insurer === "Hestia");
  const skipPolicyNumbers = downloadPdfs ? getPortfolioPdfSkipKeys(hestiaPolicies) : [];
  
  
  const knownPolicyNumbers = downloadPdfs
    ? getKnownPortfolioPdfIdentities(hestiaPolicies)
    : [];
  
  
  
  
  
  const pdfBacklogPolicyNumbers = downloadPdfs && options?.pdfBacklogOnly === true
    && Array.isArray(options?.pdfBacklogPolicyNumbers)
    ? options.pdfBacklogPolicyNumbers
      .map((value) => normalizePortfolioPdfIdentityTransport(value, "Hestia"))
      .filter(Boolean)
    : [];
  const pdfBacklogOnly = pdfBacklogPolicyNumbers.length > 0;
  if (!pdfBacklogOnly) hestiaPortfolioChainTotals = { added: 0, enriched: 0, attached: 0, pdfFailed: 0, pdfEnriched: 0, transferred: 0 };
  setHestiaPortfolioImportStatus(pdfBacklogOnly
    ? "Pobieranie kolejnej partii zaległych PDF-ów z Ergo Hestii…"
    : downloadPdfs
      ? "Rozpoczynanie importu polis z Ergo Hestii (z pobieraniem PDF-ów)…"
      : "Rozpoczynanie importu polis z Ergo Hestii…");
  try {
    const response = await apiFetch("/api/hestia/portfolio", {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify(limitPortfolioPdfRequestPayload({
        username: uiSettings.calculatorAccounts?.hestia?.username || "",
        downloadPdfs,
        ...getPortfolioFullReimportRequestFields(options),
        skipPdfPolicyNumbers: skipPolicyNumbers.slice(0, 5000),
        knownPolicyNumbers: knownPolicyNumbers.slice(0, 10000),
        ...(pdfBacklogOnly
          ? {
            pdfBacklogOnly: true,
            pdfBacklogPolicyNumbers: pdfBacklogPolicyNumbers.slice(0, 10000),
          }
          : {}),
      })),
    });
    const data = await response.json();
    if (!response.ok) throw new Error(data?.error || "Nie udało się rozpocząć importu polis Ergo Hestii.");
    hestiaPortfolioImportJobId = data.job.id;
    await applyHestiaPortfolioImportJobState(data.job);
  } catch (error) {
    finishHestiaPortfolioImportPolling();
    setHestiaPortfolioImportStatus(error?.message || "Nie udało się rozpocząć importu polis Ergo Hestii.", "error");
  }
}

async function repairHestiaPortfolioImportManually() {
  if (hestiaPortfolioImportActive || !hestiaPortfolioImportJobId) return;
  hestiaPortfolioImportActive = true;
  elements.hestiaPortfolioImportButton.disabled = true;
  elements.hestiaPortfolioManualRepair.hidden = true;
  setHestiaPortfolioImportStatus("Otwieranie Ergo Hestii do poprawienia ścieżki importu…");
  try {
    const response = await apiFetch(`/api/automation/jobs/${encodeURIComponent(hestiaPortfolioImportJobId)}/manual`, {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: "{}",
    });
    const data = await response.json();
    if (!response.ok) throw new Error(data?.error || "Nie udało się uruchomić poprawiania ścieżki.");
    await applyHestiaPortfolioImportJobState(data.job);
  } catch (error) {
    finishHestiaPortfolioImportPolling();
    elements.hestiaPortfolioManualRepair.hidden = false;
    setHestiaPortfolioImportStatus(error?.message || "Nie udało się uruchomić poprawiania ścieżki.", "error");
  }
}

function updateHestiaPortfolioPdfOptions() {
  const enabled = elements.hestiaPortfolioDownloadPdfs?.checked === true;
  if (elements.hestiaPortfolioPdfOptions) elements.hestiaPortfolioPdfOptions.dataset.enabled = enabled ? "true" : "false";
}

elements.hestiaPortfolioImportButton.addEventListener("click", startHestiaPortfolioImport);
elements.hestiaPortfolioManualRepair.addEventListener("click", () => {
  void runConfirmedPortfolioPathRepair("Ergo Hestii", repairHestiaPortfolioImportManually);
});
elements.hestiaPortfolioDownloadPdfs?.addEventListener("change", updateHestiaPortfolioPdfOptions);
updateHestiaPortfolioPdfOptions();
elements.closeHestiaPortfolioReport.addEventListener("click", () => elements.hestiaPortfolioReportDialog.close());
elements.confirmHestiaPortfolioReport.addEventListener("click", () => elements.hestiaPortfolioReportDialog.close());
elements.toggleHestiaPassword.addEventListener("click", toggleHestiaPasswordVisibility);
elements.clearHestiaCredentials.addEventListener("click", clearHestiaSavedPassword);
elements.hestiaPasswordSetting.addEventListener("focus", beginEditingHestiaPassword);
elements.hestiaPasswordSetting.addEventListener("blur", restoreHestiaPasswordMask);
elements.hestiaPasswordSetting.addEventListener("input", () => {
  if (isHestiaPasswordMaskActive() && elements.hestiaPasswordSetting.value !== SAVED_CALCULATOR_PASSWORD_MASK) {
    delete elements.hestiaPasswordSetting.dataset.savedPasswordMask;
    resetHestiaPasswordToggle();
  }
  if (elements.hestiaPasswordSetting.value.length > MAX_CALCULATOR_PASSWORD_LENGTH) {
    elements.hestiaPasswordSetting.value = elements.hestiaPasswordSetting.value.slice(0, MAX_CALCULATOR_PASSWORD_LENGTH);
  }
});


let wienerPortfolioImportActive = false;


let wienerPortfolioChainTotals = { added: 0, enriched: 0, attached: 0, pdfFailed: 0, pdfEnriched: 0, transferred: 0 };
let wienerPortfolioImportJobId = "";
let wienerPortfolioImportPollTimer = 0;


function normalizeImportedWienerPortfolioPolicy(entry) {
  return {
    clientName: String(entry?.clientName || "").trim(),
    identityNumber: String(entry?.identityNumber || "").trim(),
    contact: String(entry?.contact || "").trim(),
    riskSummary: String(entry?.riskSummary || "").trim(),
    insurer: "Wiener",
    policyNumber: String(entry?.policyNumber || "").trim(),
    registration: String(entry?.registration || "").trim() || "Inne",
    vehicleMake: String(entry?.vehicleMake || "").trim(),
    vehicleModel: String(entry?.vehicleModel || "").trim(),
    vin: String(entry?.vin || "").trim(),
    clientAddress: String(entry?.clientAddress || "").trim(),
    issueDate: String(entry?.issueDate || "").trim(),
    validFrom: String(entry?.validFrom || "").trim(),
    validUntil: String(entry?.validUntil || "").trim(),
    premium: String(entry?.premium || "").trim(),
  };
}

function applyWienerPortfolioMerge(importedEntries) {
  return applyConfiguredPortfolioMerge(importedEntries, getPortfolioMergeConfiguration("wiener"));
}

function setWienerPortfolioImportStatus(message, state = "running") {
  if (!elements.wienerPortfolioImportStatus) return;
  elements.wienerPortfolioImportStatus.hidden = !message;
  elements.wienerPortfolioImportStatus.textContent = message || "";
  elements.wienerPortfolioImportStatus.dataset.state = state;
}

function finishWienerPortfolioImportPolling() {
  wienerPortfolioImportActive = false;
  globalThis.clearTimeout(wienerPortfolioImportPollTimer);
  if (elements.wienerPortfolioImportButton) elements.wienerPortfolioImportButton.disabled = false;
}

function showWienerPortfolioReport(counts, persistFailed, pdfResult, pdfRetry = null) {
  
  if (isPortfolioImportRunActive()) return;
  const dialog = elements.wienerPortfolioReportDialog;
  if (!dialog?.showModal) return;
  elements.wienerPortfolioReportAdded.textContent = String(counts.added);
  elements.wienerPortfolioReportEnriched.textContent = String(counts.enriched);
  fillPortfolioPdfReportElements(elements.wienerPortfolioReportPdfs, elements.wienerPortfolioReportPdfInfo, pdfResult);
  const warnings = [];
  appendPortfolioConflictWarnings(warnings, counts);
  if (persistFailed) warnings.push("Nie udało się zapisać pliku bazy - cała partia importu została cofnięta.");
  if (pdfResult?.folderUnavailable) warnings.push("Nie podpięto PDF-ów: brak dostępu do folderu bazy. Zezwól na dostęp i uruchom import ponownie.");
  else if (pdfResult?.failed > 0) warnings.push(`Nie udało się podpiąć ${pdfResult.failed} plików PDF (część polis nie ma dostępnego wydruku).`);
  const retryWarning = describePortfolioPdfRetryStatus(pdfRetry);
  if (retryWarning) warnings.push(retryWarning);
  elements.wienerPortfolioReportWarning.hidden = warnings.length === 0;
  elements.wienerPortfolioReportWarning.textContent = warnings.join(" ");
  if (!dialog.open) dialog.showModal();
}

async function finalizeWienerPortfolioImport(importedEntries, pdfQueueRemaining = null, job = null) {
  return runPortfolioImportCore(
    importedEntries,
    pdfQueueRemaining,
    job,
    getPortfolioImportCoreConfiguration("wiener"),
  );
}

async function applyWienerPortfolioImportJobState(job) {
  return applyConfiguredPortfolioImportJobState(
    job,
    getPortfolioImportRuntimeConfiguration("wiener"),
  );
}

async function pollWienerPortfolioImportJob() {
  return pollConfiguredPortfolioImportJob(
    getPortfolioImportRuntimeConfiguration("wiener"),
  );
}

async function startWienerPortfolioImport(options = {}) {
  if (!canUseAgencyInsurerFeature("wiener", "Wiener")) return;
  if (wienerPortfolioImportActive) return;
  elements.wienerPortfolioManualRepair.hidden = true;
  if (!(await checkWartaAutomationBridge())) {
    setWienerPortfolioImportStatus("Automatyzacja jest nieaktywna. Uruchom aplikację plikiem „Uruchom Baza Polis.cmd”.", "error");
    return;
  }
  if (!hasWienerCredentials()) {
    setWienerPortfolioImportStatus("Uzupełnij login i hasło Wiener powyżej i zapisz ustawienia.", "error");
    return;
  }
  wienerPortfolioImportActive = true;
  elements.wienerPortfolioImportButton.disabled = true;
  const downloadPdfs = elements.wienerPortfolioDownloadPdfs?.checked === true;
  
  
  const wienerPolicies = policies.filter((policy) => policy.insurer === "Wiener");
  const skipPolicyNumbers = downloadPdfs ? getPortfolioPdfSkipKeys(wienerPolicies) : [];
  
  
  const knownPolicyNumbers = downloadPdfs
    ? getKnownPortfolioPdfIdentities(wienerPolicies)
    : [];
  if (options?.autoContinuation !== true) wienerPortfolioChainTotals = { added: 0, enriched: 0, attached: 0, pdfFailed: 0, pdfEnriched: 0, transferred: 0 };
  setWienerPortfolioImportStatus(downloadPdfs
    ? "Rozpoczynanie importu polis z Wiener (z pobieraniem PDF-ów)…"
    : "Rozpoczynanie importu polis z Wiener…");
  try {
    const response = await apiFetch("/api/wiener/portfolio", {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify(limitPortfolioPdfRequestPayload({
        username: uiSettings.calculatorAccounts?.wiener?.username || "",
        downloadPdfs,
        ...getPortfolioFullReimportRequestFields(options),
        skipPdfPolicyNumbers: skipPolicyNumbers.slice(0, 5000),
        knownPolicyNumbers: knownPolicyNumbers.slice(0, 10000),
      })),
    });
    const data = await response.json();
    if (!response.ok) throw new Error(data?.error || "Nie udało się rozpocząć importu polis Wiener.");
    wienerPortfolioImportJobId = data.job.id;
    await applyWienerPortfolioImportJobState(data.job);
  } catch (error) {
    finishWienerPortfolioImportPolling();
    setWienerPortfolioImportStatus(error?.message || "Nie udało się rozpocząć importu polis Wiener.", "error");
  }
}

async function repairWienerPortfolioImportManually() {
  if (wienerPortfolioImportActive || !wienerPortfolioImportJobId) return;
  wienerPortfolioImportActive = true;
  elements.wienerPortfolioImportButton.disabled = true;
  elements.wienerPortfolioManualRepair.hidden = true;
  setWienerPortfolioImportStatus("Otwieranie Wiener do poprawienia ścieżki importu…");
  try {
    const response = await apiFetch(`/api/automation/jobs/${encodeURIComponent(wienerPortfolioImportJobId)}/manual`, {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: "{}",
    });
    const data = await response.json();
    if (!response.ok) throw new Error(data?.error || "Nie udało się uruchomić poprawiania ścieżki.");
    await applyWienerPortfolioImportJobState(data.job);
  } catch (error) {
    finishWienerPortfolioImportPolling();
    elements.wienerPortfolioManualRepair.hidden = false;
    setWienerPortfolioImportStatus(error?.message || "Nie udało się uruchomić poprawiania ścieżki.", "error");
  }
}

function updateWienerPortfolioPdfOptions() {
  const enabled = elements.wienerPortfolioDownloadPdfs?.checked === true;
  if (elements.wienerPortfolioPdfOptions) elements.wienerPortfolioPdfOptions.dataset.enabled = enabled ? "true" : "false";
}

elements.wienerPortfolioImportButton?.addEventListener("click", startWienerPortfolioImport);
elements.wienerPortfolioManualRepair?.addEventListener("click", () => {
  void runConfirmedPortfolioPathRepair("Wiener", repairWienerPortfolioImportManually);
});
elements.wienerPortfolioDownloadPdfs?.addEventListener("change", updateWienerPortfolioPdfOptions);
updateWienerPortfolioPdfOptions();
elements.closeWienerPortfolioReport?.addEventListener("click", () => elements.wienerPortfolioReportDialog.close());
elements.confirmWienerPortfolioReport?.addEventListener("click", () => elements.wienerPortfolioReportDialog.close());


let generaliPortfolioImportActive = false;


let generaliPortfolioChainTotals = { added: 0, enriched: 0, attached: 0, pdfFailed: 0, pdfEnriched: 0, transferred: 0 };
let generaliPortfolioImportJobId = "";
let generaliPortfolioImportPollTimer = 0;


function normalizeImportedGeneraliPortfolioPolicy(entry) {
  return {
    clientName: String(entry?.clientName || "").trim(),
    identityNumber: String(entry?.identityNumber || "").trim(),
    contact: String(entry?.contact || "").trim(),
    riskSummary: String(entry?.riskSummary || "").trim(),
    insurer: "Generali",
    policyNumber: String(entry?.policyNumber || "").trim(),
    registration: String(entry?.registration || "").trim() || "Inne",
    vehicleMake: String(entry?.vehicleMake || "").trim(),
    vehicleModel: String(entry?.vehicleModel || "").trim(),
    vin: String(entry?.vin || "").trim(),
    clientAddress: String(entry?.clientAddress || "").trim(),
    issueDate: String(entry?.issueDate || "").trim(),
    validFrom: String(entry?.validFrom || "").trim(),
    validUntil: String(entry?.validUntil || "").trim(),
    premium: String(entry?.premium || "").trim(),
  };
}

function applyGeneraliPortfolioMerge(importedEntries) {
  return applyConfiguredPortfolioMerge(importedEntries, getPortfolioMergeConfiguration("generali"));
}

function setGeneraliPortfolioImportStatus(message, state = "running") {
  if (!elements.generaliPortfolioImportStatus) return;
  elements.generaliPortfolioImportStatus.hidden = !message;
  elements.generaliPortfolioImportStatus.textContent = message || "";
  elements.generaliPortfolioImportStatus.dataset.state = state;
}

function finishGeneraliPortfolioImportPolling() {
  generaliPortfolioImportActive = false;
  globalThis.clearTimeout(generaliPortfolioImportPollTimer);
  if (elements.generaliPortfolioImportButton) elements.generaliPortfolioImportButton.disabled = false;
}

function showGeneraliPortfolioReport(counts, persistFailed, pdfResult, pdfRetry = null) {
  
  if (isPortfolioImportRunActive()) return;
  const dialog = elements.generaliPortfolioReportDialog;
  if (!dialog?.showModal) return;
  elements.generaliPortfolioReportAdded.textContent = String(counts.added);
  elements.generaliPortfolioReportEnriched.textContent = String(counts.enriched);
  fillPortfolioPdfReportElements(elements.generaliPortfolioReportPdfs, elements.generaliPortfolioReportPdfInfo, pdfResult);
  const warnings = [];
  appendPortfolioConflictWarnings(warnings, counts);
  if (persistFailed) warnings.push("Nie udało się zapisać pliku bazy - cała partia importu została cofnięta.");
  if (pdfResult?.folderUnavailable) warnings.push("Nie podpięto PDF-ów: brak dostępu do folderu bazy. Zezwól na dostęp i uruchom import ponownie.");
  else if (pdfResult?.failed > 0) warnings.push(`Nie udało się podpiąć ${pdfResult.failed} plików PDF (część polis nie ma dostępnego wydruku).`);
  const retryWarning = describePortfolioPdfRetryStatus(pdfRetry);
  if (retryWarning) warnings.push(retryWarning);
  elements.generaliPortfolioReportWarning.hidden = warnings.length === 0;
  elements.generaliPortfolioReportWarning.textContent = warnings.join(" ");
  if (!dialog.open) dialog.showModal();
}

async function finalizeGeneraliPortfolioImport(importedEntries, pdfQueueRemaining = null, job = null) {
  return runPortfolioImportCore(
    importedEntries,
    pdfQueueRemaining,
    job,
    getPortfolioImportCoreConfiguration("generali"),
  );
}

async function applyGeneraliPortfolioImportJobState(job) {
  return applyConfiguredPortfolioImportJobState(
    job,
    getPortfolioImportRuntimeConfiguration("generali"),
  );
}

async function pollGeneraliPortfolioImportJob() {
  return pollConfiguredPortfolioImportJob(
    getPortfolioImportRuntimeConfiguration("generali"),
  );
}

async function startGeneraliPortfolioImport(options = {}) {
  if (!canUseAgencyInsurerFeature("generali", "Generali")) return;
  if (generaliPortfolioImportActive) return;
  if (elements.generaliPortfolioManualRepair) elements.generaliPortfolioManualRepair.hidden = true;
  if (!(await checkWartaAutomationBridge())) {
    setGeneraliPortfolioImportStatus("Automatyzacja jest nieaktywna. Uruchom aplikację plikiem „Uruchom Baza Polis.cmd”.", "error");
    return;
  }
  if (!hasGeneraliCredentials()) {
    setGeneraliPortfolioImportStatus("Uzupełnij login i hasło Generali powyżej i zapisz ustawienia.", "error");
    return;
  }
  generaliPortfolioImportActive = true;
  if (elements.generaliPortfolioImportButton) elements.generaliPortfolioImportButton.disabled = true;
  const downloadPdfs = elements.generaliPortfolioDownloadPdfs?.checked === true;
  
  
  const generaliPolicies = policies.filter((policy) => policy.insurer === "Generali");
  const skipPolicyNumbers = downloadPdfs ? getPortfolioPdfSkipKeys(generaliPolicies) : [];
  
  
  const knownPolicyNumbers = downloadPdfs
    ? getKnownPortfolioPdfIdentities(generaliPolicies)
    : [];
  if (options?.autoContinuation !== true) generaliPortfolioChainTotals = { added: 0, enriched: 0, attached: 0, pdfFailed: 0, pdfEnriched: 0, transferred: 0 };
  setGeneraliPortfolioImportStatus(downloadPdfs
    ? "Rozpoczynanie importu polis z Generali (z pobieraniem PDF-ów)…"
    : "Rozpoczynanie importu polis z Generali…");
  try {
    const response = await apiFetch("/api/generali/portfolio", {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify(limitPortfolioPdfRequestPayload({
        username: uiSettings.calculatorAccounts?.generali?.username || "",
        downloadPdfs,
        ...getPortfolioFullReimportRequestFields(options),
        skipPdfPolicyNumbers: skipPolicyNumbers.slice(0, 5000),
        knownPolicyNumbers: knownPolicyNumbers.slice(0, 10000),
      })),
    });
    const data = await response.json();
    if (!response.ok) throw new Error(data?.error || "Nie udało się rozpocząć importu polis Generali.");
    generaliPortfolioImportJobId = data.job.id;
    await applyGeneraliPortfolioImportJobState(data.job);
  } catch (error) {
    finishGeneraliPortfolioImportPolling();
    setGeneraliPortfolioImportStatus(error?.message || "Nie udało się rozpocząć importu polis Generali.", "error");
  }
}

async function repairGeneraliPortfolioImportManually() {
  if (generaliPortfolioImportActive || !generaliPortfolioImportJobId) return;
  generaliPortfolioImportActive = true;
  if (elements.generaliPortfolioImportButton) elements.generaliPortfolioImportButton.disabled = true;
  if (elements.generaliPortfolioManualRepair) elements.generaliPortfolioManualRepair.hidden = true;
  setGeneraliPortfolioImportStatus("Otwieranie Generali do poprawienia ścieżki importu…");
  try {
    const response = await apiFetch(`/api/automation/jobs/${encodeURIComponent(generaliPortfolioImportJobId)}/manual`, {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: "{}",
    });
    const data = await response.json();
    if (!response.ok) throw new Error(data?.error || "Nie udało się uruchomić poprawiania ścieżki.");
    await applyGeneraliPortfolioImportJobState(data.job);
  } catch (error) {
    finishGeneraliPortfolioImportPolling();
    if (elements.generaliPortfolioManualRepair) elements.generaliPortfolioManualRepair.hidden = false;
    setGeneraliPortfolioImportStatus(error?.message || "Nie udało się uruchomić poprawiania ścieżki.", "error");
  }
}

function updateGeneraliPortfolioPdfOptions() {
  const enabled = elements.generaliPortfolioDownloadPdfs?.checked === true;
  if (elements.generaliPortfolioPdfOptions) elements.generaliPortfolioPdfOptions.dataset.enabled = enabled ? "true" : "false";
}

elements.generaliPortfolioImportButton?.addEventListener("click", startGeneraliPortfolioImport);
elements.generaliPortfolioManualRepair?.addEventListener("click", () => {
  void runConfirmedPortfolioPathRepair("Generali", repairGeneraliPortfolioImportManually);
});
elements.generaliPortfolioDownloadPdfs?.addEventListener("change", updateGeneraliPortfolioPdfOptions);
updateGeneraliPortfolioPdfOptions();
elements.closeGeneraliPortfolioReport?.addEventListener("click", () => elements.generaliPortfolioReportDialog.close());
elements.confirmGeneraliPortfolioReport?.addEventListener("click", () => elements.generaliPortfolioReportDialog.close());





let compensaPortfolioImportActive = false;
let compensaPortfolioChainTotals = { added: 0, enriched: 0, attached: 0, pdfFailed: 0 };
let compensaPortfolioImportJobId = "";
let compensaPortfolioImportPollTimer = 0;

function setCompensaPortfolioImportStatus(message, state = "running") {
  if (!elements.compensaPortfolioImportStatus) return;
  elements.compensaPortfolioImportStatus.hidden = !message;
  elements.compensaPortfolioImportStatus.textContent = message || "";
  elements.compensaPortfolioImportStatus.dataset.state = state;
}

function finishCompensaPortfolioImportPolling() {
  compensaPortfolioImportActive = false;
  globalThis.clearTimeout(compensaPortfolioImportPollTimer);
  if (elements.compensaPortfolioImportButton) elements.compensaPortfolioImportButton.disabled = false;
}




function normalizeImportedCompensaPortfolioPolicy(entry) {
  return {
    clientName: String(entry?.clientName || "").trim(),
    identityNumber: String(entry?.identityNumber || "").trim(),
    contact: String(entry?.contact || "").trim(),
    insurer: "Compensa",
    policyNumber: String(entry?.policyNumber || "").trim(),
    registration: String(entry?.registration || "").trim(),
    vehicleMake: String(entry?.vehicleMake || "").trim(),
    vehicleModel: String(entry?.vehicleModel || "").trim(),
    vin: String(entry?.vin || "").trim(),
    issueDate: String(entry?.issueDate || "").trim(),
    validFrom: String(entry?.validFrom || "").trim(),
    validUntil: String(entry?.validUntil || "").trim(),
    premium: String(entry?.premium || "").trim(),
  };
}

function applyCompensaPortfolioMerge(importedEntries) {
  return applyConfiguredPortfolioMerge(importedEntries, getPortfolioMergeConfiguration("compensa"));
}

function showCompensaPortfolioReport(counts, persistFailed, pdfResult, pdfRetry = null) {
  
  if (isPortfolioImportRunActive()) return;
  const dialog = elements.compensaPortfolioReportDialog;
  if (!dialog?.showModal) return;
  elements.compensaPortfolioReportAdded.textContent = String(counts.added);
  elements.compensaPortfolioReportEnriched.textContent = String(counts.enriched);
  fillPortfolioPdfReportElements(elements.compensaPortfolioReportPdfs, elements.compensaPortfolioReportPdfInfo, pdfResult);
  const warnings = [];
  appendPortfolioConflictWarnings(warnings, counts);
  if (persistFailed) warnings.push("Nie uda\u0142o si\u0119 zapisa\u0107 pliku bazy - ca\u0142a partia importu zosta\u0142a cofni\u0119ta.");
  if (pdfResult?.folderUnavailable) warnings.push("Nie podpi\u0119to PDF-\u00f3w: brak dost\u0119pu do folderu bazy. Zezw\u00f3l na dost\u0119p i uruchom import ponownie.");
  else if (pdfResult?.failed > 0) warnings.push(`Nie uda\u0142o si\u0119 podpi\u0105\u0107 ${pdfResult.failed} plik\u00f3w PDF.`);
  const retryWarning = describePortfolioPdfRetryStatus(pdfRetry);
  if (retryWarning) warnings.push(retryWarning);
  if (!(pdfResult?.attached > 0)) warnings.push("Compensa nie podaje na li\u015bcie sk\u0142adki, daty pocz\u0105tku ani numeru rejestracyjnego - te dane wchodz\u0105 dopiero z PDF-\u00f3w polis.");
  elements.compensaPortfolioReportWarning.hidden = warnings.length === 0;
  elements.compensaPortfolioReportWarning.textContent = warnings.join(" ");
  if (!dialog.open) dialog.showModal();
}

async function finalizeCompensaPortfolioImport(importedEntries, pdfQueueRemaining = null, job = null) {
  return runPortfolioImportCore(
    importedEntries,
    pdfQueueRemaining,
    job,
    getPortfolioImportCoreConfiguration("compensa"),
  );
}

async function applyCompensaPortfolioImportJobState(job) {
  return applyConfiguredPortfolioImportJobState(
    job,
    getPortfolioImportRuntimeConfiguration("compensa"),
  );
}

async function pollCompensaPortfolioImportJob() {
  return pollConfiguredPortfolioImportJob(
    getPortfolioImportRuntimeConfiguration("compensa"),
  );
}

async function startCompensaPortfolioImport(options = {}) {
  if (!canUseAgencyInsurerFeature("compensa", "Compensa")) return;
  if (compensaPortfolioImportActive) return;
  if (elements.compensaPortfolioManualRepair) elements.compensaPortfolioManualRepair.hidden = true;
  if (!(await checkWartaAutomationBridge())) {
    setCompensaPortfolioImportStatus("Automatyzacja jest nieaktywna. Uruchom aplikacj\u0119 plikiem \u201eUruchom Baza Polis.cmd\u201d.", "error");
    return;
  }
  if (!hasCompensaCredentials()) {
    setCompensaPortfolioImportStatus("Uzupe\u0142nij login i has\u0142o Compensy powy\u017cej i zapisz ustawienia.", "error");
    return;
  }
  compensaPortfolioImportActive = true;
  if (elements.compensaPortfolioImportButton) elements.compensaPortfolioImportButton.disabled = true;
  if (options?.autoContinuation !== true) compensaPortfolioChainTotals = { added: 0, enriched: 0, attached: 0, pdfFailed: 0 };
  const downloadPdfs = elements.compensaPortfolioDownloadPdfs?.checked === true;
  setCompensaPortfolioImportStatus(downloadPdfs
    ? "Rozpoczynanie importu polis z Compensy (z pobieraniem PDF-\u00f3w)\u2026"
    : "Rozpoczynanie importu polis z Compensy\u2026");
  try {
    const response = await apiFetch("/api/compensa/portfolio", {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify(limitPortfolioPdfRequestPayload({
        username: uiSettings.calculatorAccounts?.compensa?.username || "",
        downloadPdfs,
        ...getPortfolioFullReimportRequestFields(options),
        skipPdfPolicyNumbers: downloadPdfs
          ? getPortfolioPdfSkipKeys(policies.filter((policy) => policy.insurer === "Compensa")).slice(0, 5000)
          : [],
      })),
    });
    const data = await response.json();
    if (!response.ok) throw new Error(data?.error || "Nie uda\u0142o si\u0119 rozpocz\u0105\u0107 importu polis Compensa.");
    compensaPortfolioImportJobId = data.job.id;
    await applyCompensaPortfolioImportJobState(data.job);
  } catch (error) {
    finishCompensaPortfolioImportPolling();
    setCompensaPortfolioImportStatus(error?.message || "Nie uda\u0142o si\u0119 rozpocz\u0105\u0107 importu polis Compensa.", "error");
  }
}

function updateCompensaPortfolioPdfOptions() {
  if (!elements.compensaPortfolioPdfOptions) return;
  elements.compensaPortfolioPdfOptions.dataset.state = elements.compensaPortfolioDownloadPdfs?.checked === true
    ? "on"
    : "off";
}

async function repairCompensaPortfolioImportManually() {
  if (compensaPortfolioImportActive || !compensaPortfolioImportJobId) return;
  compensaPortfolioImportActive = true;
  if (elements.compensaPortfolioImportButton) elements.compensaPortfolioImportButton.disabled = true;
  if (elements.compensaPortfolioManualRepair) elements.compensaPortfolioManualRepair.hidden = true;
  setCompensaPortfolioImportStatus("Otwieranie Compensy do poprawienia \u015bcie\u017cki importu\u2026");
  try {
    const response = await apiFetch(`/api/automation/jobs/${encodeURIComponent(compensaPortfolioImportJobId)}/manual`, {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: "{}",
    });
    const data = await response.json();
    if (!response.ok) throw new Error(data?.error || "Nie uda\u0142o si\u0119 uruchomi\u0107 poprawiania \u015bcie\u017cki.");
    await applyCompensaPortfolioImportJobState(data.job);
  } catch (error) {
    finishCompensaPortfolioImportPolling();
    if (elements.compensaPortfolioManualRepair) elements.compensaPortfolioManualRepair.hidden = false;
    setCompensaPortfolioImportStatus(error?.message || "Nie uda\u0142o si\u0119 uruchomi\u0107 poprawiania \u015bcie\u017cki.", "error");
  }
}

elements.compensaPortfolioImportButton?.addEventListener("click", startCompensaPortfolioImport);
elements.compensaPortfolioDownloadPdfs?.addEventListener("change", updateCompensaPortfolioPdfOptions);
updateCompensaPortfolioPdfOptions();
elements.compensaPortfolioManualRepair?.addEventListener("click", () => {
  void runConfirmedPortfolioPathRepair("Compensy", repairCompensaPortfolioImportManually);
});
elements.closeCompensaPortfolioReport?.addEventListener("click", () => elements.compensaPortfolioReportDialog.close());
elements.confirmCompensaPortfolioReport?.addEventListener("click", () => elements.compensaPortfolioReportDialog.close());


let allianzPortfolioImportActive = false;
let allianzPortfolioChainTotals = { added: 0, enriched: 0, attached: 0, pdfFailed: 0, pdfEnriched: 0, transferred: 0 };
let allianzPortfolioImportJobId = "";
let allianzPortfolioImportPollTimer = 0;

function setAllianzPortfolioImportStatus(message, state = "running") {
  if (!elements.allianzPortfolioImportStatus) return;
  elements.allianzPortfolioImportStatus.hidden = !message;
  elements.allianzPortfolioImportStatus.textContent = message || "";
  elements.allianzPortfolioImportStatus.dataset.state = state;
}

function finishAllianzPortfolioImportPolling() {
  allianzPortfolioImportActive = false;
  globalThis.clearTimeout(allianzPortfolioImportPollTimer);
  if (elements.allianzPortfolioImportButton) elements.allianzPortfolioImportButton.disabled = false;
}



function normalizeImportedAllianzPortfolioPolicy(entry) {
  return {
    clientName: String(entry?.clientName || "").trim(),
    identityNumber: String(entry?.identityNumber || "").trim(),
    secondaryIdentityNumber: String(entry?.secondaryIdentityNumber || "").trim(),
    contact: String(entry?.contact || "").trim(),
    insurer: "Allianz",
    policyNumber: String(entry?.policyNumber || "").trim(),
    registration: String(entry?.registration || "").trim(),
    vehicleMake: String(entry?.vehicleMake || "").trim(),
    vehicleModel: String(entry?.vehicleModel || "").trim(),
    vin: String(entry?.vin || "").trim(),
    clientAddress: String(entry?.clientAddress || "").trim(),
    clientPostalCode: String(entry?.clientPostalCode || "").trim(),
    issueDate: String(entry?.issueDate || "").trim(),
    validFrom: String(entry?.validFrom || "").trim(),
    validUntil: String(entry?.validUntil || "").trim(),
    premium: String(entry?.premium || "").trim(),
    riskSummary: String(entry?.riskSummary || "").trim(),
  };
}

function applyAllianzPortfolioMerge(importedEntries) {
  return applyConfiguredPortfolioMerge(importedEntries, getPortfolioMergeConfiguration("allianz"));
}

function showAllianzPortfolioReport(counts, persistFailed, pdfResult, pdfRetry = null) {
  
  if (isPortfolioImportRunActive()) return;
  const dialog = elements.allianzPortfolioReportDialog;
  if (!dialog?.showModal) return;
  elements.allianzPortfolioReportAdded.textContent = String(counts.added);
  elements.allianzPortfolioReportEnriched.textContent = String(counts.enriched);
  fillPortfolioPdfReportElements(
    elements.allianzPortfolioReportPdfs,
    elements.allianzPortfolioReportPdfInfo,
    pdfResult,
  );
  const warnings = [];
  appendPortfolioConflictWarnings(warnings, counts);
  if (persistFailed) warnings.push("Nie udało się zapisać pliku bazy - cała partia importu została cofnięta.");
  if (pdfResult?.folderUnavailable) warnings.push("Nie podpięto PDF-ów: brak dostępu do folderu bazy. Zezwól na dostęp i uruchom import ponownie.");
  else if (pdfResult?.failed > 0) warnings.push(`Nie udało się podpiąć ${pdfResult.failed} plików PDF (część polis nie ma dostępnego właściwego wydruku).`);
  const retryWarning = describePortfolioPdfRetryStatus(pdfRetry);
  if (retryWarning) warnings.push(retryWarning);
  elements.allianzPortfolioReportWarning.hidden = warnings.length === 0;
  elements.allianzPortfolioReportWarning.textContent = warnings.join(" ");
  if (!dialog.open) dialog.showModal();
}

async function finalizeAllianzPortfolioImport(importedEntries, pdfQueueRemaining = null, job = null) {
  return runPortfolioImportCore(
    importedEntries,
    pdfQueueRemaining,
    job,
    getPortfolioImportCoreConfiguration("allianz"),
  );
}

async function applyAllianzPortfolioImportJobState(job) {
  return applyConfiguredPortfolioImportJobState(
    job,
    getPortfolioImportRuntimeConfiguration("allianz"),
  );
}

async function pollAllianzPortfolioImportJob() {
  return pollConfiguredPortfolioImportJob(
    getPortfolioImportRuntimeConfiguration("allianz"),
  );
}

async function startAllianzPortfolioImport(options = {}) {
  if (!canUseAgencyInsurerFeature("allianz", "Allianz")) return;
  if (allianzPortfolioImportActive) return;
  if (elements.allianzPortfolioManualRepair) elements.allianzPortfolioManualRepair.hidden = true;
  if (!(await checkWartaAutomationBridge())) {
    setAllianzPortfolioImportStatus("Automatyzacja jest nieaktywna. Uruchom aplikację plikiem „Uruchom Baza Polis.cmd”.", "error");
    return;
  }
  if (!hasAllianzCredentials()) {
    setAllianzPortfolioImportStatus("Uzupełnij login i hasło Allianz powyżej i zapisz ustawienia.", "error");
    return;
  }
  allianzPortfolioImportActive = true;
  if (elements.allianzPortfolioImportButton) elements.allianzPortfolioImportButton.disabled = true;
  const downloadPdfs = elements.allianzPortfolioDownloadPdfs?.checked === true;
  const allianzPolicies = policies.filter((policy) => getPortfolioInsurerKey(policy) === "allianz");
  const skipPolicyNumbers = downloadPdfs ? getPortfolioPdfSkipKeys(allianzPolicies) : [];
  const knownPolicyNumbers = downloadPdfs
    ? getKnownPortfolioPdfIdentities(allianzPolicies)
    : [];
  if (options?.autoContinuation !== true) {
    allianzPortfolioChainTotals = { added: 0, enriched: 0, attached: 0, pdfFailed: 0, pdfEnriched: 0, transferred: 0 };
  }
  setAllianzPortfolioImportStatus(downloadPdfs
    ? "Rozpoczynanie importu polis z Allianz (z pobieraniem PDF-ów)…"
    : "Rozpoczynanie importu polis z Allianz…");
  try {
    const response = await apiFetch("/api/allianz/portfolio", {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify(limitPortfolioPdfRequestPayload({
        username: uiSettings.calculatorAccounts?.allianz?.username || "",
        downloadPdfs,
        ...getPortfolioFullReimportRequestFields(options),
        skipPdfPolicyNumbers: skipPolicyNumbers.slice(0, 5000),
        knownPolicyNumbers: knownPolicyNumbers.slice(0, 10000),
      })),
    });
    const data = await response.json();
    if (!response.ok) throw new Error(data?.error || "Nie udało się rozpocząć importu polis Allianz.");
    allianzPortfolioImportJobId = data.job.id;
    await applyAllianzPortfolioImportJobState(data.job);
  } catch (error) {
    finishAllianzPortfolioImportPolling();
    setAllianzPortfolioImportStatus(error?.message || "Nie udało się rozpocząć importu polis Allianz.", "error");
  }
}

async function repairAllianzPortfolioImportManually() {
  if (allianzPortfolioImportActive || !allianzPortfolioImportJobId) return;
  allianzPortfolioImportActive = true;
  if (elements.allianzPortfolioImportButton) elements.allianzPortfolioImportButton.disabled = true;
  if (elements.allianzPortfolioManualRepair) elements.allianzPortfolioManualRepair.hidden = true;
  setAllianzPortfolioImportStatus("Otwieranie Allianz do poprawienia ścieżki importu…");
  try {
    const response = await apiFetch(`/api/automation/jobs/${encodeURIComponent(allianzPortfolioImportJobId)}/manual`, {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: "{}",
    });
    const data = await response.json();
    if (!response.ok) throw new Error(data?.error || "Nie udało się uruchomić poprawiania ścieżki.");
    await applyAllianzPortfolioImportJobState(data.job);
  } catch (error) {
    finishAllianzPortfolioImportPolling();
    if (elements.allianzPortfolioManualRepair) elements.allianzPortfolioManualRepair.hidden = false;
    setAllianzPortfolioImportStatus(error?.message || "Nie udało się uruchomić poprawiania ścieżki.", "error");
  }
}

function updateAllianzPortfolioPdfOptions() {
  const enabled = elements.allianzPortfolioDownloadPdfs?.checked === true;
  if (elements.allianzPortfolioPdfOptions) {
    elements.allianzPortfolioPdfOptions.dataset.enabled = enabled ? "true" : "false";
  }
}

elements.allianzPortfolioImportButton?.addEventListener("click", startAllianzPortfolioImport);
elements.allianzPortfolioManualRepair?.addEventListener("click", () => {
  void runConfirmedPortfolioPathRepair("Allianz", repairAllianzPortfolioImportManually);
});
elements.allianzPortfolioDownloadPdfs?.addEventListener("change", updateAllianzPortfolioPdfOptions);
updateAllianzPortfolioPdfOptions();
elements.closeAllianzPortfolioReport?.addEventListener("click", () => elements.allianzPortfolioReportDialog.close());
elements.confirmAllianzPortfolioReport?.addEventListener("click", () => elements.allianzPortfolioReportDialog.close());


let trastiPortfolioImportActive = false;


let trastiPortfolioChainTotals = { added: 0, enriched: 0, attached: 0, pdfFailed: 0, pdfEnriched: 0, transferred: 0 };
let trastiPortfolioImportJobId = "";
let trastiPortfolioImportPollTimer = 0;

function setTrastiPortfolioImportStatus(message, state = "running") {
  if (!elements.trastiPortfolioImportStatus) return;
  elements.trastiPortfolioImportStatus.hidden = !message;
  elements.trastiPortfolioImportStatus.textContent = message || "";
  elements.trastiPortfolioImportStatus.dataset.state = state;
}

function finishTrastiPortfolioImportPolling() {
  trastiPortfolioImportActive = false;
  globalThis.clearTimeout(trastiPortfolioImportPollTimer);
  if (elements.trastiPortfolioImportButton) elements.trastiPortfolioImportButton.disabled = false;
}



function normalizeImportedTrastiPortfolioPolicy(entry) {
  return {
    clientName: String(entry?.clientName || "").trim(),
    identityNumber: String(entry?.identityNumber || "").trim(),
    contact: String(entry?.contact || "").trim(),
    riskSummary: String(entry?.riskSummary || "").trim(),
    insurer: "Trasti",
    policyNumber: String(entry?.policyNumber || "").trim(),
    registration: String(entry?.registration || "").trim() || "Auto",
    vehicleMake: String(entry?.vehicleMake || "").trim(),
    vehicleModel: String(entry?.vehicleModel || "").trim(),
    vin: String(entry?.vin || "").trim(),
    issueDate: String(entry?.issueDate || "").trim(),
    validFrom: String(entry?.validFrom || "").trim(),
    validUntil: String(entry?.validUntil || "").trim(),
    premium: String(entry?.premium || "").trim(),
  };
}

function applyTrastiPortfolioMerge(importedEntries) {
  return applyConfiguredPortfolioMerge(importedEntries, getPortfolioMergeConfiguration("trasti"));
}

function showTrastiPortfolioReport(counts, persistFailed, pdfResult, pdfRetry = null) {
  
  if (isPortfolioImportRunActive()) return;
  const dialog = elements.trastiPortfolioReportDialog;
  if (!dialog?.showModal) return;
  elements.trastiPortfolioReportAdded.textContent = String(counts.added);
  elements.trastiPortfolioReportEnriched.textContent = String(counts.enriched);
  fillPortfolioPdfReportElements(elements.trastiPortfolioReportPdfs, elements.trastiPortfolioReportPdfInfo, pdfResult);
  const warnings = [];
  appendPortfolioConflictWarnings(warnings, counts);
  if (persistFailed) warnings.push("Nie udało się zapisać pliku bazy - cała partia importu została cofnięta.");
  if (pdfResult?.folderUnavailable) warnings.push("Nie podpięto PDF-ów: brak dostępu do folderu bazy. Zezwól na dostęp i uruchom import ponownie.");
  else if (pdfResult?.failed > 0) warnings.push(`Nie udało się podpiąć ${pdfResult.failed} plików PDF (część polis nie ma dostępnego wydruku).`);
  const retryWarning = describePortfolioPdfRetryStatus(pdfRetry);
  if (retryWarning) warnings.push(retryWarning);
  elements.trastiPortfolioReportWarning.hidden = warnings.length === 0;
  elements.trastiPortfolioReportWarning.textContent = warnings.join(" ");
  if (!dialog.open) dialog.showModal();
}

async function finalizeTrastiPortfolioImport(importedEntries, pdfQueueRemaining = null, job = null) {
  return runPortfolioImportCore(
    importedEntries,
    pdfQueueRemaining,
    job,
    getPortfolioImportCoreConfiguration("trasti"),
  );
}

async function applyTrastiPortfolioImportJobState(job) {
  return applyConfiguredPortfolioImportJobState(
    job,
    getPortfolioImportRuntimeConfiguration("trasti"),
  );
}

async function pollTrastiPortfolioImportJob() {
  return pollConfiguredPortfolioImportJob(
    getPortfolioImportRuntimeConfiguration("trasti"),
  );
}

async function startTrastiPortfolioImport(options = {}) {
  if (!canUseAgencyInsurerFeature("trasti", "Trasti")) return;
  if (trastiPortfolioImportActive) return;
  if (elements.trastiPortfolioManualRepair) elements.trastiPortfolioManualRepair.hidden = true;
  if (!(await checkWartaAutomationBridge())) {
    setTrastiPortfolioImportStatus("Automatyzacja jest nieaktywna. Uruchom aplikację plikiem „Uruchom Baza Polis.cmd”.", "error");
    return;
  }
  if (!hasTrastiCredentials()) {
    setTrastiPortfolioImportStatus("Uzupełnij adres e-mail i hasło Trasti powyżej i zapisz ustawienia.", "error");
    return;
  }
  trastiPortfolioImportActive = true;
  if (elements.trastiPortfolioImportButton) elements.trastiPortfolioImportButton.disabled = true;
  const downloadPdfs = elements.trastiPortfolioDownloadPdfs?.checked === true;
  
  
  const trastiPolicies = policies.filter((policy) => policy.insurer === "Trasti");
  const skipPolicyNumbers = downloadPdfs ? getPortfolioPdfSkipKeys(trastiPolicies) : [];
  
  
  const knownPolicyNumbers = downloadPdfs
    ? getKnownPortfolioPdfIdentities(trastiPolicies)
    : [];
  if (options?.autoContinuation !== true) trastiPortfolioChainTotals = { added: 0, enriched: 0, attached: 0, pdfFailed: 0, pdfEnriched: 0, transferred: 0 };
  setTrastiPortfolioImportStatus(downloadPdfs
    ? "Rozpoczynanie importu polis z Trasti (z pobieraniem PDF-ów)…"
    : "Rozpoczynanie importu polis z Trasti…");
  try {
    const response = await apiFetch("/api/trasti/portfolio", {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify(limitPortfolioPdfRequestPayload({
        username: uiSettings.calculatorAccounts?.trasti?.username || "",
        downloadPdfs,
        ...getPortfolioFullReimportRequestFields(options),
        skipPdfPolicyNumbers: skipPolicyNumbers.slice(0, 5000),
        knownPolicyNumbers: knownPolicyNumbers.slice(0, 10000),
      })),
    });
    const data = await response.json();
    if (!response.ok) throw new Error(data?.error || "Nie udało się rozpocząć importu polis Trasti.");
    trastiPortfolioImportJobId = data.job.id;
    await applyTrastiPortfolioImportJobState(data.job);
  } catch (error) {
    finishTrastiPortfolioImportPolling();
    setTrastiPortfolioImportStatus(error?.message || "Nie udało się rozpocząć importu polis Trasti.", "error");
  }
}

async function repairTrastiPortfolioImportManually() {
  if (trastiPortfolioImportActive || !trastiPortfolioImportJobId) return;
  trastiPortfolioImportActive = true;
  if (elements.trastiPortfolioImportButton) elements.trastiPortfolioImportButton.disabled = true;
  if (elements.trastiPortfolioManualRepair) elements.trastiPortfolioManualRepair.hidden = true;
  setTrastiPortfolioImportStatus("Otwieranie Trasti do poprawienia ścieżki importu…");
  try {
    const response = await apiFetch(`/api/automation/jobs/${encodeURIComponent(trastiPortfolioImportJobId)}/manual`, {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: "{}",
    });
    const data = await response.json();
    if (!response.ok) throw new Error(data?.error || "Nie udało się uruchomić poprawiania ścieżki.");
    await applyTrastiPortfolioImportJobState(data.job);
  } catch (error) {
    finishTrastiPortfolioImportPolling();
    if (elements.trastiPortfolioManualRepair) elements.trastiPortfolioManualRepair.hidden = false;
    setTrastiPortfolioImportStatus(error?.message || "Nie udało się uruchomić poprawiania ścieżki.", "error");
  }
}

function updateTrastiPortfolioPdfOptions() {
  const enabled = elements.trastiPortfolioDownloadPdfs?.checked === true;
  if (elements.trastiPortfolioPdfOptions) elements.trastiPortfolioPdfOptions.dataset.enabled = enabled ? "true" : "false";
}

elements.trastiPortfolioImportButton?.addEventListener("click", startTrastiPortfolioImport);
elements.trastiPortfolioManualRepair?.addEventListener("click", () => {
  void runConfirmedPortfolioPathRepair("Trasti", repairTrastiPortfolioImportManually);
});
elements.trastiPortfolioDownloadPdfs?.addEventListener("change", updateTrastiPortfolioPdfOptions);
updateTrastiPortfolioPdfOptions();
elements.closeTrastiPortfolioReport?.addEventListener("click", () => elements.trastiPortfolioReportDialog.close());
elements.confirmTrastiPortfolioReport?.addEventListener("click", () => elements.trastiPortfolioReportDialog.close());


let wartaPortfolioRecordsActive = false;
let wartaPortfolioRecordsJobId = "";
let wartaPortfolioRecordsPollTimer = 0;


let wartaPortfolioRecordsLastError = "";
let wartaPortfolioImportActive = false;
let wartaPortfolioImportJobId = "";
let wartaPortfolioImportPollTimer = 0;

function setWartaPortfolioImportStatus(message, state = "running") {
  if (!elements.wartaPortfolioImportStatus) return;
  elements.wartaPortfolioImportStatus.hidden = !message;
  elements.wartaPortfolioImportStatus.textContent = message || "";
  elements.wartaPortfolioImportStatus.dataset.state = state;
}

function finishWartaPortfolioRecordsPolling() {
  wartaPortfolioRecordsActive = false;
  globalThis.clearTimeout(wartaPortfolioRecordsPollTimer);
  if (elements.wartaPortfolioRecordsButton) elements.wartaPortfolioRecordsButton.disabled = false;
}

function finishWartaPortfolioImportPolling() {
  wartaPortfolioImportActive = false;
  globalThis.clearTimeout(wartaPortfolioImportPollTimer);
  if (elements.wartaPortfolioImportButton) elements.wartaPortfolioImportButton.disabled = false;
}



function normalizeImportedWartaPortfolioPolicy(entry) {
  const rawRiskSummary = String(entry?.riskSummary || "").trim();
  const riskSummary = isWartaTravelPortfolioLabel(rawRiskSummary)
    ? rawRiskSummary.replace(/^eAgent\s+/i, "")
    : rawRiskSummary;
  return {
    clientName: String(entry?.clientName || "").trim(),
    identityNumber: String(entry?.identityNumber || "").trim(),
    contact: String(entry?.contact || "").trim(),
    riskSummary,
    insurer: "Warta",
    policyNumber: String(entry?.policyNumber || "").trim(),
    registration: isWartaTravelPortfolioLabel(riskSummary)
      ? "Podróż"
      : (String(entry?.registration || "").trim() || "Inne"),
    vehicleMake: String(entry?.vehicleMake || "").trim(),
    vehicleModel: String(entry?.vehicleModel || "").trim(),
    vin: String(entry?.vin || "").trim(),
    issueDate: String(entry?.issueDate || "").trim(),
    validFrom: String(entry?.validFrom || "").trim(),
    validUntil: String(entry?.validUntil || "").trim(),
    premium: String(entry?.premium || "").trim(),
  };
}

function applyWartaPortfolioMerge(importedEntries) {
  return applyConfiguredPortfolioMerge(importedEntries, getPortfolioMergeConfiguration("warta"));
}

async function finalizeWartaPortfolioImport(importedEntries, pdfQueueRemaining = null, job = null) {
  return runPortfolioImportCore(
    importedEntries,
    pdfQueueRemaining,
    job,
    getPortfolioImportCoreConfiguration("warta"),
  );
}

function populateWartaRecordDropdown(records) {
  const select = elements.wartaPortfolioRecordSelect;
  if (!select) return 0;
  const list = Array.isArray(records) ? records.filter((record) => record && record.agreementId) : [];
  select.innerHTML = "";
  list.forEach((record) => {
    const option = document.createElement("option");
    option.value = String(record.agreementId);
    option.textContent = String(record.label || record.agreementId);
    select.appendChild(option);
  });
  const hasRecords = list.length > 0;
  if (elements.wartaPortfolioRecordField) elements.wartaPortfolioRecordField.hidden = !hasRecords;
  
  
  return list.length;
}

async function applyWartaPortfolioRecordsJobState(job) {
  if (!job || job.id !== wartaPortfolioRecordsJobId) return;
  if (job.status === "completed") {
    finishWartaPortfolioRecordsPolling();
    const count = populateWartaRecordDropdown(job.records);
    if (count === 0) {
      setWartaPortfolioImportStatus("Warta nie zwróciła żadnego rekordu do wyboru.", "error");
      return;
    }
    setWartaPortfolioImportStatus(`Znaleziono ${count} rekordów. Wybierz rekord i kliknij „Importuj polisy z Warty”.`, "success");
    return;
  }
  if (job.status === "manual_required" || job.status === "error") {
    finishWartaPortfolioRecordsPolling();
    wartaPortfolioRecordsLastError = `${job.title}${job.detail ? ` - ${job.detail}` : ""}`;
    setWartaPortfolioImportStatus(wartaPortfolioRecordsLastError, "error");
    return;
  }
  setWartaPortfolioImportStatus(`${job.title}${job.detail ? ` - ${job.detail}` : ""}`);
  wartaPortfolioRecordsPollTimer = globalThis.setTimeout(pollWartaPortfolioRecordsJob, 900);
}

async function pollWartaPortfolioRecordsJob() {
  if (!wartaPortfolioRecordsActive || !wartaPortfolioRecordsJobId) return;
  try {
    const response = await apiFetch(`/api/automation/jobs/${encodeURIComponent(wartaPortfolioRecordsJobId)}`, { cache: "no-store" });
    const data = await response.json();
    if (!response.ok) throw new Error(data?.error || "Nie udało się odczytać stanu pobierania rekordów Warty.");
    await applyWartaPortfolioRecordsJobState(data.job);
  } catch (error) {
    finishWartaPortfolioRecordsPolling();
    wartaPortfolioRecordsLastError = error?.message || "Utracono połączenie z lokalnym serwerem automatyzacji.";
    setWartaPortfolioImportStatus(wartaPortfolioRecordsLastError, "error");
  }
}

async function startWartaPortfolioRecords() {
  if (!canUseAgencyInsurerFeature("warta", "Warta")) return;
  if (wartaPortfolioRecordsActive || wartaPortfolioImportActive) return;
  if (!(await checkWartaAutomationBridge())) {
    setWartaPortfolioImportStatus("Automatyzacja jest nieaktywna. Uruchom aplikację plikiem „Uruchom Baza Polis.cmd”.", "error");
    return;
  }
  if (!hasWartaCredentials()) {
    setWartaPortfolioImportStatus("Uzupełnij login i hasło Warty powyżej i zapisz ustawienia.", "error");
    return;
  }
  wartaPortfolioRecordsActive = true;
  wartaPortfolioRecordsLastError = "";
  if (elements.wartaPortfolioRecordsButton) elements.wartaPortfolioRecordsButton.disabled = true;
  if (elements.wartaPortfolioRecordField) elements.wartaPortfolioRecordField.hidden = true;
  setWartaPortfolioImportStatus("Logowanie do Warty i pobieranie listy rekordów…");
  try {
    const response = await apiFetch("/api/warta/portfolio/records", {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({ username: uiSettings.calculatorAccounts?.warta?.username || "" }),
    });
    const data = await response.json();
    if (!response.ok) throw new Error(data?.error || "Nie udało się pobrać listy rekordów Warty.");
    wartaPortfolioRecordsJobId = data.job.id;
    await applyWartaPortfolioRecordsJobState(data.job);
  } catch (error) {
    finishWartaPortfolioRecordsPolling();
    setWartaPortfolioImportStatus(error?.message || "Nie udało się pobrać listy rekordów Warty.", "error");
  }
}

async function applyWartaPortfolioImportJobState(job) {
  return applyConfiguredPortfolioImportJobState(
    job,
    getPortfolioImportRuntimeConfiguration("warta"),
  );
}

async function pollWartaPortfolioImportJob() {
  return pollConfiguredPortfolioImportJob(
    getPortfolioImportRuntimeConfiguration("warta"),
  );
}

async function startWartaPortfolioImport(options = {}) {
  if (!canUseAgencyInsurerFeature("warta", "Warta")) return;
  if (wartaPortfolioImportActive || wartaPortfolioRecordsActive) return;
  const select = elements.wartaPortfolioRecordSelect;
  let agreementId = String(select?.value || "").trim();
  
  
  
  if (!agreementId && select) {
    const remembered = String(globalThis.localStorage?.getItem(PORTFOLIO_IMPORT_WARTA_RECORD_KEY) || "").trim();
    if (remembered) {
      const option = document.createElement("option");
      option.value = remembered;
      option.textContent = "Zapamiętany rekord";
      select.append(option);
      select.value = remembered;
      agreementId = remembered;
    }
  }
  if (!agreementId) {
    await startWartaPortfolioRecords();
    
    
    const recordsDeadline = Date.now() + 3 * 60 * 1000;
    while (wartaPortfolioRecordsActive && Date.now() < recordsDeadline) {
      await new Promise((resolve) => globalThis.setTimeout(resolve, 500));
    }
    const options = [...(select?.options || [])].filter((option) => option.value);
    if (options.length === 1) {
      select.value = options[0].value;
      agreementId = options[0].value;
    } else if (options.length > 1) {
      setWartaPortfolioImportStatus("Wybierz rekord z listy powyżej i kliknij „Importuj polisy z Warty” jeszcze raz.", "success");
      return;
    } else {
      
      return;
    }
  }
  const agreementLabel = select?.selectedOptions?.[0]?.textContent || "";
  if (!(await checkWartaAutomationBridge())) {
    setWartaPortfolioImportStatus("Automatyzacja jest nieaktywna. Uruchom aplikację plikiem „Uruchom Baza Polis.cmd”.", "error");
    return;
  }
  wartaPortfolioImportActive = true;
  elements.wartaPortfolioImportButton.disabled = true;
  const downloadPdfs = elements.wartaPortfolioDownloadPdfs?.checked === true;
  
  
  const wartaPolicies = policies.filter((policy) => policy.insurer === "Warta");
  const skipPolicyNumbers = downloadPdfs ? getPortfolioPdfSkipKeys(wartaPolicies) : [];
  
  
  const knownPolicyNumbers = downloadPdfs
    ? getKnownPortfolioPdfIdentities(wartaPolicies)
    : [];
  setWartaPortfolioImportStatus(downloadPdfs
    ? `Rozpoczynanie importu polis z Warty (rekord: ${agreementLabel}, z pobieraniem PDF-ów)…`
    : `Rozpoczynanie importu polis z Warty (rekord: ${agreementLabel})…`);
  try {
    const response = await apiFetch("/api/warta/portfolio", {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify(limitPortfolioPdfRequestPayload({
        username: uiSettings.calculatorAccounts?.warta?.username || "",
        agreementId,
        agreementLabel,
        downloadPdfs,
        ...getPortfolioFullReimportRequestFields(options),
        skipPdfPolicyNumbers: skipPolicyNumbers.slice(0, 5000),
        knownPolicyNumbers: knownPolicyNumbers.slice(0, 10000),
      })),
    });
    const data = await response.json();
    if (!response.ok) throw new Error(data?.error || "Nie udało się rozpocząć importu polis Warty.");
    
    
    globalThis.localStorage?.setItem(PORTFOLIO_IMPORT_WARTA_RECORD_KEY, agreementId);
    wartaPortfolioImportJobId = data.job.id;
    await applyWartaPortfolioImportJobState(data.job);
  } catch (error) {
    finishWartaPortfolioImportPolling();
    setWartaPortfolioImportStatus(error?.message || "Nie udało się rozpocząć importu polis Warty.", "error");
  }
}

function updateWartaPortfolioPdfOptions() {
  const enabled = elements.wartaPortfolioDownloadPdfs?.checked === true;
  if (elements.wartaPortfolioPdfOptions) elements.wartaPortfolioPdfOptions.dataset.enabled = enabled ? "true" : "false";
}

elements.wartaPortfolioRecordsButton?.addEventListener("click", startWartaPortfolioRecords);
elements.wartaPortfolioImportButton?.addEventListener("click", startWartaPortfolioImport);
elements.wartaPortfolioDownloadPdfs?.addEventListener("change", updateWartaPortfolioPdfOptions);
updateWartaPortfolioPdfOptions();


let pzuPortfolioOpenActive = false;
let pzuPortfolioOpenJobId = "";
let pzuPortfolioOpenPollTimer = 0;
let pzuPortfolioImportActive = false;
let pzuPortfolioImportJobId = "";
let pzuPortfolioImportPollTimer = 0;

function setPzuPortfolioImportStatus(message, state = "running") {
  if (!elements.pzuPortfolioImportStatus) return;
  elements.pzuPortfolioImportStatus.hidden = !message;
  elements.pzuPortfolioImportStatus.textContent = message || "";
  elements.pzuPortfolioImportStatus.dataset.state = state;
}

function finishPzuPortfolioOpenPolling() {
  pzuPortfolioOpenActive = false;
  globalThis.clearTimeout(pzuPortfolioOpenPollTimer);
  if (elements.pzuPortfolioOpenButton) elements.pzuPortfolioOpenButton.disabled = false;
}

function finishPzuPortfolioImportPolling() {
  pzuPortfolioImportActive = false;
  globalThis.clearTimeout(pzuPortfolioImportPollTimer);
  if (elements.pzuPortfolioImportButton) elements.pzuPortfolioImportButton.disabled = false;
}








function normalizeImportedPzuPortfolioPolicy(entry) {
  return {
    clientName: String(entry?.clientName || "").trim(),
    identityNumber: String(entry?.identityNumber || "").trim(),
    contact: "",
    riskSummary: String(entry?.riskSummary || "").trim(),
    insurer: "PZU",
    policyNumber: String(entry?.policyNumber || "").trim(),
    registration: String(entry?.registration || "").trim() || "Inne",
    vehicleMake: String(entry?.vehicleMake || "").trim(),
    vehicleModel: String(entry?.vehicleModel || "").trim(),
    vin: String(entry?.vin || "").trim(),
    issueDate: String(entry?.issueDate || "").trim(),
    validFrom: String(entry?.validFrom || "").trim(),
    validUntil: String(entry?.validUntil || "").trim(),
    premium: String(entry?.premium || "").trim(),
  };
}

function resolvePzuSecondaryIdentity(entry) {
  const regon = String(entry?.regon || "").trim();
  const pesel = String(entry?.pesel || "").trim();
  
  return regon && pesel ? pesel : "";
}

function applyPzuPortfolioMerge(importedEntries) {
  return applyConfiguredPortfolioMerge(importedEntries, getPortfolioMergeConfiguration("pzu"));
}

async function finalizePzuPortfolioImport(importedEntries, pdfQueueRemaining = null, job = null) {
  return runPortfolioImportCore(
    importedEntries,
    pdfQueueRemaining,
    job,
    getPortfolioImportCoreConfiguration("pzu"),
  );
}

async function applyPzuPortfolioOpenJobState(job) {
  if (!job || job.id !== pzuPortfolioOpenJobId) return;
  if (job.status === "completed") {
    finishPzuPortfolioOpenPolling();
    setPzuPortfolioImportStatus(`${job.title}${job.detail ? ` - ${job.detail}` : ""}`, "success");
    return;
  }
  if (job.status === "manual_required" || job.status === "error") {
    finishPzuPortfolioOpenPolling();
    setPzuPortfolioImportStatus(`${job.title}${job.detail ? ` - ${job.detail}` : ""}`, "error");
    return;
  }
  setPzuPortfolioImportStatus(`${job.title}${job.detail ? ` - ${job.detail}` : ""}`);
  pzuPortfolioOpenPollTimer = globalThis.setTimeout(pollPzuPortfolioOpenJob, 900);
}

async function pollPzuPortfolioOpenJob() {
  if (!pzuPortfolioOpenActive || !pzuPortfolioOpenJobId) return;
  try {
    const response = await apiFetch(`/api/automation/jobs/${encodeURIComponent(pzuPortfolioOpenJobId)}`, { cache: "no-store" });
    const data = await response.json();
    if (!response.ok) throw new Error(data?.error || "Nie udało się odczytać stanu otwierania okna PZU.");
    await applyPzuPortfolioOpenJobState(data.job);
  } catch (error) {
    finishPzuPortfolioOpenPolling();
    setPzuPortfolioImportStatus(error?.message || "Utracono połączenie z lokalnym serwerem automatyzacji.", "error");
  }
}

async function startPzuPortfolioOpen() {
  if (!canUseAgencyInsurerFeature("pzu", "PZU")) return;
  if (pzuPortfolioOpenActive || pzuPortfolioImportActive) return;
  if (!(await checkWartaAutomationBridge())) {
    setPzuPortfolioImportStatus("Automatyzacja jest nieaktywna. Uruchom aplikację plikiem „Uruchom Baza Polis.cmd”.", "error");
    return;
  }
  pzuPortfolioOpenActive = true;
  if (elements.pzuPortfolioOpenButton) elements.pzuPortfolioOpenButton.disabled = true;
  setPzuPortfolioImportStatus("Otwieranie okna PZU…");
  try {
    const response = await apiFetch("/api/pzu/portfolio/open", {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({ username: uiSettings.calculatorAccounts?.pzu?.username || "" }),
    });
    const data = await response.json();
    if (!response.ok) throw new Error(data?.error || "Nie udało się otworzyć okna PZU.");
    pzuPortfolioOpenJobId = data.job.id;
    await applyPzuPortfolioOpenJobState(data.job);
  } catch (error) {
    finishPzuPortfolioOpenPolling();
    setPzuPortfolioImportStatus(error?.message || "Nie udało się otworzyć okna PZU.", "error");
  }
}

async function applyPzuPortfolioImportJobState(job) {
  return applyConfiguredPortfolioImportJobState(
    job,
    getPortfolioImportRuntimeConfiguration("pzu"),
  );
}

async function pollPzuPortfolioImportJob() {
  return pollConfiguredPortfolioImportJob(
    getPortfolioImportRuntimeConfiguration("pzu"),
  );
}

async function startPzuPortfolioImport(options = {}) {
  if (!canUseAgencyInsurerFeature("pzu", "PZU")) return;
  if (pzuPortfolioImportActive || pzuPortfolioOpenActive) return;
  if (!(await checkWartaAutomationBridge())) {
    setPzuPortfolioImportStatus("Automatyzacja jest nieaktywna. Uruchom aplikację plikiem „Uruchom Baza Polis.cmd”.", "error");
    return;
  }
  pzuPortfolioImportActive = true;
  if (elements.pzuPortfolioImportButton) elements.pzuPortfolioImportButton.disabled = true;
  const downloadPdfs = elements.pzuPortfolioDownloadPdfs?.checked === true;
  
  
  const pzuPolicies = policies.filter((policy) => policy.insurer === "PZU");
  const skipPolicyNumbers = downloadPdfs ? getPortfolioPdfSkipKeys(pzuPolicies) : [];
  
  
  const knownPolicyNumbers = downloadPdfs
    ? getKnownPortfolioPdfIdentities(pzuPolicies)
    : [];
  setPzuPortfolioImportStatus(downloadPdfs
    ? "Rozpoczynanie importu polis z PZU (z pobieraniem PDF-ów)…"
    : "Rozpoczynanie importu polis z PZU…");
  try {
    const response = await apiFetch("/api/pzu/portfolio", {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify(limitPortfolioPdfRequestPayload({
        downloadPdfs,
        ...getPortfolioFullReimportRequestFields(options),
        skipPdfPolicyNumbers: skipPolicyNumbers.slice(0, 5000),
        knownPolicyNumbers: knownPolicyNumbers.slice(0, 10000),
        username: uiSettings.calculatorAccounts?.pzu?.username || "",
      })),
    });
    const data = await response.json();
    if (!response.ok) throw new Error(data?.error || "Nie udało się rozpocząć importu polis PZU.");
    pzuPortfolioImportJobId = data.job.id;
    await applyPzuPortfolioImportJobState(data.job);
  } catch (error) {
    finishPzuPortfolioImportPolling();
    setPzuPortfolioImportStatus(error?.message || "Nie udało się rozpocząć importu polis PZU.", "error");
  }
}

function updatePzuPortfolioPdfOptions() {
  const enabled = elements.pzuPortfolioDownloadPdfs?.checked === true;
  if (elements.pzuPortfolioPdfOptions) elements.pzuPortfolioPdfOptions.dataset.enabled = enabled ? "true" : "false";
}

elements.pzuPortfolioOpenButton?.addEventListener("click", startPzuPortfolioOpen);
elements.pzuPortfolioImportButton?.addEventListener("click", startPzuPortfolioImport);
elements.pzuPortfolioDownloadPdfs?.addEventListener("change", updatePzuPortfolioPdfOptions);
updatePzuPortfolioPdfOptions();




let inslyPortfolioOpenActive = false;
let inslyPortfolioOpenJobId = "";
let inslyPortfolioOpenPollTimer = 0;
let inslyPortfolioImportActive = false;
let inslyPortfolioImportJobId = "";
let inslyPortfolioImportPollTimer = 0;

function setInslyPortfolioImportStatus(message, state = "running") {
  if (!elements.inslyPortfolioImportStatus) return;
  elements.inslyPortfolioImportStatus.hidden = !message;
  elements.inslyPortfolioImportStatus.textContent = message || "";
  elements.inslyPortfolioImportStatus.dataset.state = state;
}

function finishInslyPortfolioOpenPolling() {
  inslyPortfolioOpenActive = false;
  globalThis.clearTimeout(inslyPortfolioOpenPollTimer);
  if (elements.inslyPortfolioOpenButton) elements.inslyPortfolioOpenButton.disabled = false;
}

function finishInslyPortfolioImportPolling() {
  inslyPortfolioImportActive = false;
  globalThis.clearTimeout(inslyPortfolioImportPollTimer);
  if (elements.inslyPortfolioImportButton) elements.inslyPortfolioImportButton.disabled = false;
}



function normalizeImportedInslyPortfolioPolicy(entry) {
  return {
    clientName: String(entry?.clientName || "").trim(),
    identityNumber: String(entry?.identityNumber || "").trim(),
    contact: String(entry?.contact || "").trim(),
    riskSummary: "",
    insurer: String(entry?.insurer || "").trim(),
    policyNumber: String(entry?.policyNumber || "").trim(),
    registration: String(entry?.registration || "").trim() || "Inne",
    vehicleMake: String(entry?.vehicleMake || "").trim(),
    vehicleModel: String(entry?.vehicleModel || "").trim(),
    vin: String(entry?.vin || "").trim(),
    clientAddress: String(entry?.clientAddress || "").trim(),
    issueDate: String(entry?.issueDate || "").trim(),
    validFrom: String(entry?.validFrom || "").trim(),
    validUntil: String(entry?.validUntil || "").trim(),
    premium: String(entry?.premium || "").trim(),
  };
}

function getOpaquePortfolioPdfFileKey(entry) {
  const key = String(entry?.pdfKey || "").trim();
  return /^[0-9A-Za-z_-]{32}$/.test(key) ? key : "";
}

function getInslyPdfPolicyCompositeKey(policy) {
  return getPortfolioPdfIdentityKey(createPortfolioPdfIdentity(policy));
}

function buildInslyPortfolioRequestPayload(downloadPdfs, options = {}) {
  const payload = {
    username: uiSettings.calculatorAccounts?.insly?.username || "",
    downloadPdfs: downloadPdfs === true,
    ...getPortfolioFullReimportRequestFields(options),
    skipPdfPolicyKeys: [],
    knownPdfPolicyKeys: [],
  };
  if (!payload.downloadPdfs) return payload;
  const skipKeys = getPortfolioPdfSkipKeys(policies)
    .slice(0, 5_000);
  const skipKeySet = new Set(skipKeys.map(getInslyPdfPolicyCompositeKey));
  const knownKeys = getKnownPortfolioPdfIdentities(policies)
    .filter((identity) => !skipKeySet.has(getInslyPdfPolicyCompositeKey(identity)))
    .slice(0, 10_000);
  return limitPortfolioPdfRequestPayload({
    ...payload,
    skipPdfPolicyKeys: skipKeys,
    knownPdfPolicyKeys: knownKeys,
  });
}

function prepareInslyPortfolioImport(importedEntries) {
  if (!Array.isArray(importedEntries) || importedEntries.length === 0) {
    throw new Error("Import z Superpolisy nie zawiera kompletnej listy polis.");
  }
  const normalizedEntries = importedEntries.map(normalizeImportedInslyPortfolioPolicy);
  const identities = new Set();
  for (let index = 0; index < normalizedEntries.length; index += 1) {
    const imported = normalizedEntries[index];
    if (importedEntries[index]?.pdfAvailable === true && !getOpaquePortfolioPdfFileKey(importedEntries[index])) {
      throw new Error("Import z Superpolisy nie zawiera bezpiecznego identyfikatora pliku PDF.");
    }
    const identityKey = getPolicyIdentityKey(imported);
    if (!identityKey || !imported.clientName || !getPortfolioInsurerKey(imported)) {
      throw new Error("Import z Superpolisy zawiera niepełny rekord. Nie zapisano żadnych zmian.");
    }
    
    
    const identityPeriodKey = getPolicyIdentityPeriodKey(imported);
    if (identities.has(identityPeriodKey)) {
      throw new Error("Import z Superpolisy zawiera powtórzoną polisę tego samego TU. Nie zapisano żadnych zmian.");
    }
    identities.add(identityPeriodKey);
  }
  return normalizedEntries;
}

function getInslyPortfolioJobBlocker(job) {
  const globalError = String(job?.pdfGlobalError || job?.globalError || "").trim();
  if (globalError) {
    return "Nie można potwierdzić kompletności pobierania PDF-ów z Superpolisy. Import nie został zatwierdzony; ponów go.";
  }
  return "";
}

function applyInslyPortfolioMerge(importedEntries) {
  return applyConfiguredPortfolioMerge(importedEntries, getPortfolioMergeConfiguration("insly"));
}

async function finalizeInslyPortfolioImport(importedEntries, pdfQueueRemaining = null, job = null) {
  return runPortfolioImportCore(
    importedEntries,
    pdfQueueRemaining,
    job,
    getPortfolioImportCoreConfiguration("insly"),
  );
}

async function applyInslyPortfolioOpenJobState(job) {
  if (!job || job.id !== inslyPortfolioOpenJobId) return;
  if (job.status === "completed") {
    finishInslyPortfolioOpenPolling();
    setInslyPortfolioImportStatus(`${job.title}${job.detail ? ` - ${job.detail}` : ""}`, "success");
    return;
  }
  if (job.status === "manual_required" || job.status === "error") {
    finishInslyPortfolioOpenPolling();
    setInslyPortfolioImportStatus(`${job.title}${job.detail ? ` - ${job.detail}` : ""}`, "error");
    return;
  }
  setInslyPortfolioImportStatus(`${job.title}${job.detail ? ` - ${job.detail}` : ""}`);
  inslyPortfolioOpenPollTimer = globalThis.setTimeout(pollInslyPortfolioOpenJob, 900);
}

async function pollInslyPortfolioOpenJob() {
  if (!inslyPortfolioOpenActive || !inslyPortfolioOpenJobId) return;
  try {
    const response = await apiFetch(`/api/automation/jobs/${encodeURIComponent(inslyPortfolioOpenJobId)}`, { cache: "no-store" });
    const data = await response.json();
    if (!response.ok) throw new Error(data?.error || "Nie udało się odczytać stanu otwierania okna Superpolisy.");
    await applyInslyPortfolioOpenJobState(data.job);
  } catch (error) {
    finishInslyPortfolioOpenPolling();
    setInslyPortfolioImportStatus(error?.message || "Utracono połączenie z lokalnym serwerem automatyzacji.", "error");
  }
}

async function startInslyPortfolioOpen() {
  if (inslyPortfolioOpenActive || inslyPortfolioImportActive) return;
  if (!(await checkWartaAutomationBridge())) {
    setInslyPortfolioImportStatus("Automatyzacja jest nieaktywna. Uruchom aplikację plikiem „Uruchom Baza Polis.cmd”.", "error");
    return;
  }
  inslyPortfolioOpenActive = true;
  if (elements.inslyPortfolioOpenButton) elements.inslyPortfolioOpenButton.disabled = true;
  setInslyPortfolioImportStatus("Otwieranie okna Superpolisy…");
  try {
    const response = await apiFetch("/api/insly/portfolio/open", {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({ username: uiSettings.calculatorAccounts?.insly?.username || "" }),
    });
    const data = await response.json();
    if (!response.ok) throw new Error(data?.error || "Nie udało się otworzyć okna Superpolisy.");
    inslyPortfolioOpenJobId = data.job.id;
    await applyInslyPortfolioOpenJobState(data.job);
  } catch (error) {
    finishInslyPortfolioOpenPolling();
    setInslyPortfolioImportStatus(error?.message || "Nie udało się otworzyć okna Superpolisy.", "error");
  }
}

async function applyInslyPortfolioImportJobState(job) {
  return applyConfiguredPortfolioImportJobState(
    job,
    getPortfolioImportRuntimeConfiguration("insly"),
  );
}

async function pollInslyPortfolioImportJob() {
  return pollConfiguredPortfolioImportJob(
    getPortfolioImportRuntimeConfiguration("insly"),
  );
}

async function startInslyPortfolioImport(options = {}) {
  if (inslyPortfolioImportActive || inslyPortfolioOpenActive) return;
  if (!(await checkWartaAutomationBridge())) {
    setInslyPortfolioImportStatus("Automatyzacja jest nieaktywna. Uruchom aplikację plikiem „Uruchom Baza Polis.cmd”.", "error");
    return;
  }
  inslyPortfolioImportActive = true;
  if (elements.inslyPortfolioImportButton) elements.inslyPortfolioImportButton.disabled = true;
  const downloadPdfs = elements.inslyPortfolioDownloadPdfs?.checked === true;
  
  
  const requestPayload = buildInslyPortfolioRequestPayload(downloadPdfs, options);
  setInslyPortfolioImportStatus(downloadPdfs
    ? "Rozpoczynanie importu polis z Superpolisy (z pobieraniem PDF-ów)…"
    : "Rozpoczynanie importu polis z Superpolisy…");
  try {
    const response = await apiFetch("/api/insly/portfolio", {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify(requestPayload),
    });
    const data = await response.json();
    if (!response.ok) throw new Error(data?.error || "Nie udało się rozpocząć importu polis z Superpolisy.");
    inslyPortfolioImportJobId = data.job.id;
    await applyInslyPortfolioImportJobState(data.job);
  } catch (error) {
    finishInslyPortfolioImportPolling();
    setInslyPortfolioImportStatus(error?.message || "Nie udało się rozpocząć importu polis z Superpolisy.", "error");
  }
}

function updateInslyPortfolioPdfOptions() {
  const enabled = elements.inslyPortfolioDownloadPdfs?.checked === true;
  if (elements.inslyPortfolioPdfOptions) elements.inslyPortfolioPdfOptions.dataset.enabled = enabled ? "true" : "false";
}

elements.inslyPortfolioOpenButton?.addEventListener("click", startInslyPortfolioOpen);
elements.inslyPortfolioImportButton?.addEventListener("click", startInslyPortfolioImport);
elements.inslyPortfolioDownloadPdfs?.addEventListener("change", updateInslyPortfolioPdfOptions);
updateInslyPortfolioPdfOptions();

async function resumeUnconsumedPortfolioJob(job) {
  const jobId = String(job?.id || "");
  if (!jobId) return false;
  switch (String(job.insurerId || "")) {
    case "mtu":
      mtuPortfolioImportJobId = jobId;
      if (job.status === "consumed") {
        mtuPortfolioImportActive = false;
        const retryHint = describePortfolioPdfRetryStatus(job.pdfRetry);
        setMtuPortfolioImportStatus(
          `Import MTU jest już zapisany.${retryHint ? ` ${retryHint}` : ""}`,
          job?.pdfRetry?.manualRetryAvailable === true ? "warning" : "success",
        );
        return true;
      }
      mtuPortfolioImportActive = true;
      if (elements.mtuPortfolioImportButton) elements.mtuPortfolioImportButton.disabled = true;
      setMtuPortfolioImportStatus("Odzyskiwanie niezatwierdzonego importu MTU…");
      return applyMtuPortfolioImportJobState(job);
    case "hestia":
      hestiaPortfolioImportJobId = jobId;
      if (job.status === "consumed") {
        hestiaPortfolioImportActive = false;
        const retryHint = describePortfolioPdfRetryStatus(job.pdfRetry);
        setHestiaPortfolioImportStatus(
          `Import Ergo Hestii jest już zapisany.${retryHint ? ` ${retryHint}` : ""}`,
          job?.pdfRetry?.manualRetryAvailable === true ? "warning" : "success",
        );
        return true;
      }
      hestiaPortfolioImportActive = true;
      if (elements.hestiaPortfolioImportButton) elements.hestiaPortfolioImportButton.disabled = true;
      setHestiaPortfolioImportStatus("Odzyskiwanie niezatwierdzonego importu Ergo Hestii…");
      return applyHestiaPortfolioImportJobState(job);
    case "wiener":
      wienerPortfolioImportJobId = jobId;
      if (job.status === "consumed") {
        wienerPortfolioImportActive = false;
        const retryHint = describePortfolioPdfRetryStatus(job.pdfRetry);
        setWienerPortfolioImportStatus(
          `Import Wiener jest już zapisany.${retryHint ? ` ${retryHint}` : ""}`,
          job?.pdfRetry?.manualRetryAvailable === true ? "warning" : "success",
        );
        return true;
      }
      wienerPortfolioImportActive = true;
      if (elements.wienerPortfolioImportButton) elements.wienerPortfolioImportButton.disabled = true;
      setWienerPortfolioImportStatus("Odzyskiwanie niezatwierdzonego importu Wiener…");
      return applyWienerPortfolioImportJobState(job);
    case "generali":
      generaliPortfolioImportJobId = jobId;
      if (job.status === "consumed") {
        generaliPortfolioImportActive = false;
        const retryHint = describePortfolioPdfRetryStatus(job.pdfRetry);
        setGeneraliPortfolioImportStatus(
          `Import Generali jest już zapisany.${retryHint ? ` ${retryHint}` : ""}`,
          job?.pdfRetry?.manualRetryAvailable === true ? "warning" : "success",
        );
        return true;
      }
      generaliPortfolioImportActive = true;
      if (elements.generaliPortfolioImportButton) elements.generaliPortfolioImportButton.disabled = true;
      setGeneraliPortfolioImportStatus("Odzyskiwanie niezatwierdzonego importu Generali…");
      return applyGeneraliPortfolioImportJobState(job);
    case "trasti":
      trastiPortfolioImportJobId = jobId;
      if (job.status === "consumed") {
        trastiPortfolioImportActive = false;
        const retryHint = describePortfolioPdfRetryStatus(job.pdfRetry);
        setTrastiPortfolioImportStatus(
          `Import Trasti jest już zapisany.${retryHint ? ` ${retryHint}` : ""}`,
          job?.pdfRetry?.manualRetryAvailable === true ? "warning" : "success",
        );
        return true;
      }
      trastiPortfolioImportActive = true;
      if (elements.trastiPortfolioImportButton) elements.trastiPortfolioImportButton.disabled = true;
      setTrastiPortfolioImportStatus("Odzyskiwanie niezatwierdzonego importu Trasti…");
      return applyTrastiPortfolioImportJobState(job);
    case "warta":
      wartaPortfolioImportJobId = jobId;
      if (job.status === "consumed") {
        wartaPortfolioImportActive = false;
        const retryHint = describePortfolioPdfRetryStatus(job.pdfRetry);
        setWartaPortfolioImportStatus(
          `Import Warty jest już zapisany.${retryHint ? ` ${retryHint}` : ""}`,
          job?.pdfRetry?.manualRetryAvailable === true ? "warning" : "success",
        );
        return true;
      }
      wartaPortfolioImportActive = true;
      if (elements.wartaPortfolioImportButton) elements.wartaPortfolioImportButton.disabled = true;
      setWartaPortfolioImportStatus("Odzyskiwanie niezatwierdzonego importu Warty…");
      return applyWartaPortfolioImportJobState(job);
    case "pzu":
      pzuPortfolioImportJobId = jobId;
      if (job.status === "consumed") {
        pzuPortfolioImportActive = false;
        const retryHint = describePortfolioPdfRetryStatus(job.pdfRetry);
        setPzuPortfolioImportStatus(
          `Import PZU jest już zapisany.${retryHint ? ` ${retryHint}` : ""}`,
          job?.pdfRetry?.manualRetryAvailable === true ? "warning" : "success",
        );
        return true;
      }
      pzuPortfolioImportActive = true;
      if (elements.pzuPortfolioImportButton) elements.pzuPortfolioImportButton.disabled = true;
      setPzuPortfolioImportStatus("Odzyskiwanie niezatwierdzonego importu PZU…");
      return applyPzuPortfolioImportJobState(job);
    case "allianz":
      allianzPortfolioImportJobId = jobId;
      if (job.status === "consumed") {
        allianzPortfolioImportActive = false;
        setAllianzPortfolioImportStatus("Import Allianz jest już zapisany.", "success");
        return true;
      }
      allianzPortfolioImportActive = true;
      if (elements.allianzPortfolioImportButton) elements.allianzPortfolioImportButton.disabled = true;
      setAllianzPortfolioImportStatus("Odzyskiwanie niezatwierdzonego importu Allianz…");
      return applyAllianzPortfolioImportJobState(job);
    case "compensa":
      compensaPortfolioImportJobId = jobId;
      compensaPortfolioImportActive = true;
      if (elements.compensaPortfolioImportButton) elements.compensaPortfolioImportButton.disabled = true;
      setCompensaPortfolioImportStatus("Odzyskiwanie niezatwierdzonego importu Compensy…");
      return applyCompensaPortfolioImportJobState(job);
    case "insly":
      inslyPortfolioImportJobId = jobId;
      inslyPortfolioImportActive = true;
      if (elements.inslyPortfolioImportButton) elements.inslyPortfolioImportButton.disabled = true;
      setInslyPortfolioImportStatus("Odzyskiwanie niezatwierdzonego importu z Superpolisy…");
      return applyInslyPortfolioImportJobState(job);
    default:
      return false;
  }
}

const TERMINAL_PORTFOLIO_JOB_STATUSES = new Set(["completed", "consumed", "error", "manual_required"]);

function noteRecoveredPortfolioImportJob(job) {
  
  
  if (!job || TERMINAL_PORTFOLIO_JOB_STATUSES.has(String(job.status || ""))) return;
  adoptRecoveredPortfolioImport(String(job.insurerId || ""), job);
}

async function recoverUnconsumedPortfolioImports() {
  if (isEmployeeAccount()) return;
  try {
    const response = await apiFetch("/api/automation/jobs?unconsumedPortfolio=1", { cache: "no-store" });
    const data = await response.json();
    if (!response.ok) throw new Error(data?.error || "Nie udało się odczytać importów oczekujących na odbiór.");
    const recoverableJobs = (Array.isArray(data?.jobs) ? data.jobs : [])
      .filter((job) => (
        job?.kind === "portfolio"
        && (
          job.status === "queued"
          || job.status === "running"
          || job.status === "action_required"
          || job.status === "input_required"
          || job.status === "completed"
          || (
            (
              (job.insurerId === "warta" || job.insurerId === "wiener")
              || job.insurerId === "mtu"
              || job.insurerId === "hestia"
              || job.insurerId === "generali"
              || job.insurerId === "trasti"
              || job.insurerId === "pzu"
            )
            && job.status === "consumed"
            && job?.pdfRetry?.manualRetryAvailable === true
          )
        )
      ))
      .sort((left, right) => (left.createdAt || 0) - (right.createdAt || 0));
    for (const job of recoverableJobs) {
      try {
        noteRecoveredPortfolioImportJob(job);
        await resumeUnconsumedPortfolioJob(job);
      } catch (error) {
        console.warn(`Nie udało się odzyskać importu ${job?.insurer || job?.insurerId || ""}.`, error);
      }
    }
  } catch (error) {
    
    
    console.warn("Nie udało się odzyskać niezatwierdzonych importów portfela.", error);
  }
}

elements.toggleTrastiPassword.addEventListener("click", toggleTrastiPasswordVisibility);
elements.clearTrastiCredentials.addEventListener("click", clearTrastiSavedPassword);
elements.clearTrastiNavigationPath.addEventListener("click", clearTrastiSavedNavigationPath);
elements.importTrastiNavigationPath.addEventListener("click", () => elements.trastiNavigationPathInput.click());
elements.trastiNavigationPathInput.addEventListener("change", importTrastiNavigationPath);
elements.restoreTrastiNavigationPath.addEventListener("click", () => restoreSavedNavigationPath({
  insurer: "trasti",
  label: "Trasti",
  buttonKey: "restoreTrastiNavigationPath",
  onRestored: () => {
    trastiPathSaved = true;
    updateTrastiNavigationHint();
  },
}));
elements.trastiPasswordSetting.addEventListener("focus", beginEditingTrastiPassword);
elements.trastiPasswordSetting.addEventListener("blur", restoreTrastiPasswordMask);
elements.trastiPasswordSetting.addEventListener("input", () => {
  if (isTrastiPasswordMaskActive() && elements.trastiPasswordSetting.value !== SAVED_CALCULATOR_PASSWORD_MASK) {
    delete elements.trastiPasswordSetting.dataset.savedPasswordMask;
    resetTrastiPasswordToggle();
  }
  if (elements.trastiPasswordSetting.value.length > MAX_CALCULATOR_PASSWORD_LENGTH) {
    elements.trastiPasswordSetting.value = elements.trastiPasswordSetting.value.slice(0, MAX_CALCULATOR_PASSWORD_LENGTH);
  }
});
elements.toggleWienerPassword.addEventListener("click", toggleWienerPasswordVisibility);
elements.clearWienerCredentials.addEventListener("click", clearWienerSavedPassword);
elements.clearWienerNavigationPath.addEventListener("click", clearWienerSavedNavigationPath);
elements.importWienerNavigationPath.addEventListener("click", () => elements.wienerNavigationPathInput.click());
elements.wienerNavigationPathInput.addEventListener("change", importWienerNavigationPath);
elements.restoreWienerNavigationPath.addEventListener("click", () => restoreSavedNavigationPath({
  insurer: "wiener",
  label: "Wiener",
  buttonKey: "restoreWienerNavigationPath",
  onRestored: () => {
    wienerPathSaved = true;
    updateWienerNavigationHint();
  },
}));
elements.wienerPasswordSetting.addEventListener("focus", beginEditingWienerPassword);
elements.wienerPasswordSetting.addEventListener("blur", restoreWienerPasswordMask);
elements.wienerPasswordSetting.addEventListener("input", () => {
  if (isWienerPasswordMaskActive() && elements.wienerPasswordSetting.value !== SAVED_CALCULATOR_PASSWORD_MASK) {
    delete elements.wienerPasswordSetting.dataset.savedPasswordMask;
    resetWienerPasswordToggle();
  }
  if (elements.wienerPasswordSetting.value.length > MAX_CALCULATOR_PASSWORD_LENGTH) {
    elements.wienerPasswordSetting.value = elements.wienerPasswordSetting.value.slice(0, MAX_CALCULATOR_PASSWORD_LENGTH);
  }
});
elements.toggleCompensaPassword.addEventListener("click", toggleCompensaPasswordVisibility);
elements.clearCompensaCredentials.addEventListener("click", clearCompensaSavedPassword);
elements.clearCompensaNavigationPath.addEventListener("click", clearCompensaSavedNavigationPath);
elements.importCompensaNavigationPath.addEventListener("click", () => elements.compensaNavigationPathInput.click());
elements.compensaNavigationPathInput.addEventListener("change", importCompensaNavigationPath);
elements.restoreCompensaNavigationPath.addEventListener("click", () => restoreSavedNavigationPath({
  insurer: "compensa",
  label: "Compensa",
  buttonKey: "restoreCompensaNavigationPath",
  onRestored: () => {
    compensaPathSaved = true;
    updateCompensaNavigationHint();
  },
}));
elements.compensaPasswordSetting.addEventListener("focus", beginEditingCompensaPassword);
elements.compensaPasswordSetting.addEventListener("blur", restoreCompensaPasswordMask);
elements.compensaPasswordSetting.addEventListener("input", () => {
  if (isCompensaPasswordMaskActive() && elements.compensaPasswordSetting.value !== SAVED_CALCULATOR_PASSWORD_MASK) {
    delete elements.compensaPasswordSetting.dataset.savedPasswordMask;
    resetCompensaPasswordToggle();
  }
  if (elements.compensaPasswordSetting.value.length > MAX_CALCULATOR_PASSWORD_LENGTH) {
    elements.compensaPasswordSetting.value = elements.compensaPasswordSetting.value.slice(0, MAX_CALCULATOR_PASSWORD_LENGTH);
  }
});
elements.toggleAllianzPassword.addEventListener("click", toggleAllianzPasswordVisibility);
elements.clearAllianzCredentials.addEventListener("click", clearAllianzSavedPassword);
elements.allianzPasswordSetting.addEventListener("focus", beginEditingAllianzPassword);
elements.allianzPasswordSetting.addEventListener("blur", restoreAllianzPasswordMask);
elements.allianzPasswordSetting.addEventListener("input", () => {
  if (isAllianzPasswordMaskActive() && elements.allianzPasswordSetting.value !== SAVED_CALCULATOR_PASSWORD_MASK) {
    delete elements.allianzPasswordSetting.dataset.savedPasswordMask;
    resetAllianzPasswordToggle();
  }
  if (elements.allianzPasswordSetting.value.length > MAX_CALCULATOR_PASSWORD_LENGTH) {
    elements.allianzPasswordSetting.value = elements.allianzPasswordSetting.value.slice(0, MAX_CALCULATOR_PASSWORD_LENGTH);
  }
});
elements.settingsLogoInput.addEventListener("change", handleSettingsLogoFile);
elements.resetSettingsLogo.addEventListener("click", resetSettingsLogo);
elements.welcomeQuickSetup.addEventListener("click", chooseAppDirectory);
elements.welcomeOpenDataFile.addEventListener("click", openDataFile);
elements.welcomeCreateDataFile.addEventListener("click", saveDataFileAs);
elements.welcomeOpenSettingsFile.addEventListener("click", openSettingsFileFromPicker);
elements.welcomeCreateSettingsFile.addEventListener("click", () => saveSettingsFileAs(uiSettings));
elements.finishInitialSetup.addEventListener("click", finishInitialSetup);
elements.welcomeDialog.addEventListener("cancel", (event) => event.preventDefault());
elements.welcomeDialog.addEventListener("close", () => {
  if (initialDataFileReady && initialSettingsFileReady) return;
  setTimeout(() => {
    if (!elements.welcomeDialog.open && !(initialDataFileReady && initialSettingsFileReady)) {
      elements.welcomeDialog.showModal();
    }
  }, 0);
});
elements.settingsDialog.addEventListener("cancel", () => {
  applyTheme(settingsOpeningTheme);
  applyFontSize(settingsOpeningFontSize);
  applyStartDateInputSetting(settingsOpeningShowStartDateInput);
  applyUsageGuideSetting(settingsOpeningShowUsageGuide);
  resetWartaPasswordEditor();
  resetGeneraliPasswordEditor();
  resetMtuPasswordEditor();
  resetTrastiPasswordEditor();
  resetWienerPasswordEditor();
  resetCompensaPasswordEditor();
  resetAllianzPasswordEditor();
});
elements.clearPolicyForm.addEventListener("click", clearPolicyFormFields);
elements.importPolicies.addEventListener("click", () => {
  elements.policyImportInput.click();
});
elements.importPolicies.addEventListener("dragenter", (event) => {
  if (!isAttachmentFileDrag(event) || attachmentOperationActive) return;
  event.preventDefault();
  setPolicyImportDropTargetActive(true);
});
elements.importPolicies.addEventListener("dragover", (event) => {
  if (!isAttachmentFileDrag(event)) return;
  event.preventDefault();
  event.dataTransfer.dropEffect = attachmentOperationActive ? "none" : "copy";
});
elements.importPolicies.addEventListener("dragleave", (event) => {
  if (event.relatedTarget instanceof Node && elements.importPolicies.contains(event.relatedTarget)) return;
  setPolicyImportDropTargetActive(false);
});
elements.importPolicies.addEventListener("drop", importDroppedPolicyFiles);
elements.policyImportInput.addEventListener("change", () => {
  importPolicyFiles(elements.policyImportInput.files);
});
elements.resolveDataIntegrity.addEventListener("click", resolveDataIntegrityIssue);
elements.dismissDataIntegrity.addEventListener("click", () => {
  elements.dataIntegrityBanner.hidden = true;
});
elements.policyAttachmentInput.addEventListener("change", () => {
  addPendingAttachmentFiles(elements.policyAttachmentInput.files);
});
elements.clearPendingAttachments.addEventListener("click", () => {
  clearNewPolicyAttachments();
  showToast("Usunięto załączniki z nowego rekordu");
});
elements.pendingAttachmentList.addEventListener("click", (event) => {
  const removeButton = event.target.closest?.("[data-pending-attachment-id]");
  if (!removeButton) return;
  pendingAttachments = pendingAttachments.filter((attachment) => attachment.id !== removeButton.dataset.pendingAttachmentId);
  renderPendingAttachments();
});
elements.recordAttachmentInput.addEventListener("change", async () => {
  const policyId = recordAttachmentPolicyId;
  const selectedFiles = [...elements.recordAttachmentInput.files];
  elements.recordAttachmentInput.value = "";
  recordAttachmentPolicyId = null;
  if (!policyId || selectedFiles.length === 0) return;
  const category = await requestAttachmentCategory(selectedFiles);
  if (category === null) return;
  await addAttachmentsToPolicy(policyId, selectedFiles, category);
});
elements.clientNameInput.addEventListener("input", updateAddFormIdentityFromClientName);
elements.clientNameInput.addEventListener("input", updateAddPolicyButtonState);
elements.identityNumberInput.addEventListener("input", () => {
  if (String(elements.identityNumberInput.value ?? "").trim() !== addFormAutoFilledIdentity) {
    addFormAutoFilledIdentity = "";
  }
});
elements.contactInput.addEventListener("input", () => resizeAutoGrowingTextarea(elements.contactInput));
elements.registrationInput.addEventListener("input", () => {
  delete elements.form.dataset.importedValidFrom;
  updateAddFormEndDateForPolicyType();
});
elements.validFromInput.addEventListener("input", () => {
  delete elements.form.dataset.importedValidFrom;
  if (!elements.validFromInput.value) {
    elements.startDateFormField.dataset.manuallyEdited = "false";
    updateAddFormStartDateFromEnd();
    return;
  }
  elements.startDateFormField.dataset.manuallyEdited = "true";
  const isTravelPolicy = isTravelPolicySelected();
  const calculatedEndDate = isTravelPolicy
    ? calculateTravelEndDate(elements.validFromInput.value)
    : calculateEndDate(elements.validFromInput.value);
  elements.validUntilInput.value = formatDateForInput(calculatedEndDate);
  if (isTravelPolicy) elements.validUntilInput.dataset.travelDerived = "true";
  else delete elements.validUntilInput.dataset.travelDerived;
});
elements.validUntilInput.addEventListener("input", () => {
  delete elements.form.dataset.importedValidFrom;
  delete elements.validUntilInput.dataset.travelDerived;
  updateAddFormStartDateFromEnd();
});
elements.recordsPerPage.addEventListener("change", changeRecordsPerPage);
elements.paginationNav.addEventListener("click", (event) => {
  const pageButton = event.target.closest?.("[data-page]");
  if (pageButton) {
    goToPage(pageButton.dataset.page);
    return;
  }
  if (event.target.closest?.("[data-page-jump]")) {
    pageJumpOpen = true;
    updatePaginationControls(getVisiblePolicies().length);
    return;
  }
  if (event.target.closest?.("[data-page-jump-cancel]")) {
    pageJumpOpen = false;
    updatePaginationControls(getVisiblePolicies().length);
    return;
  }
  if (event.target.closest?.("[data-page-jump-confirm]")) {
    goToPage(elements.paginationNav.querySelector("[data-page-jump-input]")?.value);
  }
});
elements.paginationNav.addEventListener("keydown", (event) => {
  if (!event.target?.dataset || !("pageJumpInput" in event.target.dataset)) return;
  if (event.key === "Enter") {
    event.preventDefault();
    goToPage(event.target.value);
  } else if (event.key === "Escape") {
    pageJumpOpen = false;
    updatePaginationControls(getVisiblePolicies().length);
  }
});
elements.printPolicies.addEventListener("click", openPrintOptionsDialog);
elements.toggleRenewedPolicies.addEventListener("click", () => {
  hideRenewedPolicies = !hideRenewedPolicies;
  resetPaginationAndRender();
});
elements.toggleInactivePolicies.addEventListener("click", () => {
  hideInactivePolicies = !hideInactivePolicies;
  resetPaginationAndRender();
});
elements.closePrintOptions.addEventListener("click", closePrintOptionsDialog);
elements.cancelPrintOptions.addEventListener("click", closePrintOptionsDialog);
elements.confirmPrint.addEventListener("click", printVisiblePolicies);
elements.selectAllPrintColumns.addEventListener("click", () => setAllPrintColumns(true));
elements.clearAllPrintColumns.addEventListener("click", () => setAllPrintColumns(false));
printColumnInputs.forEach((input) => input.addEventListener("change", updatePrintOptionsState));
elements.clientProfileSearchForm.addEventListener("submit", (event) => {
  event.preventDefault();
  const policy = findClientProfilePolicy(elements.clientProfileSearch.value);
  if (!policy) {
    showToast("Nie znaleziono klienta. Wpisz nazwę, PESEL, numer polisy lub rejestrację.", "warning");
    elements.clientProfileSearch.focus();
    return;
  }
  clientProfilePolicyId = policy.id;
  clientProfileEditingPolicyId = null;
  clientProfileEditingVehicleKey = "";
  clientProfileVehicleHistoryHighlights.clear();
  clientProfileMergeOpen = false;
  clientProfileMergeSearchPolicyId = null;
  clientProfileLinkPanelOpen = false;
  clientProfileLinkSearchPolicyId = null;
  renderClientProfile();
  elements.clientProfileContent.scrollTo?.({ top: 0, behavior: "smooth" });
});
elements.clientProfileContent.addEventListener("submit", async (event) => {
  event.preventDefault();
  if (event.target.matches("#clientProfilePersonForm")) {
    await saveClientProfilePerson(event.target);
  } else if (event.target.matches("[data-client-profile-vehicle-form]")) {
    await saveClientProfileVehicle(event.target);
  } else if (event.target.matches("[data-client-profile-policy-form]")) {
    await saveClientProfilePolicy(event.target);
  } else if (event.target.matches("[data-client-profile-merge-search]")) {
    if (!CLIENT_PROFILE_MERGE_ENABLED) return;
    const query = String(event.target.elements.mergeQuery?.value ?? "");
    const excludedIds = new Set(getClientProfileCurrentPolicies().map((policy) => policy.id));
    const foundPolicy = findClientProfilePolicy(query, excludedIds);
    if (!foundPolicy) {
      showToast("Nie znaleziono innego konta pasującego do wyszukiwania", "warning");
      return;
    }
    clientProfileMergeSearchPolicyId = foundPolicy.id;
    renderClientProfile();
    elements.clientProfileContent.querySelector(".client-profile-merge-section")
      ?.scrollIntoView({ behavior: "smooth", block: "nearest" });
  } else if (event.target.matches("[data-client-profile-link-search]")) {
    const query = String(event.target.elements.linkQuery?.value ?? "");
    const excludedIds = new Set(getClientProfileCurrentPolicies().map((policy) => policy.id));
    const foundPolicy = findClientProfilePolicy(query, excludedIds);
    if (!foundPolicy) {
      showToast("Nie znaleziono innego konta pasującego do wyszukiwania", "warning");
      return;
    }
    clientProfileLinkSearchPolicyId = foundPolicy.id;
    renderClientProfile();
    elements.clientProfileContent.querySelector(".client-profile-link-section")
      ?.scrollIntoView({ behavior: "smooth", block: "nearest" });
  }
});
elements.clientProfileContent.addEventListener("input", (event) => {
  if (event.target.name === "clientPostalCode") {
    event.target.value = formatClientPostalCodeInput(event.target.value);
  } else if (event.target.name === "vin") {
    event.target.value = normalizeVehicleIdentifier(event.target.value);
  } else if (event.target.name === "identityPesel") {
    event.target.value = event.target.value.replace(/\D/g, "").slice(0, 11);
  } else if (event.target.name === "identityNip") {
    event.target.value = event.target.value.replace(/\D/g, "").slice(0, 10);
  } else if (event.target.name === "identityRegon") {
    event.target.value = event.target.value.replace(/\D/g, "").slice(0, 9);
  }
});
elements.clientProfileContent.addEventListener("click", (event) => {
  const editPolicyButton = event.target.closest("[data-client-profile-edit-policy]");
  if (editPolicyButton) {
    clientProfileEditingPolicyId = editPolicyButton.dataset.clientProfileEditPolicy;
    clientProfileEditingVehicleKey = "";
    renderClientProfile();
    const card = [...elements.clientProfileContent.querySelectorAll("[data-client-profile-policy-card]")]
      .find((item) => item.dataset.clientProfilePolicyCard === clientProfileEditingPolicyId);
    card?.scrollIntoView({ behavior: "smooth", block: "center" });
    card?.querySelector("input")?.focus();
    return;
  }
  if (event.target.closest("[data-client-profile-cancel-policy]")) {
    clientProfileEditingPolicyId = null;
    renderClientProfile();
    return;
  }
  const editVehicleButton = event.target.closest("[data-client-profile-edit-vehicle]");
  if (editVehicleButton) {
    
    
    if (clientProfileEditingVehicleKey !== editVehicleButton.dataset.clientProfileEditVehicle) {
      clientProfileEditingVehicleKey = editVehicleButton.dataset.clientProfileEditVehicle;
      clientProfileEditingPolicyId = null;
      renderClientProfile();
    }
    elements.clientProfileContent.querySelector("[data-client-profile-vehicle-form] input")?.focus();
    return;
  }
  if (event.target.closest("[data-client-profile-cancel-vehicle]")) {
    clientProfileEditingVehicleKey = "";
    renderClientProfile();
    return;
  }
  const openAttachmentButton = event.target.closest("[data-client-profile-open-attachment]");
  if (openAttachmentButton) {
    void openPolicyAttachment(
      openAttachmentButton.dataset.clientProfileOpenAttachment,
      openAttachmentButton.dataset.attachmentId,
    );
    return;
  }
  const vehicleSoldButton = event.target.closest("[data-client-profile-vehicle-sold]");
  if (vehicleSoldButton) {
    void setClientProfileVehicleSold(
      vehicleSoldButton.dataset.clientProfileVehicleSold,
      vehicleSoldButton.dataset.soldNext === "yes",
    );
    return;
  }
  const removeVehicleButton = event.target.closest("[data-client-profile-remove-vehicle]");
  if (removeVehicleButton) {
    void removeClientProfileVehicle(removeVehicleButton.dataset.clientProfileRemoveVehicle);
    return;
  }
  const vehicleHistoryButton = event.target.closest("[data-client-profile-vehicle-history]");
  if (vehicleHistoryButton) {
    void fetchClientProfileVehicleHistory(vehicleHistoryButton.dataset.clientProfileVehicleHistory);
    return;
  }
  if (event.target.closest("[data-client-profile-restore-vehicles]")) {
    void restoreClientProfileRemovedVehicles();
    return;
  }
  if (event.target.closest("[data-client-profile-merge-toggle]")) {
    if (!CLIENT_PROFILE_MERGE_ENABLED) return;
    clientProfileMergeOpen = !clientProfileMergeOpen;
    if (!clientProfileMergeOpen) clientProfileMergeSearchPolicyId = null;
    renderClientProfile();
    if (clientProfileMergeOpen) {
      const mergeSection = elements.clientProfileContent.querySelector(".client-profile-merge-section");
      mergeSection?.scrollIntoView({ behavior: "smooth", block: "nearest" });
      mergeSection?.querySelector("[data-client-profile-merge-search] input")?.focus({ preventScroll: true });
    }
    return;
  }
  const mergeConfirmButton = event.target.closest("[data-client-profile-merge-confirm]");
  if (mergeConfirmButton) {
    if (!CLIENT_PROFILE_MERGE_ENABLED) return;
    mergeClientProfiles(mergeConfirmButton.dataset.clientProfileMergeConfirm);
    return;
  }
  if (event.target.closest("[data-client-profile-link-toggle]")) {
    clientProfileLinkPanelOpen = !clientProfileLinkPanelOpen;
    if (!clientProfileLinkPanelOpen) clientProfileLinkSearchPolicyId = null;
    renderClientProfile();
    if (clientProfileLinkPanelOpen) {
      const linkSection = elements.clientProfileContent.querySelector(".client-profile-link-section");
      linkSection?.scrollIntoView({ behavior: "smooth", block: "nearest" });
      linkSection?.querySelector("[data-client-profile-link-search] input")?.focus({ preventScroll: true });
    }
    return;
  }
  const linkConfirmButton = event.target.closest("[data-client-profile-link-confirm]");
  if (linkConfirmButton) {
    void linkClientProfileAccounts(linkConfirmButton.dataset.clientProfileLinkConfirm);
    return;
  }
  const linkOpenButton = event.target.closest("[data-client-profile-link-open]");
  if (linkOpenButton) {
    openClientProfileDialog(linkOpenButton.dataset.clientProfileLinkOpen);
    return;
  }
  const linkRemoveButton = event.target.closest("[data-client-profile-link-remove]");
  if (linkRemoveButton) {
    void unlinkClientProfileAccounts(linkRemoveButton.dataset.clientProfileLinkRemove);
    return;
  }
  const jumpButton = event.target.closest("[data-client-profile-jump-policy]");
  if (jumpButton) {
    const card = [...elements.clientProfileContent.querySelectorAll("[data-client-profile-policy-card]")]
      .find((item) => item.dataset.clientProfilePolicyCard === jumpButton.dataset.clientProfileJumpPolicy);
    if (!card) return;
    card.scrollIntoView({ behavior: "smooth", block: "center" });
    card.classList.remove("client-profile-policy-card--highlight");
    requestAnimationFrame(() => card.classList.add("client-profile-policy-card--highlight"));
  }
});
elements.closeClientProfile.addEventListener("click", () => closeClientProfileDialog());
elements.clientProfileDialog.addEventListener("cancel", (event) => {
  event.preventDefault();
  closeClientProfileDialog();
});
elements.contactDetailsForm.addEventListener("submit", saveContactDetails);
elements.closeContactDetails.addEventListener("click", () => closeContactDetailsDialog());
elements.cancelContactDetails.addEventListener("click", () => closeContactDetailsDialog());
elements.contactDetailsDialog.addEventListener("cancel", (event) => {
  event.preventDefault();
  closeContactDetailsDialog();
});
elements.vehicleDetailsForm.addEventListener("submit", saveVehicleDetails);
elements.vehicleDetailsForm.addEventListener("click", (event) => {
  const editButton = event.target.closest?.("[data-vehicle-edit]");
  if (editButton) {
    startVehicleDetailsFieldEditing(editButton.dataset.vehicleEdit);
    return;
  }
  
  
  const convertChip = event.target.closest?.(".vehicle-details-value-convert");
  if (convertChip) {
    void handleCopyValueClick(convertChip);
    return;
  }
  const displayButton = event.target.closest?.(".vehicle-details-value-display");
  if (displayButton) void handleCopyValueClick(displayButton);
});
elements.vehicleDetailsForm.addEventListener("input", (event) => {
  const fieldItem = event.target.closest?.("[data-vehicle-field]");
  if (!fieldItem || fieldItem.dataset.vehicleField !== vehicleDetailsEditingField) return;
  if (vehicleDetailsEditingField === "vin") {
    event.target.value = normalizeVehicleIdentifier(event.target.value);
  } else if (vehicleDetailsEditingField === "registration") {
    event.target.value = event.target.value.toLocaleUpperCase("pl");
  }
  setVehicleDetailsSaving(false);
});
elements.closeVehicleDetails.addEventListener("click", () => closeVehicleDetailsDialog());
elements.cancelVehicleDetails.addEventListener("click", cancelVehicleDetailsEditing);
elements.vehicleDetailsEditCancel.addEventListener("click", cancelVehicleDetailsEditing);
elements.vehicleDetailsHistory.addEventListener("click", () => {
  void fetchVehicleDetailsHistory();
});
elements.vehicleDetailsDialog.addEventListener("cancel", (event) => {
  event.preventDefault();
  if (vehicleDetailsEditingField) cancelVehicleDetailsEditing();
  else closeVehicleDetailsDialog();
});
elements.closePremiumDetails.addEventListener("click", () => closePremiumDetailsDialog());
elements.premiumDetailsDialog.addEventListener("cancel", (event) => {
  event.preventDefault();
  closePremiumDetailsDialog();
});
elements.terminationDateForm.addEventListener("submit", (event) => {
  event.preventDefault();
  confirmTerminationDetails();
});
elements.terminationDateForm.addEventListener("change", (event) => {
  if (event.target?.name === "terminationType") applyTerminationTypeToDialog();
});
elements.closeTerminationDate.addEventListener("click", () => finishTerminationDetailsSelection());
elements.cancelTerminationDate.addEventListener("click", () => finishTerminationDetailsSelection());
elements.terminationDateDialog.addEventListener("cancel", (event) => {
  event.preventDefault();
  finishTerminationDetailsSelection();
});
elements.attachmentCategoryForm.addEventListener("submit", (event) => {
  event.preventDefault();
  finishAttachmentCategorySelection(attachmentCategoryPicker?.getValue() ?? DEFAULT_ATTACHMENT_CATEGORY);
});
elements.closeAttachmentCategory.addEventListener("click", () => finishAttachmentCategorySelection());
elements.cancelAttachmentCategory.addEventListener("click", () => finishAttachmentCategorySelection());
elements.attachmentCategoryDialog.addEventListener("cancel", (event) => {
  event.preventDefault();
  finishAttachmentCategorySelection();
});
elements.attachmentTargetForm.addEventListener("submit", (event) => {
  event.preventDefault();
  const targetPolicy = policies.find((policy) => policy.id === attachmentTargetSelectedPolicyId);
  if (!targetPolicy) return;
  finishAttachmentTargetSelection({
    policyId: targetPolicy.id,
    category: attachmentTargetCategoryPicker?.getValue() ?? DEFAULT_ATTACHMENT_CATEGORY,
  });
});
elements.attachmentTargetSearch.addEventListener("input", renderAttachmentTargetResults);
elements.attachmentTargetResults.addEventListener("click", (event) => {
  const row = event.target.closest?.("[data-target-policy-id]");
  if (!row) return;
  attachmentTargetSelectedPolicyId = row.dataset.targetPolicyId;
  renderAttachmentTargetResults();
});
elements.closeAttachmentTarget.addEventListener("click", () => finishAttachmentTargetSelection());
elements.cancelAttachmentTarget.addEventListener("click", () => finishAttachmentTargetSelection());
elements.attachmentTargetDialog.addEventListener("cancel", (event) => {
  event.preventDefault();
  finishAttachmentTargetSelection();
});
elements.alwaysVisibleSuggestions.addEventListener("click", (event) => {
  if (event.target.closest?.("[data-always-suggestion-clear]")) {
    clearAlwaysVisibleSuggestion();
    return;
  }
  const option = event.target.closest?.("[data-always-suggestion]");
  if (option) selectAlwaysVisibleSuggestion(option.dataset.alwaysSuggestion);
});
elements.alwaysVisibleSuggestions.addEventListener("keydown", (event) => {
  const option = event.target.closest?.('button[role="option"]');
  if (!option) return;

  if (event.key === "ArrowDown") {
    event.preventDefault();
    moveAlwaysSuggestionFocus(option, 1);
  } else if (event.key === "ArrowUp") {
    event.preventDefault();
    moveAlwaysSuggestionFocus(option, -1);
  } else if (event.key === "Home") {
    event.preventDefault();
    moveAlwaysSuggestionFocus(option, "first");
  } else if (event.key === "End") {
    event.preventDefault();
    moveAlwaysSuggestionFocus(option, "last");
  } else if (event.key === "Escape") {
    event.preventDefault();
    const input = activeAlwaysSuggestionInput;
    hideAlwaysVisibleSuggestions();
    input?.focus();
  }
});
document.addEventListener("click", (event) => {
  const input = getAlwaysSuggestionInput(event.target);
  if (input) {
    showAlwaysVisibleSuggestions(input, true);
    return;
  }
  if (!elements.alwaysVisibleSuggestions.contains?.(event.target)) {
    hideAlwaysVisibleSuggestions();
  }
});
document.addEventListener("focusin", (event) => {
  const clientInput = getClientSuggestionInput(event.target);
  if (clientInput) updateClientSuggestions(clientInput);

  const input = getAlwaysSuggestionInput(event.target);
  if (input) {
    showAlwaysVisibleSuggestions(input, true);
  } else if (!elements.alwaysVisibleSuggestions.contains?.(event.target)) {
    hideAlwaysVisibleSuggestions();
  }
});
document.addEventListener("input", (event) => {
  const clientInput = getClientSuggestionInput(event.target);
  if (clientInput) updateClientSuggestions(clientInput);

  const input = getAlwaysSuggestionInput(event.target);
  if (input) showAlwaysVisibleSuggestions(input, false);
});
document.addEventListener("keydown", (event) => {
  if (event.key === "Escape" && usageGuideActive) hideUsageGuide();
  const input = getAlwaysSuggestionInput(event.target);
  if (!input) return;
  if (event.key === "Escape") {
    hideAlwaysVisibleSuggestions();
  } else if (event.key === "ArrowDown" && !elements.alwaysVisibleSuggestions.hidden) {
    event.preventDefault();
    moveAlwaysSuggestionFocus(null, "first");
  } else if (event.key === "ArrowUp" && !elements.alwaysVisibleSuggestions.hidden) {
    event.preventDefault();
    moveAlwaysSuggestionFocus(null, "last");
  }
});

globalThis.addEventListener("beforeunload", (event) => {
  if (!hasUnsavedPolicyChanges && !editingPolicyId && pendingAttachments.length === 0) return;
  event.preventDefault();
  event.returnValue = "";
});
globalThis.addEventListener?.("scroll", () => {
  if (!activeAlwaysSuggestionInput || elements.alwaysVisibleSuggestions.hidden) return;
  positionAlwaysVisibleSuggestions(activeAlwaysSuggestionInput);
}, true);
globalThis.addEventListener?.("resize", hideAlwaysVisibleSuggestions);
globalThis.addEventListener("scroll", schedulePageScrollControlsUpdate, { passive: true });
globalThis.addEventListener("resize", schedulePageScrollControlsUpdate);
globalThis.addEventListener("scroll", scheduleUsageGuideRender, { passive: true, capture: true });
globalThis.addEventListener("resize", scheduleUsageGuideRender);
elements.scrollPageTop.addEventListener("click", () => scrollPageTo("top"));
elements.scrollPageBottom.addEventListener("click", () => scrollPageTo("bottom"));
const pageScrollResizeObserver = typeof ResizeObserver === "function"
  ? new ResizeObserver(schedulePageScrollControlsUpdate)
  : null;
pageScrollResizeObserver?.observe(document.body);
elements.openDataFile.addEventListener("click", openDataFile);
elements.backupDataFile.addEventListener("click", createDataFileBackup);
elements.saveDataFile.addEventListener("click", saveDataFileAs);
elements.mergeFirstDataFile.addEventListener("change", updateMergeDatabasesButton);
elements.mergeSecondDataFile.addEventListener("change", updateMergeDatabasesButton);
elements.mergeDataFiles.addEventListener("click", mergeSelectedDatabases);
elements.mergeChooseFirst.addEventListener("click", () => finishMergeConflict({ side: "first", applyToAll: false }));
elements.mergeKeepBoth.addEventListener("click", () => finishMergeConflict({ keepBoth: true }));
elements.mergeChooseSecond.addEventListener("click", () => finishMergeConflict({ side: "second", applyToAll: false }));
elements.mergeChooseAllFirst.addEventListener("click", () => finishMergeConflict({ side: "first", applyToAll: true }));
elements.mergeChooseAllSecond.addEventListener("click", () => finishMergeConflict({ side: "second", applyToAll: true }));
elements.cancelMergeConflict.addEventListener("click", () => finishMergeConflict({ cancelled: true }));
elements.mergeConflictDialog.addEventListener("cancel", (event) => {
  event.preventDefault();
  finishMergeConflict({ cancelled: true });
});
elements.openSettingsFile.addEventListener("click", openSettingsFile);
elements.saveSettingsFile.addEventListener("click", () => saveSettingsFileAs(uiSettings));
elements.settingsFileInput.addEventListener("change", async () => {
  const [file] = elements.settingsFileInput.files ?? [];
  if (!file) return;
  try {
    await loadSettingsFromFile(file);
  } catch (error) {
    showToast(error?.message || "Nie udało się wczytać pliku ustawień");
  } finally {
    elements.settingsFileInput.value = "";
  }
});
elements.dataFileInput.addEventListener("change", async () => {
  const [file] = elements.dataFileInput.files ?? [];
  if (!file) return;
  try {
    await loadPoliciesFromFile(file);
  } catch (error) {
    showToast(error?.message || "Nie udało się wczytać pliku danych");
  } finally {
    elements.dataFileInput.value = "";
  }
});

elements.clientNameSortButton.addEventListener("click", () => {
  sortDirection = sortMode === "clientName" && sortDirection === "asc" ? "desc" : "asc";
  sortMode = "clientName";
  resetPaginationAndRender();
});

elements.insurerSortButton.addEventListener("click", () => {
  const insurerGroups = getInsurerSortGroups(getVisiblePolicies());
  if (insurerGroups.length === 0) return;
  let nextIndex = 0;
  if (sortMode === "insurer" && insurerSortSelection) {
    const currentIndex = insurerGroups.findIndex((group) => group.key === insurerSortSelection.key);
    if (currentIndex >= 0) nextIndex = (currentIndex + 1) % insurerGroups.length;
  }
  insurerSortSelection = insurerGroups[nextIndex];
  sortMode = "insurer";
  sortDirection = "asc";
  resetPaginationAndRender();
});

elements.registrationSortButton.addEventListener("click", () => {
  const registrationGroups = getRegistrationSortGroups(getVisiblePolicies());
  if (registrationGroups.length === 0) return;
  const currentToken = sortMode === "registration"
    ? "registration"
    : sortMode === "policyType" && policyTypeSortIndex >= 0 ? `type:${policyTypeSortIndex}` : null;
  let nextIndex = 0;
  if (currentToken) {
    const currentIndex = registrationGroups.findIndex((group) => group.token === currentToken);
    if (currentIndex >= 0) nextIndex = (currentIndex + 1) % registrationGroups.length;
  }
  const nextGroup = registrationGroups[nextIndex];
  if (nextGroup.token === "registration") {
    sortMode = "registration";
    policyTypeSortIndex = -1;
  } else {
    sortMode = "policyType";
    policyTypeSortIndex = Number(nextGroup.token.slice(5));
  }
  sortDirection = "asc";
  resetPaginationAndRender();
});

elements.resetSortingButton.addEventListener("click", () => {
  sortMode = null;
  sortDirection = "asc";
  insurerSortSelection = null;
  policyTypeSortIndex = -1;
  resetPaginationAndRender();
});

elements.sortButton.addEventListener("click", () => {
  sortDirection = sortMode === "date" && sortDirection === "asc" ? "desc" : "asc";
  sortMode = "date";
  resetPaginationAndRender();
});

elements.startDateSortButton.addEventListener("click", () => {
  sortDirection = sortMode === "startDate" && sortDirection === "asc" ? "desc" : "asc";
  sortMode = "startDate";
  resetPaginationAndRender();
});

elements.premiumSortButton.addEventListener("click", () => {
  sortDirection = sortMode === "premium" && sortDirection === "asc" ? "desc" : "asc";
  sortMode = "premium";
  resetPaginationAndRender();
});

elements.renewalButton.addEventListener("click", () => {
  renewalsOnly = !renewalsOnly;
  if (renewalsOnly) {
    sortMode = "date";
    sortDirection = "asc";
  } else {
    sortMode = null;
    sortDirection = "asc";
  }
  resetPaginationAndRender();
});

elements.renewalWindow30.addEventListener("click", () => {
  renewalWindowDays = 30;
  resetPaginationAndRender();
});

elements.renewalWindow60.addEventListener("click", () => {
  renewalWindowDays = 60;
  resetPaginationAndRender();
});





const SERVER_WARMUP_NOTICE_DELAY_MS = 2_500;
let serverWarmupNoticeElement = null;
let serverWarmupNoticeTitleElement = null;
let serverWarmupNoticeBodyElement = null;
let serverWarmupNoticeTimer = null;
let serverWarmupNoticeShown = false;
let serverWarmupPendingRequests = 0;



let serverWarmupPendingCleanupRequests = 0;

function ensureServerWarmupNoticeElement() {
  if (serverWarmupNoticeElement) return serverWarmupNoticeElement;
  const notice = document.createElement("div");
  notice.id = "serverWarmupNotice";
  notice.setAttribute("role", "status");
  
  notice.style.cssText = "position:fixed;right:24px;bottom:24px;top:auto;left:auto;background:rgba(28,38,33,0.94);color:#fff;padding:10px 18px;border-radius:12px;font-size:13px;line-height:1.4;box-shadow:0 6px 24px rgba(0,0,0,0.25);z-index:2147483647;pointer-events:none;margin:0;border:0;max-width:min(92vw,380px);text-align:left;";
  const noticeTitle = document.createElement("div");
  noticeTitle.style.cssText = "font-weight:600;margin-bottom:2px;";
  noticeTitle.textContent = "Trwa uruchamianie";
  const noticeBody = document.createElement("div");
  noticeBody.textContent = "Niektóre funkcje mogą być niedostępne podczas uruchamiania…";
  notice.append(noticeTitle, noticeBody);
  notice.hidden = true;
  document.body.append(notice);
  serverWarmupNoticeElement = notice;
  serverWarmupNoticeTitleElement = noticeTitle;
  serverWarmupNoticeBodyElement = noticeBody;
  return notice;
}

function showServerWarmupNotice() {
  const notice = ensureServerWarmupNoticeElement();
  serverWarmupNoticeShown = true;
  
  
  
  
  
  const withinStartupWindow = (globalThis.performance?.now?.() || 0) < 60_000;
  
  
  
  const quoteCleanupInProgress = serverWarmupPendingCleanupRequests > 0;
  if (serverWarmupNoticeTitleElement) {
    serverWarmupNoticeTitleElement.textContent = quoteCleanupInProgress
      ? "Zamykanie poprzedniej kalkulacji"
      : withinStartupWindow
        ? "Trwa uruchamianie"
        : "Serwer jest chwilowo obciążony";
  }
  if (serverWarmupNoticeBodyElement) {
    serverWarmupNoticeBodyElement.textContent = quoteCleanupInProgress
      ? "Domykamy karty przeglądarki po poprzedniej kalkulacji…"
      : withinStartupWindow
        ? "Niektóre funkcje mogą być niedostępne podczas uruchamiania…"
        : "Trwa duża operacja w tle. Aplikacja odpowie za chwilę…";
  }
  
  
  notice.hidden = false;
  
  
  if (typeof notice.showPopover === "function") {
    try {
      if (!notice.hasAttribute("popover")) notice.setAttribute("popover", "manual");
      if (!notice.matches(":popover-open")) notice.showPopover();
      return;
    } catch {
      
    }
  }
  notice.hidden = false;
}

function armServerWarmupNoticeTimer() {
  if (serverWarmupNoticeTimer !== null || serverWarmupNoticeShown) return;
  serverWarmupNoticeTimer = globalThis.setTimeout(() => {
    serverWarmupNoticeTimer = null;
    if (serverWarmupPendingRequests > 0) showServerWarmupNotice();
  }, SERVER_WARMUP_NOTICE_DELAY_MS);
}

function hideServerWarmupNotice() {
  if (serverWarmupNoticeTimer !== null) {
    globalThis.clearTimeout(serverWarmupNoticeTimer);
    serverWarmupNoticeTimer = null;
  }
  
  
  
  if (serverWarmupPendingRequests > 0) armServerWarmupNoticeTimer();
  if (!serverWarmupNoticeShown) return;
  serverWarmupNoticeShown = false;
  const notice = serverWarmupNoticeElement;
  if (!notice) return;
  try {
    if (notice.matches(":popover-open")) notice.hidePopover();
  } catch {
  }
  notice.hidden = true;
}

{
  
  
  
  
  const nativeFetch = globalThis.fetch.bind(globalThis);
  globalThis.fetch = function watchedFetch(input, init) {
    const requestUrl = typeof input === "string" ? input : String(input?.url || "");
    const isLocalApiRequest = requestUrl.startsWith("/api/")
      || requestUrl.startsWith(`${globalThis.location.origin}/api/`);
    if (!isLocalApiRequest) return nativeFetch(input, init);
    
    
    const isQuoteCleanupRequest = /\/api\/automation\/(?:jobs|quote-batches)\/[^/]+\/cancel(?:\?|$)/
      .test(requestUrl);
    serverWarmupPendingRequests += 1;
    if (isQuoteCleanupRequest) serverWarmupPendingCleanupRequests += 1;
    armServerWarmupNoticeTimer();
    const settleWarmupCounters = () => {
      serverWarmupPendingRequests = Math.max(0, serverWarmupPendingRequests - 1);
      if (isQuoteCleanupRequest) {
        serverWarmupPendingCleanupRequests = Math.max(0, serverWarmupPendingCleanupRequests - 1);
      }
    };
    return nativeFetch(input, init).then(
      (response) => {
        settleWarmupCounters();
        hideServerWarmupNotice();
        return response;
      },
      (error) => {
        settleWarmupCounters();
        throw error;
      },
    );
  };
}

updateMergeDatabasesButton();
updatePrintOptionsState();
updateTodayDate();
globalThis.setInterval(updateTodayDate, 60 * 1000);
applyUiSettings();
renderWartaAutomationAvailability("checking");
checkWartaAutomationBridge();
updateAddPolicyButtonState();
renderPendingAttachments();
render();
updateDataFileStatus();
updateSettingsFileStatus();
updateDeletedRecordsSettingsSummary();

async function migrateScopedFileCacheEntries() {
  let database = null;
  try {
    database = await openFileSettingsDatabase();
    if (!database) return;
    const runRequest = (request) => new Promise((resolve, reject) => {
      request.onsuccess = () => resolve(request.result);
      request.onerror = () => reject(request.error);
    });
    const runTransaction = (transaction) => new Promise((resolve, reject) => {
      transaction.oncomplete = () => resolve();
      transaction.onerror = () => reject(transaction.error);
      transaction.onabort = () => reject(transaction.error);
    });
    const allKeys = await runRequest(
      database.transaction(FILE_SETTINGS_STORE, "readonly").objectStore(FILE_SETTINGS_STORE).getAllKeys(),
    );
    for (const baseKey of [FILE_HANDLE_KEY, DATA_FILE_SNAPSHOT_KEY]) {
      const scopedKeys = allKeys.filter((key) => typeof key === "string" && key.startsWith(`${baseKey}:`));
      if (scopedKeys.length === 0) continue;
      const existing = await runRequest(
        database.transaction(FILE_SETTINGS_STORE, "readonly").objectStore(FILE_SETTINGS_STORE).get(baseKey),
      );
      if (!existing) {
        const migrated = await runRequest(
          database.transaction(FILE_SETTINGS_STORE, "readonly").objectStore(FILE_SETTINGS_STORE).get(scopedKeys[scopedKeys.length - 1]),
        );
        if (migrated !== undefined && migrated !== null) {
          const writeTransaction = database.transaction(FILE_SETTINGS_STORE, "readwrite");
          writeTransaction.objectStore(FILE_SETTINGS_STORE).put(migrated, baseKey);
          await runTransaction(writeTransaction);
        }
      }
      const cleanupTransaction = database.transaction(FILE_SETTINGS_STORE, "readwrite");
      for (const key of scopedKeys) cleanupTransaction.objectStore(FILE_SETTINGS_STORE).delete(key);
      await runTransaction(cleanupTransaction);
    }
  } catch {
  } finally {
    database?.close();
  }
}

function deletePolicyFileSettingsDatabase() {
  return new Promise((resolve, reject) => {
    if (!globalThis.indexedDB) {
      resolve();
      return;
    }
    const request = globalThis.indexedDB.deleteDatabase(FILE_SETTINGS_DB);
    request.onsuccess = () => resolve();
    request.onerror = () => reject(request.error || new Error("Nie udało się wyczyścić pamięci aplikacji."));
    request.onblocked = () => reject(new Error(
      "Czyszczenie jest zablokowane przez inną otwartą kartę Bazy Polis. Zamknij pozostałe karty aplikacji i odśwież tę stronę.",
    ));
  });
}

async function resetPolicyBrowserFileConnections() {
  globalThis.localStorage?.removeItem(LEGACY_STORAGE_KEY);
  await deletePolicyFileSettingsDatabase();
}

function getUrlWithoutBrowserFileConnectionsReset() {
  const cleanUrl = new URL(globalThis.location.href);
  cleanUrl.searchParams.delete(BROWSER_FILE_CONNECTIONS_RESET_QUERY);
  return cleanUrl.href;
}





let accountGateMode = "login";

function isEmployeeAccount() {
  return currentAccount?.mode === "employee";
}

function getAgencyMemberById(accountId) {
  if (!accountId) return null;
  return agencyMembers.find((member) => member.id === accountId) || null;
}


function getAccountDisplayName(accountId) {
  if (!accountId || (currentAccount && accountId === currentAccount.id)) {
    return currentAccount?.name || "";
  }
  return getAgencyMemberById(accountId)?.label || "";
}

function applyAccountSnapshot(snapshot) {
  if (!snapshot?.account) return;
  currentAccount = snapshot.account;
  agencyMembers = Array.isArray(snapshot.members) ? snapshot.members : [];
  refreshAgencyUi();
}



function refreshAgencyUi() {
  refreshProfileSwitcher();
  refreshAgencySettingsPanel();
  applyEmployeeModeRestrictions();
  applyAgencyInsurerVisibility();
}

function createAgencyInsurerChoicesMarkup({ disabled = false, selectedIds = null } = {}) {
  const selectedInsurerIds = selectedIds instanceof Set ? selectedIds : getServedInsurerIds();
  return normalizeInsurerSettings(uiSettings.insurers).map((insurer) => `
    <label class="agency-insurer-option">
      <input
        type="checkbox"
        value="${escapeHtml(insurer.id)}"
        data-agency-insurer
        ${selectedInsurerIds.has(insurer.id) ? "checked" : ""}
        ${disabled ? "disabled" : ""}
      />
      <span>${escapeHtml(insurer.name)}</span>
    </label>
  `).join("");
}

function renderAgencyInsurerSettings() {
  if (!elements.agencyInsurersList) return;
  const employee = isEmployeeAccount();
  elements.agencyInsurersList.innerHTML = createAgencyInsurerChoicesMarkup({ disabled: employee });
  if (elements.agencyInsurersSave) elements.agencyInsurersSave.hidden = employee;
  if (elements.agencyInsurersHint) {
    elements.agencyInsurersHint.textContent = employee
      ? "Zakres towarzystw ustaliła centrala agencji."
      : "Nowe towarzystwa dodane przez aktualizację pojawią się tutaj odznaczone.";
  }
}

function applyAgencyInsurerVisibility() {
  const servedInsurerIds = getServedInsurerIds();
  document.querySelectorAll("#settingsUserPanel .calculator-account-card[data-insurer]").forEach((card) => {
    card.hidden = !servedInsurerIds.has(normalizeInsurerId(card.dataset.insurer));
  });

  let visibleQuoteInsurers = 0;
  document.querySelectorAll("#quoteCalculatorDialog .quote-insurer-card[data-insurer]").forEach((card) => {
    const visible = servedInsurerIds.has(normalizeInsurerId(card.dataset.insurer));
    card.hidden = !visible;
    const checkbox = card.querySelector('input[type="checkbox"]');
    
    
    if (!visible && checkbox && checkbox.checked) {
      checkbox.checked = false;
      checkbox.dataset.autoUnchecked = "true";
    }
    if (visible && checkbox && checkbox.dataset.autoUnchecked === "true") {
      checkbox.checked = true;
      delete checkbox.dataset.autoUnchecked;
    }
    if (visible) visibleQuoteInsurers += 1;
  });
  if (elements.quoteInsurersEmpty) elements.quoteInsurersEmpty.hidden = visibleQuoteInsurers > 0;
  syncQuoteStartButton();
  if (visibleQuoteInsurers === 0) elements.startQuoteCalculation.disabled = true;
  if (insurerSortSelection && !servedInsurerIds.has(normalizeInsurerId(insurerSortSelection.key))) {
    insurerSortSelection = null;
  }
}




const EMPLOYEE_HIDDEN_ELEMENT_IDS = [
  "portfolioImportLauncher",
  "compensaPortfolioImportButton",
  "allianzPortfolioImportButton",
  "wartaPortfolioImportButton",
  "pzuPortfolioImportButton",
  "inslyPortfolioImportButton",
  "mtuPortfolioImportButton",
  "hestiaPortfolioImportButton",
  "trastiPortfolioImportButton",
  "wienerPortfolioImportButton",
  "generaliPortfolioImportButton",
];

function isInsurerImportAllowedForAccount() {
  return !isEmployeeAccount() || currentAccount?.allowInsurerImports === true;
}

function applyEmployeeModeRestrictions() {
  const employee = isEmployeeAccount();
  const employeeImportsBlocked = !isInsurerImportAllowedForAccount();
  if (elements.inslyPortfolioCard) elements.inslyPortfolioCard.hidden = employeeImportsBlocked;
  EMPLOYEE_HIDDEN_ELEMENT_IDS.forEach((elementId) => {
    const element = document.getElementById(elementId);
    if (element) element.hidden = employeeImportsBlocked;
  });
  
  const centralLockTitle = employee ? "To ustawienie zablokowała centrala agencji." : "";
  if (elements.settingsLogoInput) elements.settingsLogoInput.disabled = employee;
  if (elements.settingsDatabaseName) {
    elements.settingsDatabaseName.disabled = employee;
    elements.settingsDatabaseName.title = centralLockTitle;
  }
  if (elements.resetSettingsLogo) {
    elements.resetSettingsLogo.disabled = employee;
    elements.resetSettingsLogo.title = centralLockTitle;
  }
}

function setAgencyStatus(statusElement, message, tone = "ok") {
  if (!statusElement) return;
  statusElement.textContent = message || "";
  statusElement.hidden = !message;
  statusElement.dataset.tone = tone;
}

function renderAgencyMembers() {
  if (!elements.agencyMembersList) return;
  elements.agencyMembersEmpty.hidden = agencyMembers.length > 0;
  elements.agencyMembersList.innerHTML = agencyMembers.map((member) => `
    <div class="agency-member-card" data-member-id="${escapeHtml(member.id)}">
      <div class="agency-member-info">
        <input
          class="agency-member-label"
          data-member-label
          value="${escapeHtml(member.label)}"
          maxlength="40"
          aria-label="Nazwa pracownika o identyfikatorze ${escapeHtml(member.id)}"
        />
        <code class="agency-member-id" data-member-copy title="Kliknij, aby skopiować">${escapeHtml(member.id)}</code>
      </div>
      <div class="agency-member-actions">
        <button type="button" class="settings-file-button" data-member-assign>Przekaż polisy</button>
        <button type="button" class="settings-secondary-button" data-member-pairing>Pokaż kod parowania</button>
        <button type="button" class="settings-file-button" data-member-import>Importuj bazę</button>
        <button type="button" class="settings-secondary-button settings-secondary-button--danger" data-member-remove>Usuń</button>
        <input type="file" accept=".json,.zip,application/json,application/zip" data-member-file hidden />
      </div>
    </div>
  `).join("");
}





function getAgencyExportPeriodRange() {
  const choice = elements.agencyExportPeriod?.value || "";
  if (choice === "custom") {
    const from = parseLocalDate(elements.agencyExportFrom?.value || "");
    const to = parseLocalDate(elements.agencyExportTo?.value || "");
    if (!from && !to) return null;
    return { from, to };
  }
  const today = new Date();
  today.setHours(0, 0, 0, 0);
  if (choice === "year") return { from: new Date(today.getFullYear(), 0, 1), to: null };
  const days = Number(choice);
  if (Number.isFinite(days) && days > 0) {
    const from = new Date(today);
    from.setDate(from.getDate() - days);
    return { from, to: null };
  }
  return null;
}

function policyMatchesAgencyExportClient(policy, normalizedQuery, compactQuery) {
  
  if (compactQuery) {
    const identityValues = [policy.identityNumber, policy.secondaryIdentityNumber]
      .map((value) => normalize(value).replace(/[\s-]+/g, ""))
      .filter(Boolean);
    if (identityValues.some((value) => value.includes(compactQuery))) return true;
  }
  const searchableValues = [
    policy.clientName,
    policy.policyNumber,
    policy.registration,
    policy.clientPhone,
    policy.clientEmail,
  ].map((value) => normalize(value)).filter(Boolean);
  if (searchableValues.some((value) => value.includes(normalizedQuery))) return true;
  return normalizedQuery
    .split(/\s+/)
    .every((term) => searchableValues.some((value) => value.includes(term)));
}

function getAgencyExportSelection() {
  const insurerChoice = elements.agencyExportInsurer?.value || "";
  const periodRange = getAgencyExportPeriodRange();
  const normalizedClientQuery = normalize(elements.agencyExportClient?.value || "");
  const compactClientQuery = normalizedClientQuery.replace(/[\s-]+/g, "");
  const filtered = Boolean(insurerChoice || periodRange || normalizedClientQuery);
  const matchedPolicies = !filtered ? policies : policies.filter((policy) => {
    if (insurerChoice && String(policy.insurer || "").trim() !== insurerChoice) return false;
    if (periodRange) {
      const startDate = getPolicyStartDate(policy);
      if (!startDate) return false;
      if (periodRange.from && startDate < periodRange.from) return false;
      if (periodRange.to && startDate > periodRange.to) return false;
    }
    if (normalizedClientQuery
      && !policyMatchesAgencyExportClient(policy, normalizedClientQuery, compactClientQuery)) return false;
    return true;
  });
  const attachmentCount = matchedPolicies.reduce(
    (sum, policy) => sum + normalizePolicyAttachments(policy.attachments).length,
    0,
  );
  return { filtered, matchedPolicies, attachmentCount };
}

function refreshAgencyExportInsurerOptions() {
  const select = elements.agencyExportInsurer;
  if (!select) return;
  const previousChoice = select.value;
  const counts = new Map();
  policies.forEach((policy) => {
    const name = String(policy.insurer || "").trim();
    if (!name) return;
    counts.set(name, (counts.get(name) || 0) + 1);
  });
  const names = [...counts.keys()].sort(compareAlphabetically);
  select.innerHTML = [
    '<option value="">Wszystkie towarzystwa</option>',
    ...names.map((name) => `<option value="${escapeHtml(name)}">${escapeHtml(name)} (${counts.get(name)})</option>`),
  ].join("");
  if (names.includes(previousChoice)) select.value = previousChoice;
}

function syncAgencyExportCustomRangeVisibility() {
  const custom = elements.agencyExportPeriod?.value === "custom";
  if (elements.agencyExportFromField) elements.agencyExportFromField.hidden = !custom;
  if (elements.agencyExportToField) elements.agencyExportToField.hidden = !custom;
}

function updateAgencyExportSummary() {
  if (!elements.agencyExportSummary) return;
  const selection = getAgencyExportSelection();
  if (elements.agencyExportReset) elements.agencyExportReset.hidden = !selection.filtered;
  if (selection.matchedPolicies.length === 0) {
    elements.agencyExportSummary.textContent = selection.filtered
      ? "Żadna polisa nie pasuje do wybranych filtrów - zmień je albo wyczyść."
      : "Baza jest pusta - nie ma czego spakować.";
    elements.agencyExportSummary.dataset.tone = "warning";
  } else {
    const attachmentsPart = selection.attachmentCount > 0
      ? ` i ${pluralizeAttachments(selection.attachmentCount)}`
      : "";
    elements.agencyExportSummary.textContent = selection.filtered
      ? `Zawartość paczki: ${pluralizePolicies(selection.matchedPolicies.length)} z ${policies.length}${attachmentsPart}.`
      : `Zawartość paczki: cała baza - ${pluralizePolicies(selection.matchedPolicies.length)}${attachmentsPart}.`;
    elements.agencyExportSummary.dataset.tone = "";
  }
  if (elements.agencyExportButton) elements.agencyExportButton.disabled = selection.matchedPolicies.length === 0;
}

function refreshAgencyExportLastInfo() {
  if (!elements.agencyExportLastInfo) return;
  const lastExport = currentAccount?.lastCentralExport;
  const timestamp = lastExport?.at ? Date.parse(lastExport.at) : Number.NaN;
  if (!Number.isFinite(timestamp)) {
    elements.agencyExportLastInfo.textContent = "Nie robiono jeszcze eksportu.";
    return;
  }
  const scopePart = lastExport.policyCount > 0
    ? ` (${lastExport.filtered ? "wybrane polisy" : "cała baza"}, ${pluralizePolicies(lastExport.policyCount)})`
    : "";
  elements.agencyExportLastInfo.textContent = `Ostatni eksport: ${formatClientProfileTimestamp(timestamp)}${scopePart}`;
}

function refreshAgencyExportPanel() {
  refreshAgencyExportInsurerOptions();
  syncAgencyExportCustomRangeVisibility();
  updateAgencyExportSummary();
  refreshAgencyExportLastInfo();
}







const MAX_AGENCY_SEED_POLICIES = 10_000;
const MAX_AGENCY_SEED_DATABASE_BYTES = 128 * 1024 * 1024;
const MAX_AGENCY_SEED_REQUEST_BYTES = 160 * 1024 * 1024;
const agencySeedPolicyTokens = new WeakMap();
const agencySeedSelectedPolicyTokens = new Set();
let agencySeedNextPolicyToken = 1;
let agencySeedGenerationActive = false;

function getAgencySeedPolicyToken(policy) {
  if (!policy || typeof policy !== "object") return "";
  let token = agencySeedPolicyTokens.get(policy);
  if (!token) {
    token = `policy-${agencySeedNextPolicyToken}`;
    agencySeedNextPolicyToken += 1;
    agencySeedPolicyTokens.set(policy, token);
  }
  return token;
}

function getSelectedAgencySeedPolicies(
  policyRecords = policies,
  selectedTokens = agencySeedSelectedPolicyTokens,
) {
  if (!(selectedTokens instanceof Set) || !Array.isArray(policyRecords)) return [];
  return policyRecords.filter((policy) => {
    const policyToken = getAgencySeedPolicyToken(policy);
    return Boolean(policyToken && selectedTokens.has(policyToken));
  });
}

function createAgencySeedDatabaseContents(selectedPolicies) {
  
  
  
  return createDataFileContents(selectedPolicies, new Date().toISOString(), [], [], [], []);
}

function createAgencySeedRequestBody(payload, {
  maxDatabaseBytes = MAX_AGENCY_SEED_DATABASE_BYTES,
  maxRequestBytes = MAX_AGENCY_SEED_REQUEST_BYTES,
} = {}) {
  const databaseContents = typeof payload?.databaseContents === "string"
    ? payload.databaseContents
    : "";
  if (databaseContents && new Blob([databaseContents]).size > maxDatabaseBytes) {
    throw new Error("Wybrane polisy przekraczają limit 128 MB. Przygotuj dwie mniejsze paczki.");
  }
  const requestBody = JSON.stringify(payload);
  if (new Blob([requestBody]).size > maxRequestBytes) {
    throw new Error(
      "Wybrane polisy po bezpiecznym zakodowaniu przekraczają limit przesyłania. "
      + "Przygotuj dwie mniejsze paczki.",
    );
  }
  return requestBody;
}

function getAgencySeedMode() {
  return elements.agencyGenerateSeedSelected?.checked ? "selected" : "empty";
}

function reconcileAgencySeedSelection() {
  const currentPolicyTokens = new Set(policies.map(getAgencySeedPolicyToken).filter(Boolean));
  for (const policyToken of agencySeedSelectedPolicyTokens) {
    if (!currentPolicyTokens.has(policyToken)) agencySeedSelectedPolicyTokens.delete(policyToken);
  }
}

function getAgencySeedSelectionSummary() {
  reconcileAgencySeedSelection();
  const selectedPolicies = getSelectedAgencySeedPolicies();
  const attachmentCount = selectedPolicies.reduce(
    (sum, policy) => sum + (Array.isArray(policy?.attachments) ? policy.attachments.length : 0),
    0,
  );
  return { selectedPolicies, attachmentCount };
}


function describeAgencySelectionByInsurer(selectedPolicies, maxGroups = 4) {
  const counts = new Map();
  selectedPolicies.forEach((policy) => {
    const name = String(policy?.insurer || "").trim() || "Bez towarzystwa";
    counts.set(name, (counts.get(name) || 0) + 1);
  });
  const parts = [...counts.entries()]
    .sort((first, second) => second[1] - first[1] || compareAlphabetically(first[0], second[0]))
    .map(([name, count]) => `${name} ${count}`);
  if (parts.length === 0) return "";
  const visible = parts.slice(0, maxGroups);
  const hiddenCount = parts.length - visible.length;
  return hiddenCount > 0 ? `${visible.join(", ")} i jeszcze ${hiddenCount} TU` : visible.join(", ");
}

function updateAgencySeedSummary() {
  const selectedMode = getAgencySeedMode() === "selected";
  const { selectedPolicies, attachmentCount } = getAgencySeedSelectionSummary();
  if (elements.agencyGenerateSeedSummary) {
    if (!selectedMode) {
      elements.agencyGenerateSeedSummary.textContent = "Paczka będzie zawierała pustą bazę polis.";
      elements.agencyGenerateSeedSummary.dataset.tone = "";
    } else if (policies.length === 0) {
      elements.agencyGenerateSeedSummary.textContent = "Baza jest pusta - nie ma polis do przekazania.";
      elements.agencyGenerateSeedSummary.dataset.tone = "warning";
    } else if (selectedPolicies.length === 0) {
      elements.agencyGenerateSeedSummary.textContent = "Nie wybrano jeszcze żadnej polisy. Kliknij „Wybierz polisy…”.";
      elements.agencyGenerateSeedSummary.dataset.tone = "warning";
    } else {
      const breakdown = describeAgencySelectionByInsurer(selectedPolicies);
      const attachmentsPart = attachmentCount > 0 ? ` oraz ${pluralizeAttachments(attachmentCount)}` : "";
      elements.agencyGenerateSeedSummary.textContent = (
        `Do startowej bazy trafi ${pluralizePolicies(selectedPolicies.length)}`
        + `${breakdown ? ` (${breakdown})` : ""}${attachmentsPart}. `
        + "Właściciele rekordów pozostaną bez zmian."
      );
      elements.agencyGenerateSeedSummary.dataset.tone = "";
    }
  }
  if (elements.agencyGenerateButton) {
    elements.agencyGenerateButton.disabled = agencySeedGenerationActive
      || (selectedMode && selectedPolicies.length === 0);
  }
}

function setAgencySeedGenerationLoading(active) {
  agencySeedGenerationActive = Boolean(active);
  if (elements.agencyGenerateName) elements.agencyGenerateName.disabled = agencySeedGenerationActive;
  if (elements.agencyGenerateSeedEmpty) elements.agencyGenerateSeedEmpty.disabled = agencySeedGenerationActive;
  if (elements.agencyGenerateSeedSelected) elements.agencyGenerateSeedSelected.disabled = agencySeedGenerationActive;
  if (elements.agencyGenerateSeedChoose) elements.agencyGenerateSeedChoose.disabled = agencySeedGenerationActive;
  if (elements.agencyGenerateAllowImports) elements.agencyGenerateAllowImports.disabled = agencySeedGenerationActive;
  if (elements.agencyGenerateButton) {
    elements.agencyGenerateButton.textContent = agencySeedGenerationActive
      ? "Przygotowywanie…"
      : "Przygotuj bazę (ZIP)";
  }
  updateAgencySeedSummary();
}



function renderAgencySeedPicker() {
  if (!elements.agencyGenerateSeedPicker) return;
  reconcileAgencySeedSelection();
  const selectedMode = getAgencySeedMode() === "selected";
  elements.agencyGenerateSeedPicker.hidden = !selectedMode;
  updateAgencySeedSummary();
}

const agencyAssignmentSelectedPolicyTokens = new Set();
let agencyAssignmentTargetId = "";
let agencyAssignmentActive = false;

function getAgencyAssignmentTarget() {
  return getAgencyMemberById(agencyAssignmentTargetId);
}

function getAgencyAssignmentSelection() {
  return getSelectedAgencySeedPolicies(policies, agencyAssignmentSelectedPolicyTokens);
}

function closeAgencyAssignmentPanel() {
  agencyAssignmentTargetId = "";
  agencyAssignmentSelectedPolicyTokens.clear();
  if (agencyPolicyPickerMode === "assignment") closeAgencyPolicyPicker();
  if (elements.agencyAssignmentPanel) elements.agencyAssignmentPanel.hidden = true;
  setAgencyStatus(elements.agencyAssignmentStatus, "");
}

function updateAgencyAssignmentSummary() {
  const selectedPolicies = getAgencyAssignmentSelection();
  const attachmentCount = selectedPolicies.reduce(
    (sum, policy) => sum + normalizePolicyAttachments(policy?.attachments).length,
    0,
  );
  if (elements.agencyAssignmentSummary) {
    const breakdown = describeAgencySelectionByInsurer(selectedPolicies);
    elements.agencyAssignmentSummary.textContent = selectedPolicies.length === 0
      ? "Nie wybrano jeszcze żadnej polisy. Kliknij „Wybierz polisy…”."
      : `Paczka zawiera ${pluralizePolicies(selectedPolicies.length)}`
        + `${breakdown ? ` (${breakdown})` : ""}`
        + `${attachmentCount ? ` i ${pluralizeAttachments(attachmentCount)}` : ""}.`
        + " Rekordy zachowają właścicieli i pełne dane klientów.";
    elements.agencyAssignmentSummary.dataset.tone = selectedPolicies.length ? "" : "warning";
  }
  if (elements.agencyAssignmentDownload) {
    elements.agencyAssignmentDownload.disabled = agencyAssignmentActive || selectedPolicies.length === 0;
  }
}



function renderAgencyAssignmentPicker() {
  if (!elements.agencyAssignmentPanel) return;
  const target = getAgencyAssignmentTarget();
  if (!target || isEmployeeAccount()) {
    closeAgencyAssignmentPanel();
    return;
  }
  const currentTokens = new Set(policies.map(getAgencySeedPolicyToken).filter(Boolean));
  for (const token of agencyAssignmentSelectedPolicyTokens) {
    if (!currentTokens.has(token)) agencyAssignmentSelectedPolicyTokens.delete(token);
  }
  elements.agencyAssignmentPanel.hidden = false;
  if (elements.agencyAssignmentTarget) {
    elements.agencyAssignmentTarget.textContent = `Odbiorca: ${target.label} (${target.id}). Odbiorca jest zablokowany do zamknięcia tego wyboru.`;
  }
  updateAgencyAssignmentSummary();
}

function openAgencyAssignmentPanel(member) {
  if (!member || isEmployeeAccount()) return;
  agencyAssignmentTargetId = member.id;
  agencyAssignmentSelectedPolicyTokens.clear();
  setAgencyStatus(elements.agencyAssignmentStatus, "");
  renderAgencyAssignmentPicker();
  elements.agencyAssignmentPanel?.scrollIntoView?.({ behavior: "smooth", block: "nearest" });
}

function setAgencyAssignmentActive(active) {
  agencyAssignmentActive = Boolean(active);
  if (elements.agencyAssignmentChoose) elements.agencyAssignmentChoose.disabled = agencyAssignmentActive;
  if (elements.agencyAssignmentClose) elements.agencyAssignmentClose.disabled = agencyAssignmentActive;
  updateAgencyAssignmentSummary();
}







let agencyPolicyPickerMode = "";
let agencyPolicyPickerRenderTimer = null;
const agencyPolicyPickerWorkingSelection = new Set();
const agencyPolicyPickerOpenGroups = new Set();

function getAgencyPolicyPickerTargetSelection(mode = agencyPolicyPickerMode) {
  if (mode === "assignment") return agencyAssignmentSelectedPolicyTokens;
  if (mode === "seed") return agencySeedSelectedPolicyTokens;
  return null;
}

function getAgencyPolicyPickerPeriodRange() {
  const choice = elements.agencyPolicyPickerPeriod?.value || "";
  if (choice === "custom") {
    const from = parseLocalDate(elements.agencyPolicyPickerFrom?.value || "");
    const to = parseLocalDate(elements.agencyPolicyPickerTo?.value || "");
    if (!from && !to) return null;
    return { from, to };
  }
  const today = new Date();
  today.setHours(0, 0, 0, 0);
  if (choice === "year") return { from: new Date(today.getFullYear(), 0, 1), to: null };
  const days = Number(choice);
  if (Number.isFinite(days) && days > 0) {
    const from = new Date(today);
    from.setDate(from.getDate() - days);
    return { from, to: null };
  }
  return null;
}

function getAgencyPolicyPickerFilters() {
  const periodChoice = elements.agencyPolicyPickerPeriod?.value || "";
  const normalizedQuery = normalize(elements.agencyPolicyPickerSearch?.value || "");
  return {
    activeOnly: periodChoice === "active",
    periodRange: periodChoice === "active" ? null : getAgencyPolicyPickerPeriodRange(),
    normalizedQuery,
    compactQuery: normalizedQuery.replace(/[\s-]+/g, ""),
  };
}

function agencyPolicyPickerPolicyMatches(policy, filters) {
  if (filters.activeOnly) {
    const today = new Date();
    today.setHours(0, 0, 0, 0);
    const validUntil = parseLocalDate(String(policy?.validUntil || ""));
    if (!validUntil || validUntil < today) return false;
  }
  if (filters.periodRange) {
    const startDate = getPolicyStartDate(policy);
    if (!startDate) return false;
    if (filters.periodRange.from && startDate < filters.periodRange.from) return false;
    if (filters.periodRange.to && startDate > filters.periodRange.to) return false;
  }
  if (
    filters.normalizedQuery
    && !policyMatchesAgencyExportClient(policy, filters.normalizedQuery, filters.compactQuery)
  ) return false;
  return true;
}

function getAgencyPolicyPickerVisiblePolicies(filters = getAgencyPolicyPickerFilters()) {
  return policies.filter((policy) => agencyPolicyPickerPolicyMatches(policy, filters));
}

function syncAgencyPolicyPickerCustomRangeVisibility() {
  const custom = elements.agencyPolicyPickerPeriod?.value === "custom";
  if (elements.agencyPolicyPickerFromField) elements.agencyPolicyPickerFromField.hidden = !custom;
  if (elements.agencyPolicyPickerToField) elements.agencyPolicyPickerToField.hidden = !custom;
}

function updateAgencyPolicyPickerSummary(visiblePolicies = getAgencyPolicyPickerVisiblePolicies()) {
  if (!elements.agencyPolicyPickerSummary) return;
  const selectedPolicies = getSelectedAgencySeedPolicies(policies, agencyPolicyPickerWorkingSelection);
  const attachmentCount = selectedPolicies.reduce(
    (sum, policy) => sum + normalizePolicyAttachments(policy?.attachments).length,
    0,
  );
  const overLimit = selectedPolicies.length > MAX_AGENCY_SEED_POLICIES;
  if (overLimit) {
    elements.agencyPolicyPickerSummary.textContent = (
      `Wybrano ${pluralizePolicies(selectedPolicies.length)} - to więcej niż limit `
      + `${MAX_AGENCY_SEED_POLICIES.toLocaleString("pl-PL")} polis w jednej paczce. Odznacz część.`
    );
    elements.agencyPolicyPickerSummary.dataset.tone = "warning";
  } else {
    const breakdown = describeAgencySelectionByInsurer(selectedPolicies);
    const attachmentsPart = attachmentCount > 0 ? ` i ${pluralizeAttachments(attachmentCount)}` : "";
    const filteredPart = visiblePolicies.length === policies.length
      ? ""
      : ` Filtry pokazują ${visiblePolicies.length} z ${policies.length} polis.`;
    elements.agencyPolicyPickerSummary.textContent = selectedPolicies.length === 0
      ? `Nie wybrano żadnej polisy.${filteredPart}`
      : `Wybrano ${pluralizePolicies(selectedPolicies.length)}`
        + `${breakdown ? ` (${breakdown})` : ""}${attachmentsPart}.${filteredPart}`;
    elements.agencyPolicyPickerSummary.dataset.tone = selectedPolicies.length === 0 ? "warning" : "";
  }
  if (elements.agencyPolicyPickerConfirm) elements.agencyPolicyPickerConfirm.disabled = overLimit;
}

function refreshAgencyPolicyPickerGroupHeader(group) {
  const rowCheckboxes = [...group.querySelectorAll("[data-agency-seed-policy-token]")];
  const selectedCount = rowCheckboxes.filter((checkbox) => checkbox.checked).length;
  const groupCheckbox = group.querySelector("[data-agency-picker-group-toggle]");
  if (groupCheckbox) {
    groupCheckbox.checked = rowCheckboxes.length > 0 && selectedCount === rowCheckboxes.length;
    groupCheckbox.indeterminate = selectedCount > 0 && selectedCount < rowCheckboxes.length;
  }
  const countLabel = group.querySelector("[data-agency-picker-group-count]");
  if (countLabel) {
    countLabel.textContent = selectedCount > 0
      ? `zaznaczone ${selectedCount} z ${rowCheckboxes.length}`
      : `${pluralizePolicies(rowCheckboxes.length)}`;
  }
}

function renderAgencyPolicyPickerGroups() {
  if (!elements.agencyPolicyPickerGroups) return;
  const filters = getAgencyPolicyPickerFilters();
  const visiblePolicies = getAgencyPolicyPickerVisiblePolicies(filters);
  
  const forceOpen = Boolean(filters.normalizedQuery);
  const groups = new Map();
  visiblePolicies.forEach((policy) => {
    const name = String(policy?.insurer || "").trim() || "Bez towarzystwa";
    if (!groups.has(name)) groups.set(name, []);
    groups.get(name).push(policy);
  });
  const fragment = document.createDocumentFragment();
  [...groups.keys()].sort(compareAlphabetically).forEach((groupName) => {
    const groupPolicies = groups.get(groupName).sort((first, second) => (
      compareAlphabetically(first?.clientName, second?.clientName)
      || compareAlphabetically(first?.policyNumber, second?.policyNumber)
    ));

    const group = document.createElement("details");
    group.className = "agency-policy-picker-group";
    group.dataset.agencyPickerGroup = groupName;
    group.open = forceOpen || agencyPolicyPickerOpenGroups.has(groupName);

    const summary = document.createElement("summary");
    summary.className = "agency-policy-picker-group__summary";
    const groupCheckbox = document.createElement("input");
    groupCheckbox.type = "checkbox";
    groupCheckbox.dataset.agencyPickerGroupToggle = groupName;
    groupCheckbox.title = "Zaznacz lub odznacz wszystkie widoczne polisy tego towarzystwa";
    const groupLabel = document.createElement("strong");
    groupLabel.textContent = groupName;
    const groupCount = document.createElement("small");
    groupCount.dataset.agencyPickerGroupCount = "true";
    summary.append(groupCheckbox, groupLabel, groupCount);
    group.append(summary);

    const list = document.createElement("div");
    list.className = "agency-policy-picker-group__rows";
    groupPolicies.forEach((policy) => {
      const policyToken = getAgencySeedPolicyToken(policy);
      const row = document.createElement("label");
      row.className = "agency-seed-policy";
      const checkbox = document.createElement("input");
      checkbox.type = "checkbox";
      checkbox.dataset.agencySeedPolicyToken = policyToken;
      checkbox.checked = agencyPolicyPickerWorkingSelection.has(policyToken);
      const details = document.createElement("span");
      details.className = "agency-seed-policy__details";
      const client = document.createElement("strong");
      client.textContent = String(policy?.clientName || "Bez nazwy klienta");
      const description = document.createElement("small");
      const policyNumber = String(policy?.policyNumber || "bez numeru");
      const validUntil = String(policy?.validUntil || "").trim();
      description.textContent = `polisa ${policyNumber}${validUntil ? ` · do ${validUntil}` : ""}`;
      details.append(client, description);
      row.append(checkbox, details);
      list.append(row);
    });
    group.append(list);
    refreshAgencyPolicyPickerGroupHeader(group);
    fragment.append(group);
  });
  elements.agencyPolicyPickerGroups.replaceChildren(fragment);
  if (elements.agencyPolicyPickerEmpty) {
    elements.agencyPolicyPickerEmpty.hidden = visiblePolicies.length > 0;
  }
  updateAgencyPolicyPickerSummary(visiblePolicies);
}

function scheduleAgencyPolicyPickerRender() {
  if (agencyPolicyPickerRenderTimer) globalThis.clearTimeout(agencyPolicyPickerRenderTimer);
  agencyPolicyPickerRenderTimer = globalThis.setTimeout(() => {
    agencyPolicyPickerRenderTimer = null;
    renderAgencyPolicyPickerGroups();
  }, 150);
}

function openAgencyPolicyPicker(mode) {
  if (!elements.agencyPolicyPickerDialog) return;
  const targetSelection = getAgencyPolicyPickerTargetSelection(mode);
  if (!targetSelection) return;
  agencyPolicyPickerMode = mode;
  const currentTokens = new Set(policies.map(getAgencySeedPolicyToken).filter(Boolean));
  for (const token of targetSelection) {
    if (!currentTokens.has(token)) targetSelection.delete(token);
  }
  agencyPolicyPickerWorkingSelection.clear();
  targetSelection.forEach((token) => agencyPolicyPickerWorkingSelection.add(token));
  if (elements.agencyPolicyPickerContext) {
    const target = mode === "assignment" ? getAgencyAssignmentTarget() : null;
    elements.agencyPolicyPickerContext.textContent = mode === "assignment" && target
      ? `Paczka dla pracownika: ${target.label} (${target.id}).`
      : "Startowa baza nowego pracownika.";
  }
  
  if (elements.agencyPolicyPickerSearch) elements.agencyPolicyPickerSearch.value = "";
  if (elements.agencyPolicyPickerPeriod) elements.agencyPolicyPickerPeriod.value = "";
  if (elements.agencyPolicyPickerFrom) elements.agencyPolicyPickerFrom.value = "";
  if (elements.agencyPolicyPickerTo) elements.agencyPolicyPickerTo.value = "";
  syncAgencyPolicyPickerCustomRangeVisibility();
  agencyPolicyPickerOpenGroups.clear();
  renderAgencyPolicyPickerGroups();
  if (!elements.agencyPolicyPickerDialog.open) elements.agencyPolicyPickerDialog.showModal();
}

function closeAgencyPolicyPicker() {
  agencyPolicyPickerMode = "";
  agencyPolicyPickerWorkingSelection.clear();
  if (elements.agencyPolicyPickerDialog?.open) elements.agencyPolicyPickerDialog.close();
}

function confirmAgencyPolicyPickerSelection() {
  const mode = agencyPolicyPickerMode;
  const targetSelection = getAgencyPolicyPickerTargetSelection(mode);
  if (!targetSelection) {
    closeAgencyPolicyPicker();
    return;
  }
  const selectedPolicies = getSelectedAgencySeedPolicies(policies, agencyPolicyPickerWorkingSelection);
  if (selectedPolicies.length > MAX_AGENCY_SEED_POLICIES) {
    updateAgencyPolicyPickerSummary();
    return;
  }
  targetSelection.clear();
  selectedPolicies.forEach((policy) => {
    const policyToken = getAgencySeedPolicyToken(policy);
    if (policyToken) targetSelection.add(policyToken);
  });
  closeAgencyPolicyPicker();
  setAgencyStatus(
    mode === "assignment" ? elements.agencyAssignmentStatus : elements.agencyGenerateStatus,
    "",
  );
  if (mode === "assignment") updateAgencyAssignmentSummary();
  else updateAgencySeedSummary();
}

function setAgencyPolicyPickerPolicies(policyRecords, shouldSelect) {
  policyRecords.forEach((policy) => {
    const policyToken = getAgencySeedPolicyToken(policy);
    if (!policyToken) return;
    if (shouldSelect) agencyPolicyPickerWorkingSelection.add(policyToken);
    else agencyPolicyPickerWorkingSelection.delete(policyToken);
  });
  renderAgencyPolicyPickerGroups();
}

function clearAgencyPairingCodeDialog() {
  if (elements.agencyPairingCodeOutput) elements.agencyPairingCodeOutput.textContent = "";
  if (elements.agencyPairingCodeDialog?.open) elements.agencyPairingCodeDialog.close();
}

function refreshAgencyAssignmentImportPanel() {
  const employee = isEmployeeAccount();
  const pairingReady = employee && currentAccount?.pairingReady === true;
  if (elements.agencyAssignmentImportSection) elements.agencyAssignmentImportSection.hidden = !employee;
  if (elements.agencyPairingPanel) elements.agencyPairingPanel.hidden = !employee || pairingReady;
  if (elements.agencyAssignmentImportControls) elements.agencyAssignmentImportControls.hidden = !pairingReady;
  if (elements.agencyAssignmentImportButton) elements.agencyAssignmentImportButton.disabled = !pairingReady;
  if (employee && !pairingReady) {
    setAgencyStatus(
      elements.agencyAssignmentImportStatus,
      "Ta starsza instalacja wymaga jednorazowego sparowania z centralą przed importem.",
      "warning",
    );
  } else if (!employee) {
    setAgencyStatus(elements.agencyAssignmentImportStatus, "");
  }
}

function refreshAgencySettingsPanel() {
  if (!elements.settingsAgencyPanel) return;
  const employee = isEmployeeAccount();
  if (elements.agencyAccountName) {
    elements.agencyAccountName.value = currentAccount?.name || "";
    elements.agencyAccountName.disabled = employee;
    elements.agencyAccountName.title = employee ? "Nazwę tego konta ustaliła centrala." : "";
  }
  if (elements.agencyAccountNameSave) elements.agencyAccountNameSave.hidden = employee;
  if (elements.agencyAccountId) elements.agencyAccountId.textContent = currentAccount?.id || "-";
  if (elements.agencyMembersSection) elements.agencyMembersSection.hidden = employee;
  if (elements.agencyGeneratorSection) elements.agencyGeneratorSection.hidden = employee;
  renderAgencyInsurerSettings();
  renderAgencyMembers();
  renderAgencySeedPicker();
  renderAgencyAssignmentPicker();
  refreshAgencyAssignmentImportPanel();
  refreshAgencyExportPanel();
}




function getProfileFilterLabel() {
  if (!activeProfileFilter) return "Wszyscy";
  if (currentAccount && activeProfileFilter === currentAccount.id) {
    return `${currentAccount.name} (moje)`;
  }
  return getAgencyMemberById(activeProfileFilter)?.label || "Wszyscy";
}

function setProfileFilter(accountId) {
  activeProfileFilter = accountId || "";
  try {
    globalThis.sessionStorage?.setItem(PROFILE_FILTER_SESSION_KEY, activeProfileFilter);
  } catch {
  }
  refreshProfileSwitcher();
  closeProfileSwitcherMenu();
  render();
}

function closeProfileSwitcherMenu() {
  const menu = document.querySelector("#profileSwitcherMenu");
  const button = document.querySelector("#profileSwitcherButton");
  if (menu) menu.hidden = true;
  if (button) button.setAttribute("aria-expanded", "false");
}

function renderProfileSwitcherMenu() {
  const menu = document.querySelector("#profileSwitcherMenu");
  if (!menu) return;
  const options = [
    { id: "", label: "Wszyscy" },
    ...(currentAccount ? [{ id: currentAccount.id, label: `${currentAccount.name} (moje)` }] : []),
    ...agencyMembers.map((member) => ({ id: member.id, label: member.label })),
  ];
  menu.innerHTML = options.map((option) => `
    <button
      type="button"
      role="menuitemradio"
      aria-checked="${String(option.id === activeProfileFilter)}"
      data-profile-id="${escapeHtml(option.id)}"
    >${escapeHtml(option.label)}</button>
  `).join("");
}

function refreshProfileSwitcher() {
  const switcher = document.querySelector("#profileSwitcher");
  const label = document.querySelector("#profileSwitcherLabel");
  if (!switcher) return;
  const visible = agencyMembers.length > 0;
  switcher.hidden = !visible;
  if (!visible && activeProfileFilter) {
    
    activeProfileFilter = "";
  }
  if (visible && activeProfileFilter && activeProfileFilter !== currentAccount?.id
    && !getAgencyMemberById(activeProfileFilter)) {
    activeProfileFilter = "";
  }
  if (label) label.textContent = getProfileFilterLabel();
  renderProfileSwitcherMenu();
  refreshRenewalAccountsFilter();
}

function initializeProfileSwitcher() {
  const button = document.querySelector("#profileSwitcherButton");
  const menu = document.querySelector("#profileSwitcherMenu");
  if (!button || !menu) return;
  try {
    const savedFilter = globalThis.sessionStorage?.getItem(PROFILE_FILTER_SESSION_KEY);
    if (savedFilter) activeProfileFilter = savedFilter;
  } catch {
  }
  button.addEventListener("click", () => {
    const willOpen = menu.hidden;
    menu.hidden = !willOpen;
    button.setAttribute("aria-expanded", String(willOpen));
    if (willOpen) renderProfileSwitcherMenu();
  });
  menu.addEventListener("click", (event) => {
    const option = event.target.closest("[data-profile-id]");
    if (option) setProfileFilter(option.dataset.profileId);
  });
  document.addEventListener("click", (event) => {
    if (!event.target.closest("#profileSwitcher")) closeProfileSwitcherMenu();
  });
  document.addEventListener("keydown", (event) => {
    if (event.key === "Escape") closeProfileSwitcherMenu();
  });
}

initializeProfileSwitcher();



function getRenewalAccountOptions() {
  return [
    ...(currentAccount ? [{ id: currentAccount.id, label: `${currentAccount.name} (moje)` }] : []),
    ...agencyMembers.map((member) => ({ id: member.id, label: member.label })),
  ];
}

function refreshRenewalAccountsFilter() {
  const container = document.querySelector("#renewalAccountsFilter");
  const button = document.querySelector("#renewalAccountsButton");
  if (!container) return;
  container.hidden = agencyMembers.length === 0;
  if (button) {
    
    const filterActive = getRenewalAccountOptions().some((option) => renewalOwnerExclusions.has(option.id));
    button.classList.toggle("renewal-accounts-button--active", filterActive);
  }
}

function renderRenewalAccountsMenu() {
  const menu = document.querySelector("#renewalAccountsMenu");
  if (!menu) return;
  const options = getRenewalAccountOptions();
  menu.innerHTML = `
    <p class="renewal-accounts-menu-title">Czyje odnowienia pokazywać</p>
    ${options.map((option) => `
      <label class="renewal-account-option">
        <input type="checkbox" data-renewal-account="${escapeHtml(option.id)}" ${renewalOwnerExclusions.has(option.id) ? "" : "checked"} />
        <span>${escapeHtml(option.label)}</span>
      </label>
    `).join("")}
  `;
}

function initializeRenewalAccountsFilter() {
  const button = document.querySelector("#renewalAccountsButton");
  const menu = document.querySelector("#renewalAccountsMenu");
  if (!button || !menu) return;
  const closeMenu = () => {
    menu.hidden = true;
    button.setAttribute("aria-expanded", "false");
  };
  button.addEventListener("click", () => {
    const willOpen = menu.hidden;
    if (!willOpen) {
      closeMenu();
      return;
    }
    renderRenewalAccountsMenu();
    menu.hidden = false;
    
    const buttonRect = button.getBoundingClientRect();
    menu.style.top = `${Math.round(buttonRect.bottom + 9)}px`;
    menu.style.left = `${Math.round(buttonRect.right - menu.offsetWidth + 4)}px`;
    button.setAttribute("aria-expanded", "true");
  });
  
  globalThis.addEventListener("scroll", () => {
    if (!menu.hidden) closeMenu();
  }, { passive: true });
  menu.addEventListener("change", (event) => {
    const checkbox = event.target.closest("[data-renewal-account]");
    if (!checkbox) return;
    const accountId = checkbox.dataset.renewalAccount;
    if (checkbox.checked) renewalOwnerExclusions.delete(accountId);
    else renewalOwnerExclusions.add(accountId);
    saveRenewalOwnerExclusions();
    refreshRenewalAccountsFilter();
    render();
  });
  document.addEventListener("click", (event) => {
    if (!event.target.closest("#renewalAccountsFilter")) {
      menu.hidden = true;
      button.setAttribute("aria-expanded", "false");
    }
  });
}

initializeRenewalAccountsFilter();

async function copyAgencyIdToClipboard(text, toastLabel) {
  if (!text || text === "-") return;
  try {
    await globalThis.navigator?.clipboard?.writeText(text);
    showToast(toastLabel || "Skopiowano identyfikator");
  } catch {
    showToast("Nie udało się skopiować", "error");
  }
}






let employeePackageImportGate = Promise.resolve();

function runEmployeePackageImportExclusive(operation) {
  const scheduledOperation = employeePackageImportGate
    .catch(() => {})
    .then(() => {
      if (globalThis.navigator?.locks?.request) {
        return globalThis.navigator.locks.request(
          EMPLOYEE_PACKAGE_IMPORT_LOCK_NAME,
          { mode: "exclusive" },
          operation,
        );
      }
      return operation();
    });
  employeePackageImportGate = scheduledOperation.catch(() => {});
  return scheduledOperation;
}

function normalizeEmployeePackageTransactionId(value) {
  const transactionId = String(value || "").trim();
  return EMPLOYEE_PACKAGE_TRANSACTION_ID_PATTERN.test(transactionId) ? transactionId : "";
}

function normalizeEmployeePackageCounter(value) {
  const count = Number(value);
  if (!Number.isSafeInteger(count) || count < 0) {
    throw new Error("Serwer zwrócił nieprawidłowy stan importu paczki.");
  }
  return count;
}

function normalizeEmployeePackageDigest(value) {
  const digest = String(value || "").trim().toLowerCase();
  return EMPLOYEE_PACKAGE_DIGEST_PATTERN.test(digest) ? digest : "";
}

function normalizeEmployeePackagePlanCounter(value) {
  if (Array.isArray(value)) return value.length;
  return normalizeEmployeePackageCounter(value);
}

function normalizeEmployeePackageTransaction(transaction, {
  allowedStates = ["staged", "files_applied", "rollback_blocked"],
} = {}) {
  const transactionId = normalizeEmployeePackageTransactionId(transaction?.transactionId);
  const accountId = normalizePolicyOwnerId(transaction?.accountId);
  const centralAccountId = normalizePolicyOwnerId(transaction?.centralAccountId);
  const baseDigest = normalizeEmployeePackageDigest(transaction?.baseDigest);
  const packageDigest = normalizeEmployeePackageDigest(transaction?.packageDigest);
  const planDigest = normalizeEmployeePackageDigest(transaction?.planDigest);
  const state = String(transaction?.state || "");
  const kind = transaction?.kind === undefined
    ? EMPLOYEE_TO_CENTRAL_PACKAGE_KIND
    : String(transaction.kind || "");
  if (
    !transactionId
    || !allowedStates.includes(state)
    || !accountId
    || !centralAccountId
    || !baseDigest
    || !packageDigest
    || !planDigest
    || kind !== EMPLOYEE_TO_CENTRAL_PACKAGE_KIND
    || !Array.isArray(transaction?.policies)
    || (state === "files_applied" && transaction?.requiresConfirmation !== true)
  ) {
    throw new Error("Serwer zwrócił nieprawidłowy stan importu paczki.");
  }
  const normalizedTransaction = {
    transactionId,
    kind,
    state,
    requiresConfirmation: state === "files_applied",
    centralAccountId,
    baseDigest,
    packageDigest,
    planDigest,
    accountId,
    accountName: String(transaction.accountName || ""),
    policies: normalizeLoadedPolicies(transaction.policies, accountId),
  };
  if (state === "staged") {
    normalizedTransaction.attachmentsToCreate = normalizeEmployeePackagePlanCounter(
      transaction.attachmentsToCreate,
    );
    normalizedTransaction.attachmentsToReuse = normalizeEmployeePackagePlanCounter(
      transaction.attachmentsToReuse,
    );
    normalizedTransaction.attachmentsToRename = normalizeEmployeePackagePlanCounter(
      transaction.attachmentsToRename,
    );
  } else {
    normalizedTransaction.attachmentsCopied = normalizeEmployeePackageCounter(
      transaction.attachmentsCopied,
    );
    normalizedTransaction.attachmentsReused = normalizeEmployeePackageCounter(
      transaction.attachmentsReused,
    );
    normalizedTransaction.attachmentsRenamed = normalizeEmployeePackageCounter(
      transaction.attachmentsRenamed,
    );
  }
  return normalizedTransaction;
}

function getEmployeePackageTransactionActionUrl(transactionId, action) {
  const normalizedTransactionId = normalizeEmployeePackageTransactionId(transactionId);
  if (
    !normalizedTransactionId
    || (action !== "apply" && action !== "confirm" && action !== "rollback")
  ) {
    throw new Error("Nieprawidłowy identyfikator transakcji paczki.");
  }
  return `/api/konto/import-paczki/${encodeURIComponent(normalizedTransactionId)}/${action}`;
}

async function postEmployeePackageTransactionAction(transaction, action) {
  const normalizedTransactionId = normalizeEmployeePackageTransactionId(
    transaction?.transactionId,
  );
  const baseDigest = normalizeEmployeePackageDigest(transaction?.baseDigest);
  const packageDigest = normalizeEmployeePackageDigest(transaction?.packageDigest);
  const planDigest = normalizeEmployeePackageDigest(transaction?.planDigest);
  if (!normalizedTransactionId || !baseDigest || !packageDigest || !planDigest) {
    throw new Error("Nieprawidłowy dowód transakcji paczki.");
  }
  const response = await apiFetch(
    getEmployeePackageTransactionActionUrl(normalizedTransactionId, action),
    {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({ baseDigest, packageDigest, planDigest }),
    },
  );
  const data = await response.json().catch(() => null);
  if (!response.ok || data?.ok !== true) {
    const failureMessages = {
      apply: "Nie udało się zastosować plików importowanej paczki.",
      confirm: "Nie udało się potwierdzić importu paczki.",
      rollback: "Nie udało się cofnąć plików importowanej paczki.",
    };
    throw new Error(failureMessages[action] || "Nie udało się wykonać operacji na paczce.");
  }
  return true;
}

function confirmEmployeePackageImport(transaction) {
  return postEmployeePackageTransactionAction(transaction, "confirm");
}

function rollbackEmployeePackageImport(transaction) {
  return postEmployeePackageTransactionAction(transaction, "rollback");
}

async function applyEmployeePackageImport(stagedTransaction) {
  const baseDigest = normalizeEmployeePackageDigest(stagedTransaction?.baseDigest);
  const packageDigest = normalizeEmployeePackageDigest(stagedTransaction?.packageDigest);
  const planDigest = normalizeEmployeePackageDigest(stagedTransaction?.planDigest);
  if (!baseDigest || !packageDigest || !planDigest) {
    throw new Error("Nieprawidłowy dowód przygotowanej paczki.");
  }
  const response = await apiFetch(
    getEmployeePackageTransactionActionUrl(stagedTransaction.transactionId, "apply"),
    {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({ baseDigest, packageDigest, planDigest }),
    },
  );
  const data = await response.json().catch(() => null);
  if (!response.ok) throw new Error("Nie udało się bezpiecznie zastosować plików paczki.");
  const appliedTransaction = normalizeEmployeePackageTransaction(data, {
    allowedStates: ["files_applied"],
  });
  if (
    appliedTransaction.transactionId !== stagedTransaction.transactionId
    || appliedTransaction.accountId !== stagedTransaction.accountId
    || appliedTransaction.centralAccountId !== stagedTransaction.centralAccountId
    || appliedTransaction.baseDigest !== stagedTransaction.baseDigest
    || appliedTransaction.packageDigest !== stagedTransaction.packageDigest
    || appliedTransaction.planDigest !== stagedTransaction.planDigest
  ) {
    throw new Error("Serwer zwrócił niespójny stan zastosowanej paczki.");
  }
  return appliedTransaction;
}

async function rollbackEmployeePackageImportBestEffort(transaction) {
  try {
    await rollbackEmployeePackageImport(transaction);
    return true;
  } catch {
    return false;
  }
}

function cloneEmployeePackagePolicies(sourcePolicies = policies) {
  if (typeof globalThis.structuredClone === "function") {
    return globalThis.structuredClone(sourcePolicies);
  }
  return JSON.parse(JSON.stringify(sourcePolicies));
}

function captureEmployeePackageRollbackSnapshot() {
  return {
    policies: cloneEmployeePackagePolicies(),
    employeePackageImportReceipts: normalizeEmployeePackageImportReceipts(
      employeePackageImportReceipts,
    ),
    hasUnsavedPolicyChanges,
  };
}

function restoreEmployeePackageRollbackSnapshot(snapshot) {
  policies = snapshot?.policies || [];
  employeePackageImportReceipts = normalizeEmployeePackageImportReceipts(
    snapshot?.employeePackageImportReceipts,
  );
  hasUnsavedPolicyChanges = snapshot?.hasUnsavedPolicyChanges === true;
  updateDataFileStatus();
}

function getEmployeePackageChangesCount(report) {
  return report.addedCount + report.stampedCount + report.refreshedCount;
}

function getEmployeePackageSourceAccountId(transaction) {
  return normalizePolicyOwnerId(transaction?.sourceAccountId || transaction?.accountId);
}

function getEmployeePackageReceiptKind(transaction) {
  if (transaction?.kind === CENTRAL_TO_EMPLOYEE_PACKAGE_KIND || transaction?.targetAccountId) {
    return CENTRAL_TO_EMPLOYEE_PACKAGE_KIND;
  }
  return EMPLOYEE_TO_CENTRAL_PACKAGE_KIND;
}

function getEmployeePackageTargetAccountId(transaction) {
  return normalizePolicyOwnerId(transaction?.targetAccountId || transaction?.centralAccountId);
}

function createEmployeePackageImportReceipt(transaction) {
  return {
    txId: transaction.transactionId,
    kind: getEmployeePackageReceiptKind(transaction),
    packageDigest: transaction.packageDigest,
    planDigest: transaction.planDigest,
    sourceAccountId: getEmployeePackageSourceAccountId(transaction),
    targetAccountId: getEmployeePackageTargetAccountId(transaction),
  };
}

function getEmployeePackageImportReceiptStatus(transaction, receipts = employeePackageImportReceipts) {
  const expectedKind = getEmployeePackageReceiptKind(transaction);
  const normalizedReceipts = normalizeEmployeePackageImportReceipts(receipts);
  const receipt = normalizedReceipts
    .find((entry) => entry.txId === transaction.transactionId && entry.kind === expectedKind);
  if (!receipt) {
    return normalizedReceipts.some((entry) => entry.txId === transaction.transactionId)
      ? "mismatch"
      : "absent";
  }
  return (
    receipt.kind === expectedKind
    && receipt.packageDigest === transaction.packageDigest
    && receipt.planDigest === transaction.planDigest
    && receipt.sourceAccountId === getEmployeePackageSourceAccountId(transaction)
    && receipt.targetAccountId === getEmployeePackageTargetAccountId(transaction)
  ) ? "exact" : "mismatch";
}

function addEmployeePackageImportReceipt(transaction) {
  const receipt = createEmployeePackageImportReceipt(transaction);
  employeePackageImportReceipts = normalizeEmployeePackageImportReceipts([
    ...employeePackageImportReceipts.filter((entry) => (
      entry.txId !== receipt.txId || entry.kind !== receipt.kind
    )),
    receipt,
  ]);
}

async function calculateEmployeePackageBaseDigest(
  policyRecords = policies,
  deletedRecords = deletedPolicies,
  taskRecords = calendarTasks,
  importReceipts = employeePackageImportReceipts,
) {
  if (!globalThis.crypto?.subtle || typeof TextEncoder !== "function") {
    throw new Error("Ta przeglądarka nie udostępnia bezpiecznego SHA-256 wymaganego do importu ZIP.");
  }
  try {
    const contents = new TextEncoder().encode(getPoliciesFingerprint(
      policyRecords,
      deletedRecords,
      taskRecords,
      importReceipts,
    ));
    const digest = await globalThis.crypto.subtle.digest("SHA-256", contents);
    return [...new Uint8Array(digest)]
      .map((byte) => byte.toString(16).padStart(2, "0"))
      .join("");
  } catch {
    throw new Error("Nie udało się obliczyć bezpiecznej rewizji SHA-256 bieżącej bazy.");
  }
}



function mergeEmployeePoliciesIntoBase(member, employeePolicies) {
  const mergePlan = planEmployeePoliciesMerge(member, employeePolicies);
  if (mergePlan.report.conflictCount === 0) policies = mergePlan.policies;
  return mergePlan.report;
}

function getEmployeePackageAttachmentReferenceKey(attachment) {
  const relativePath = normalizeAttachmentRelativePath(attachment?.relativePath);
  if (attachment?.storage === "file" && relativePath) {
    return `file:${relativePath.join("/")}`;
  }
  return `inline:${String(attachment?.dataUrl || "")}`;
}

function planEmployeePolicyAttachmentMerge(existingAttachments, importedAttachments) {
  const normalizedExisting = normalizePolicyAttachments(existingAttachments);
  const normalizedImported = normalizePolicyAttachments(importedAttachments);
  const references = new Set();
  const referencesById = new Map();
  for (const attachment of normalizedExisting) {
    const attachmentId = String(attachment.id || "");
    const referenceKey = getEmployeePackageAttachmentReferenceKey(attachment);
    references.add(referenceKey);
    if (attachmentId) referencesById.set(attachmentId, referenceKey);
  }

  const additions = [];
  const incomingReferencesById = new Map();
  for (const attachment of normalizedImported) {
    const attachmentId = String(attachment.id || "");
    const referenceKey = getEmployeePackageAttachmentReferenceKey(attachment);
    const earlierIncomingReference = incomingReferencesById.get(attachmentId);
    if (earlierIncomingReference && earlierIncomingReference !== referenceKey) {
      return { conflict: true, attachments: normalizedExisting };
    }
    if (attachmentId) incomingReferencesById.set(attachmentId, referenceKey);
    const existingReferenceForId = referencesById.get(attachmentId);
    if (existingReferenceForId && existingReferenceForId !== referenceKey) {
      return { conflict: true, attachments: normalizedExisting };
    }
    if (existingReferenceForId || references.has(referenceKey)) continue;
    references.add(referenceKey);
    if (attachmentId) referencesById.set(attachmentId, referenceKey);
    additions.push(attachment);
  }
  return {
    conflict: false,
    attachments: [...normalizedExisting, ...cloneEmployeePackagePolicies(additions)],
    addedCount: additions.length,
  };
}

function centralAssignmentIdentityFieldsConflict(existingPolicy, importedPolicy) {
  const compactIdentifier = (value) => String(value || "")
    .trim()
    .toUpperCase()
    .replace(/[^A-Z0-9]/g, "");
  const normalizedName = (value) => String(value || "")
    .trim()
    .toLocaleLowerCase("pl-PL")
    .replace(/\s+/g, " ");
  const comparablePairs = [
    [compactIdentifier(existingPolicy?.identityNumber), compactIdentifier(importedPolicy?.identityNumber)],
    [
      compactIdentifier(existingPolicy?.secondaryIdentityNumber),
      compactIdentifier(importedPolicy?.secondaryIdentityNumber),
    ],
    [normalizedName(existingPolicy?.clientName), normalizedName(importedPolicy?.clientName)],
    [compactIdentifier(existingPolicy?.vin), compactIdentifier(importedPolicy?.vin)],
    [compactIdentifier(existingPolicy?.registration), compactIdentifier(importedPolicy?.registration)],
  ];
  return comparablePairs.some(([existingValue, importedValue]) => (
    existingValue && importedValue && existingValue !== importedValue
  ));
}

function planEmployeePoliciesMerge(member, employeePolicies, {
  basePolicies = policies,
  deletedRecords = deletedPolicies,
  requireExactOwner = false,
} = {}) {
  const plannedPolicies = cloneEmployeePackagePolicies(basePolicies);
  const policiesById = new Map(plannedPolicies.map((policy) => [policy.id, policy]));
  const policiesByMergeKey = buildPortfolioMergeKeyIndex(plannedPolicies);
  const deletedById = new Map(deletedRecords.map((policy) => [policy.id, policy]));
  const deletedByMergeKey = buildPortfolioMergeKeyIndex(deletedRecords);
  const incomingIds = new Set();
  const incomingIdentityKeys = new Set();
  let addedCount = 0;
  let stampedCount = 0;
  let refreshedCount = 0;
  let conflictCount = 0;

  for (const employeePolicy of employeePolicies) {
    const incomingId = String(employeePolicy?.id || "");
    const incomingOwnerId = normalizePolicyOwnerId(employeePolicy?.ownerId);
    const policyNumberKey = getPolicyNumberKey(employeePolicy);
    const incomingIdentityKey = policyNumberKey ? getPolicyIdentityPeriodKey(employeePolicy) : "";
    if (
      !incomingId
      || (requireExactOwner && !incomingOwnerId)
      || incomingIds.has(incomingId)
      || (incomingIdentityKey && incomingIdentityKeys.has(incomingIdentityKey))
    ) {
      conflictCount += 1;
      continue;
    }
    incomingIds.add(incomingId);
    if (incomingIdentityKey) incomingIdentityKeys.add(incomingIdentityKey);

    const deletedByNumberResolution = resolvePortfolioMergeTarget(
      deletedByMergeKey,
      employeePolicy,
    );
    if (
      deletedById.has(incomingId)
      || deletedByNumberResolution.status === "match"
      || deletedByNumberResolution.status === "ambiguous"
    ) {
      conflictCount += 1;
      continue;
    }

    const resolution = resolvePortfolioMergeTarget(policiesByMergeKey, employeePolicy);
    const policyById = policiesById.get(incomingId);
    if (
      resolution.status === "ambiguous"
      || resolution.status === "cross-insurer"
      || (policyById && !policiesHaveCompatibleIdentity(policyById, employeePolicy))
    ) {
      conflictCount += 1;
      continue;
    }
    const existing = policyById || (resolution.status === "match" ? resolution.policy : null);
    if (
      requireExactOwner
      && existing
      && (
        normalizePolicyOwnerId(existing.ownerId) !== incomingOwnerId
        || centralAssignmentIdentityFieldsConflict(existing, employeePolicy)
      )
    ) {
      conflictCount += 1;
      continue;
    }
    const attachmentMerge = planEmployeePolicyAttachmentMerge(
      existing?.attachments,
      employeePolicy.attachments,
    );
    if (attachmentMerge.conflict) {
      conflictCount += 1;
      continue;
    }
    if (!existing) {
      const record = cloneEmployeePackagePolicies([{
        ...employeePolicy,
        ownerId: incomingOwnerId || member.id,
        attachments: attachmentMerge.attachments,
      }])[0];
      plannedPolicies.push(record);
      policiesById.set(record.id, record);
      addPolicyToPortfolioMergeIndex(policiesByMergeKey, record);
      addedCount += 1;
      continue;
    }

    let changed = applyMissingImportedPolicyFields(existing, employeePolicy).length > 0;
    if (attachmentMerge.addedCount > 0) {
      existing.attachments = attachmentMerge.attachments;
      changed = true;
    }
    if (changed) {
      existing.updatedAt = Date.now();
      refreshedCount += 1;
    }
  }
  return {
    policies: plannedPolicies,
    report: { addedCount, stampedCount, refreshedCount, conflictCount },
  };
}

async function readEmployeeDatabaseFromZip(member, file, baseDigest) {
  const response = await apiFetch(
    `/api/konto/import-paczki?pracownik=${encodeURIComponent(member.id)}`
      + `&bazaRewizja=${encodeURIComponent(baseDigest)}`,
    {
    method: "POST",
    headers: { "Content-Type": "application/zip" },
    body: file,
    },
  );
  const data = await response.json().catch(() => ({}));
  if (!response.ok) throw new Error("Nie udało się bezpiecznie odczytać paczki pracownika.");
  const stagedTransaction = normalizeEmployeePackageTransaction(data, {
    allowedStates: ["staged", "files_applied"],
  });
  if (
    stagedTransaction.accountId !== member.id
    || stagedTransaction.centralAccountId !== currentAccount?.id
    || stagedTransaction.baseDigest !== baseDigest
  ) {
    throw new Error("Serwer zwrócił paczkę przypisaną do innej bazy lub innego konta.");
  }
  return stagedTransaction;
}

function getEmployeePackageReportParts(report, employeeData) {
  const reportParts = [];
  if (report.addedCount > 0) reportParts.push(`dodano ${pluralizePolicies(report.addedCount)}`);
  if (report.stampedCount > 0) reportParts.push(`oznaczono ${report.stampedCount}`);
  if (report.refreshedCount > 0) reportParts.push(`uzupełniono ${report.refreshedCount}`);
  if (employeeData.attachmentsCopied > 0) {
    reportParts.push(`skopiowano ${employeeData.attachmentsCopied} załączników`);
  }
  if (employeeData.attachmentsReused > 0) {
    reportParts.push(`wykorzystano ponownie ${employeeData.attachmentsReused} załączników`);
  }
  if (employeeData.attachmentsRenamed > 0) {
    reportParts.push(`bezpiecznie zmieniono nazwę ${employeeData.attachmentsRenamed} załączników`);
  }
  return reportParts;
}

async function inspectEmployeePackageDataFile(transaction = null) {
  const handle = dataFileHandle || rememberedDataFileHandle;
  if (!handle || !(await requestWritePermission(handle))) {
    return { status: "uncertain" };
  }
  try {
    const file = await handle.getFile();
    const inspection = await inspectPoliciesFile(file);
    const expectedCentralAccountId = transaction?.targetAccountId
      || transaction?.centralAccountId
      || currentAccount?.id
      || "";
    if (
      !expectedCentralAccountId
      || currentAccount?.id !== expectedCentralAccountId
      || inspection.documentData.accountId !== expectedCentralAccountId
    ) {
      return { status: "wrong-database" };
    }
    return {
      status: "verified",
      handle,
      file,
      inspection,
      baseDigest: await calculateEmployeePackageBaseDigest(
        inspection.documentData.policies,
        inspection.documentData.deletedPolicies,
        inspection.documentData.calendarTasks,
        inspection.documentData.employeePackageImports,
      ),
      receiptStatus: transaction
        ? getEmployeePackageImportReceiptStatus(
          transaction,
          inspection.documentData.employeePackageImports,
        )
        : "absent",
    };
  } catch {
    return { status: "uncertain" };
  }
}

async function loadVerifiedEmployeePackageDataFile(verifiedDatabase) {
  if (verifiedDatabase?.status !== "verified") return false;
  try {
    await loadPoliciesFromFile(verifiedDatabase.file, verifiedDatabase.handle, {
      inspection: verifiedDatabase.inspection,
      permissionGranted: true,
      skipLegacy: true,
      showToast: false,
      trustedSource: true,
    });
    return true;
  } catch {
    return false;
  }
}

async function rollbackConflictingEmployeePackage(transaction, message) {
  const rolledBack = await rollbackEmployeePackageImportBestEffort(transaction);
  showToast(
    rolledBack
      ? message
      : `${message} Nie udało się potwierdzić cofnięcia plików; transakcja pozostaje oczekująca.`,
    rolledBack ? "warning" : "error",
  );
  return { status: rolledBack ? "rolled-back" : "rollback-pending" };
}

async function persistAndFinalizeAppliedEmployeePackage(member, appliedTransaction, {
  recovery = false,
} = {}) {
  let rollbackSnapshot = captureEmployeePackageRollbackSnapshot();
  let mergePlan = planEmployeePoliciesMerge(member, appliedTransaction.policies);
  if (mergePlan.report.conflictCount > 0) {
    return rollbackConflictingEmployeePackage(
      appliedTransaction,
      "W najświeższej bazie wykryto konflikt polisy, TU, duplikatu lub kosza. Niczego nie zapisano.",
    );
  }

  policies = mergePlan.policies;
  addEmployeePackageImportReceipt(appliedTransaction);
  await persistPolicies({
    employeePackageImportLockHeld: true,
    reapplyAfterConflict: () => {
      
      rollbackSnapshot = captureEmployeePackageRollbackSnapshot();
      mergePlan = planEmployeePoliciesMerge(member, appliedTransaction.policies);
      if (mergePlan.report.conflictCount > 0) return false;
      policies = mergePlan.policies;
      addEmployeePackageImportReceipt(appliedTransaction);
      return true;
    },
  });

  
  
  const readback = await inspectEmployeePackageDataFile(appliedTransaction);
  if (readback.status !== "verified" || readback.receiptStatus === "mismatch") {
    restoreEmployeePackageRollbackSnapshot(rollbackSnapshot);
    render();
    showToast(
      recovery
        ? "Nie można potwierdzić właściwej bazy po wznowieniu. Paczka pozostaje oczekująca."
        : "Nie udało się jednoznacznie odczytać zapisanej bazy. Pliki pozostają oczekujące i nie zostały usunięte.",
      "warning",
    );
    return { status: "readback-uncertain", report: mergePlan.report };
  }
  if (readback.receiptStatus !== "exact") {
    restoreEmployeePackageRollbackSnapshot(rollbackSnapshot);
    render();
    const rollbackResult = await rollbackConflictingEmployeePackage(
      appliedTransaction,
      "Odczytana baza nie zawiera potwierdzenia importu. Zmiany w pamięci cofnięto.",
    );
    return { ...rollbackResult, report: mergePlan.report };
  }
  if (!(await loadVerifiedEmployeePackageDataFile(readback))) {
    showToast(
      "Receipt zapisano, ale nie udało się ponownie wczytać właściwej bazy. Paczka pozostaje oczekująca.",
      "warning",
    );
    return { status: "readback-load-pending", report: mergePlan.report };
  }

  render();
  const reportParts = getEmployeePackageReportParts(mergePlan.report, appliedTransaction);
  if (getEmployeePackageChangesCount(mergePlan.report) === 0) {
    reportParts.unshift("baza bez zmian");
  }
  try {
    await confirmEmployeePackageImport(appliedTransaction);
    showToast(
      recovery
        ? "Oczekujący import paczki został zapisany, odczytany i potwierdzony."
        : `Baza „${member.label}”: ${reportParts.join(", ")}`,
      "success",
    );
    return { status: "confirmed", report: mergePlan.report };
  } catch {
    
    showToast(
      recovery
        ? "Baza zawiera potwierdzenie importu, ale serwerowe confirm pozostaje do ponownej próby."
        : `Baza „${member.label}” została zapisana, ale serwerowe potwierdzenie paczki pozostaje oczekujące.`,
      "warning",
    );
    return { status: "confirm-pending", report: mergePlan.report };
  }
}

async function applyStagedEmployeePackage(member, stagedTransaction, {
  recovery = false,
} = {}) {
  const dryMergePlan = planEmployeePoliciesMerge(member, stagedTransaction.policies);
  if (dryMergePlan.report.conflictCount > 0) {
    return rollbackConflictingEmployeePackage(
      stagedTransaction,
      "Paczka zawiera konflikt polisy, TU, duplikatu lub kosza. Nie zastosowano plików ani zmian bazy.",
    );
  }

  
  
  const baseBeforeApply = await inspectEmployeePackageDataFile(stagedTransaction);
  if (
    baseBeforeApply.status !== "verified"
    || baseBeforeApply.baseDigest !== stagedTransaction.baseDigest
    || !(await loadVerifiedEmployeePackageDataFile(baseBeforeApply))
  ) {
    return rollbackConflictingEmployeePackage(
      stagedTransaction,
      "Baza zmieniła się po przygotowaniu paczki. Stage cofnięto; uruchom import ponownie na aktualnej bazie.",
    );
  }
  const repeatedDryMergePlan = planEmployeePoliciesMerge(member, stagedTransaction.policies);
  if (repeatedDryMergePlan.report.conflictCount > 0) {
    return rollbackConflictingEmployeePackage(
      stagedTransaction,
      "Po odczycie aktualnej bazy wykryto konflikt. Stage cofnięto bez kopiowania plików.",
    );
  }

  let appliedTransaction;
  try {
    appliedTransaction = await applyEmployeePackageImport(stagedTransaction);
  } catch {
    return rollbackConflictingEmployeePackage(
      stagedTransaction,
      "Nie udało się zastosować przygotowanej paczki. Baza pozostała bez zmian.",
    );
  }

  if (!dataFileHandle) {
    return rollbackConflictingEmployeePackage(
      appliedTransaction,
      "Utracono stałe połączenie z plikiem bazy przed zapisem. Baza pozostała bez zmian.",
    );
  }
  const latestDatabase = await inspectEmployeePackageDataFile(appliedTransaction);
  if (
    latestDatabase.status !== "verified"
    || !(await loadVerifiedEmployeePackageDataFile(latestDatabase))
  ) {
    return rollbackConflictingEmployeePackage(
      appliedTransaction,
      "Nie udało się zweryfikować najświeższej bazy. Niczego nie zapisano.",
    );
  }
  return persistAndFinalizeAppliedEmployeePackage(member, appliedTransaction, { recovery });
}

async function resumeFilesAppliedEmployeePackage(member, appliedTransaction, {
  recovery = false,
} = {}) {
  const verifiedDatabase = await inspectEmployeePackageDataFile(appliedTransaction);
  if (
    verifiedDatabase.status !== "verified"
    || verifiedDatabase.receiptStatus === "mismatch"
  ) {
    showToast(
      "Nie można jednoznacznie powiązać oczekującej paczki z właściwą bazą. Import pozostaje wstrzymany.",
      "warning",
    );
    return { status: "readback-uncertain" };
  }
  if (verifiedDatabase.receiptStatus === "exact") {
    if (!(await loadVerifiedEmployeePackageDataFile(verifiedDatabase))) {
      showToast("Nie udało się wczytać bazy z zapisanym receipt. Import pozostaje oczekujący.", "warning");
      return { status: "readback-load-pending" };
    }
    try {
      await confirmEmployeePackageImport(appliedTransaction);
      return { status: "confirmed" };
    } catch {
      showToast("Receipt jest zapisany, ale serwerowe confirm pozostaje oczekujące.", "warning");
      return { status: "confirm-pending" };
    }
  }
  if (verifiedDatabase.baseDigest !== appliedTransaction.baseDigest) {
    showToast(
      "Baza ma inną rewizję niż oczekująca paczka bez receipt. Nie wykonano merge ani rollbacku.",
      "warning",
    );
    return { status: "base-mismatch-pending" };
  }
  if (!(await loadVerifiedEmployeePackageDataFile(verifiedDatabase))) {
    showToast("Nie udało się wczytać zweryfikowanej bazy. Import pozostaje oczekujący.", "warning");
    return { status: "readback-load-pending" };
  }
  return persistAndFinalizeAppliedEmployeePackage(member, appliedTransaction, { recovery });
}

async function importEmployeeDatabaseFromFileInternal(member, file) {
  try {
    const isZipPackage = /\.zip$/i.test(String(file.name || ""));
    if (!(await ensureWritableDataFile({
      deferFreshnessCheck: !isZipPackage,
      employeePackageImportLockHeld: true,
    }))) {
      showToast("Najpierw połącz aplikację z Twoim plikiem bazy", "error");
      return;
    }
    if (isZipPackage && !dataFileHandle) {
      showToast(
        "Import ZIP wymaga stałego połączenia z plikiem bazy, aby po zapisie wykonać bezpieczny odczyt kontrolny.",
        "error",
      );
      return;
    }
    showToast(`Wczytywanie bazy pracownika „${member.label}”…`);
    let employeeData;
    if (isZipPackage) {
      
      if (!(await recoverPendingEmployeePackageImportsInternal())) {
        showToast(
          "Najpierw dokończ lub wyjaśnij oczekujący import paczki. Nowego ZIP-a nie wysłano.",
          "warning",
        );
        return;
      }
      if (!dataFileHandle) {
        showToast("Połączenie z plikiem bazy nie jest już pewne. Nowego ZIP-a nie wysłano.", "error");
        return;
      }
      if (hasUnsavedPolicyChanges) {
        showToast(
          "Przed importem ZIP zapisz bieżące zmiany w bazie. Paczki jeszcze nie wysłano.",
          "warning",
        );
        return;
      }
      const verifiedDatabase = await inspectEmployeePackageDataFile();
      if (
        verifiedDatabase.status !== "verified"
        || !(await loadVerifiedEmployeePackageDataFile(verifiedDatabase))
      ) {
        showToast(
          "Nie udało się zweryfikować właściwego pliku bazy przed uploadem. Paczki nie wysłano.",
          "error",
        );
        return;
      }
      const baseDigest = verifiedDatabase.baseDigest;
      employeeData = await readEmployeeDatabaseFromZip(member, file, baseDigest);
    } else {
      const plainJsonContents = await readPoliciesFileText(file);
      const rawPlainDocument = JSON.parse(plainJsonContents);
      const rawPlainPolicies = Array.isArray(rawPlainDocument)
        ? rawPlainDocument
        : rawPlainDocument?.policies;
      if (
        Array.isArray(rawPlainPolicies)
        && rawPlainPolicies.some((policy) => (
          Array.isArray(policy?.attachments)
          && policy.attachments.some((attachment) => attachment?.storage === "file")
        ))
      ) {
        throw new Error(
          "Plik JSON zawiera odwołania do załączników bez samych plików. "
          + "Poproś pracownika o paczkę ZIP z opcji „Paczka dla centrali”.",
        );
      }
      const parsedDocument = parsePoliciesFileDocument(plainJsonContents);
      employeeData = {
        accountId: parsedDocument.accountId,
        policies: parsedDocument.accountId
          ? parsedDocument.policies
          : normalizeLoadedPolicies(parsedDocument.policies, member.id),
        attachmentsCopied: 0,
        attachmentsReused: 0,
        attachmentsRenamed: 0,
      };
    }
    if (!employeeData.accountId) {
      throw new Error(
        "Ten plik nie ma przypisanego konta (pochodzi ze starszej wersji aplikacji). "
        + "Poproś pracownika o aktualną kopię: Ustawienia → Agencja → „Paczka dla centrali”.",
      );
    }
    if (employeeData.accountId !== member.id) {
      if (isZipPackage) {
        const rolledBack = await rollbackEmployeePackageImportBestEffort(employeeData);
        if (!rolledBack) {
          showToast(
            "Paczka należy do innego konta i nie została scalona. Nie udało się potwierdzić cofnięcia plików.",
            "error",
          );
          return;
        }
      }
      const actualMember = getAgencyMemberById(employeeData.accountId);
      throw new Error(actualMember
        ? `Wskazany plik to baza pracownika „${actualMember.label}”. Kliknij „Importuj bazę” przy tym pracowniku.`
        : `Ta baza należy do konta ${employeeData.accountId}, którego nie ma w Twojej agencji. Najpierw dodaj ten identyfikator na liście pracowników.`);
    }
    if (isZipPackage) {
      if (employeeData.state === "staged") {
        await applyStagedEmployeePackage(member, employeeData);
      } else {
        await resumeFilesAppliedEmployeePackage(member, employeeData);
      }
      return;
    }

    
    
    let rollbackSnapshot = captureEmployeePackageRollbackSnapshot();
    let mergePlan = planEmployeePoliciesMerge(member, employeeData.policies);
    let report = mergePlan.report;
    if (report.conflictCount > 0) {
      showToast(
        `Nie zmieniono bazy „${member.label}”: wykryto ${report.conflictCount} konfliktów. Cały import JSON zatrzymano.`,
        "warning",
      );
      render();
      return;
    }
    const changesCount = getEmployeePackageChangesCount(report);
    if (changesCount === 0) {
      showToast(
        `Baza pracownika „${member.label}” była już wczytana - bez zmian`,
        "success",
      );
      render();
      return;
    }
    policies = mergePlan.policies;
    const saved = await persistPolicies({
      employeePackageImportLockHeld: true,
      reapplyAfterConflict: () => {
        rollbackSnapshot = captureEmployeePackageRollbackSnapshot();
        mergePlan = planEmployeePoliciesMerge(member, employeeData.policies);
        report = mergePlan.report;
        if (report.conflictCount > 0) return false;
        policies = mergePlan.policies;
        return true;
      },
    });
    if (!saved) {
      restoreEmployeePackageRollbackSnapshot(rollbackSnapshot);
    }
    render();
    const reportParts = getEmployeePackageReportParts(report, employeeData);
    if (report.conflictCount > 0) reportParts.push(`${report.conflictCount} konfliktów wymaga sprawdzenia`);
    if (reportParts.length === 0) reportParts.push("bez zmian po wczytaniu nowszej bazy");
    showToast(
      `Baza „${member.label}”: ${reportParts.join(", ")}${saved ? "" : " (zapisz bazę, aby utrwalić zmiany)"}`,
      saved && report.conflictCount === 0 ? "success" : "warning",
    );
  } catch (error) {
    showToast(error?.message || "Nie udało się zaimportować bazy pracownika", "error");
  }
}

function importEmployeeDatabaseFromFile(member, file) {
  return runEmployeePackageImportExclusive(
    async () => {
      showAppBusyOverlay("Bezpieczny import paczki pracownika…");
      try {
        return await importEmployeeDatabaseFromFileInternal(member, file);
      } finally {
        hideAppBusyOverlay();
      }
    },
  );
}

async function recoverPendingEmployeePackageImportsInternal() {
  if (isEmployeeAccount()) return true;
  let transactions;
  try {
    const response = await apiFetch("/api/konto/import-paczki/pending", { cache: "no-store" });
    const data = await response.json().catch(() => null);
    if (!response.ok || !Array.isArray(data?.transactions)) {
      throw new Error("pending-imports-invalid");
    }
    if (data.transactions.length > 1) throw new Error("too-many-pending-imports");
    transactions = data.transactions;
  } catch {
    showToast(
      "Nie udało się sprawdzić oczekujących importów paczek. Spróbujemy ponownie przy następnym uruchomieniu.",
      "warning",
    );
    return false;
  }

  let allTransactionsResolved = true;
  for (const rawTransaction of transactions) {
    let employeeData;
    try {
      employeeData = normalizeEmployeePackageTransaction(rawTransaction, {
        allowedStates: ["staged", "files_applied", "rollback_blocked"],
      });
    } catch {
      showToast(
        "Jedna z oczekujących paczek ma nieprawidłowy stan i wymaga ponownej próby. Nie zmieniono bazy ani plików.",
        "warning",
      );
      allTransactionsResolved = false;
      continue;
    }
    const member = getAgencyMemberById(employeeData.accountId);
    if (
      !member
      || employeeData.centralAccountId !== currentAccount?.id
    ) {
      
      
      showToast(
        "Oczekująca paczka należy do konta spoza listy pracowników. Nie zmieniono bazy ani plików.",
        "warning",
      );
      allTransactionsResolved = false;
      continue;
    }

    const verifiedDatabase = await inspectEmployeePackageDataFile(employeeData);
    if (verifiedDatabase.status !== "verified") {
      showToast(
        "Nie można potwierdzić właściwego pliku bazy dla oczekującej paczki. Nie zmieniono bazy ani plików.",
        "warning",
      );
      allTransactionsResolved = false;
      continue;
    }
    if (verifiedDatabase.receiptStatus === "mismatch") {
      showToast(
        "Receipt oczekującej paczki nie zgadza się z transakcją. Import pozostaje wstrzymany.",
        "warning",
      );
      allTransactionsResolved = false;
      continue;
    }
    if (verifiedDatabase.receiptStatus === "exact") {
      if (
        employeeData.state !== "files_applied"
        || !(await loadVerifiedEmployeePackageDataFile(verifiedDatabase))
      ) {
        showToast(
          "Baza zawiera receipt, ale stan serwerowej transakcji wymaga ręcznego sprawdzenia.",
          "warning",
        );
        allTransactionsResolved = false;
        continue;
      }
      try {
        await confirmEmployeePackageImport(employeeData);
        showToast("Oczekujący import z zapisanym receipt został bezpiecznie potwierdzony.", "success");
      } catch {
        showToast("Receipt jest zapisany, ale serwerowe confirm pozostaje do ponownej próby.", "warning");
        allTransactionsResolved = false;
      }
      continue;
    }
    if (
      employeeData.state === "rollback_blocked"
      || verifiedDatabase.baseDigest !== employeeData.baseDigest
    ) {
      showToast(
        "Oczekująca paczka nie pasuje do bieżącej rewizji bazy. Nie wykonano automatycznego merge ani usunięcia plików.",
        "warning",
      );
      allTransactionsResolved = false;
      continue;
    }
    if (!(await loadVerifiedEmployeePackageDataFile(verifiedDatabase))) {
      showToast(
        "Nie udało się wczytać zweryfikowanej bazy dla oczekującej paczki. Import pozostaje wstrzymany.",
        "warning",
      );
      allTransactionsResolved = false;
      continue;
    }

    const result = employeeData.state === "staged"
      ? await applyStagedEmployeePackage(member, employeeData, { recovery: true })
      : await persistAndFinalizeAppliedEmployeePackage(member, employeeData, { recovery: true });
    if (result.status !== "confirmed" && result.status !== "rolled-back") {
      allTransactionsResolved = false;
    }
  }
  return allTransactionsResolved;
}

function recoverPendingEmployeePackageImports() {
  return runEmployeePackageImportExclusive(recoverPendingEmployeePackageImportsInternal);
}





function normalizeCentralAssignmentTransaction(transaction, {
  allowedStates = ["staged", "files_applied", "rollback_blocked"],
} = {}) {
  const transactionId = normalizeEmployeePackageTransactionId(transaction?.transactionId);
  const sourceAccountId = normalizePolicyOwnerId(transaction?.sourceAccountId);
  const targetAccountId = normalizePolicyOwnerId(transaction?.targetAccountId);
  const baseDigest = normalizeEmployeePackageDigest(transaction?.baseDigest);
  const packageDigest = normalizeEmployeePackageDigest(transaction?.packageDigest);
  const planDigest = normalizeEmployeePackageDigest(transaction?.planDigest);
  const state = String(transaction?.state || "");
  const kind = String(transaction?.kind || "");
  const rawPolicies = transaction?.policies;
  if (
    !transactionId
    || !allowedStates.includes(state)
    || !sourceAccountId
    || !targetAccountId
    || !baseDigest
    || !packageDigest
    || !planDigest
    || kind !== CENTRAL_TO_EMPLOYEE_PACKAGE_KIND
    || !Array.isArray(rawPolicies)
    || (state === "files_applied" && transaction?.requiresConfirmation !== true)
    || rawPolicies.some((policy) => (
      !policy
      || typeof policy !== "object"
      || !String(policy.id || "").trim()
      || !normalizePolicyOwnerId(policy.ownerId)
    ))
  ) {
    throw new Error("Serwer zwrócił nieprawidłowy stan paczki od centrali.");
  }
  const normalizedTransaction = {
    transactionId,
    kind,
    state,
    requiresConfirmation: state === "files_applied",
    sourceAccountId,
    targetAccountId,
    baseDigest,
    packageDigest,
    planDigest,
    policies: normalizeLoadedPolicies(rawPolicies, ""),
  };
  if (state === "staged") {
    normalizedTransaction.attachmentsToCreate = normalizeEmployeePackagePlanCounter(
      transaction.attachmentsToCreate,
    );
    normalizedTransaction.attachmentsToReuse = normalizeEmployeePackagePlanCounter(
      transaction.attachmentsToReuse,
    );
    normalizedTransaction.attachmentsToRename = normalizeEmployeePackagePlanCounter(
      transaction.attachmentsToRename,
    );
  } else {
    normalizedTransaction.attachmentsCopied = normalizeEmployeePackageCounter(
      transaction.attachmentsCopied,
    );
    normalizedTransaction.attachmentsReused = normalizeEmployeePackageCounter(
      transaction.attachmentsReused,
    );
    normalizedTransaction.attachmentsRenamed = normalizeEmployeePackageCounter(
      transaction.attachmentsRenamed,
    );
  }
  return normalizedTransaction;
}

function assertCentralAssignmentBinding(transaction) {
  if (
    !isEmployeeAccount()
    || currentAccount?.pairingReady !== true
    || !normalizePolicyOwnerId(currentAccount?.centralAccountId)
    || transaction?.targetAccountId !== currentAccount.id
    || transaction?.sourceAccountId !== currentAccount.centralAccountId
  ) {
    throw new Error("Paczka nie jest przypisana do tej instalacji pracownika i jej centrali.");
  }
  return true;
}

function getCentralAssignmentActionUrl(transactionId, action) {
  const normalizedTransactionId = normalizeEmployeePackageTransactionId(transactionId);
  if (
    !normalizedTransactionId
    || (action !== "apply" && action !== "confirm" && action !== "rollback")
  ) {
    throw new Error("Nieprawidłowy identyfikator przydziału polis.");
  }
  return `/api/konto/import-przydzialu/${encodeURIComponent(normalizedTransactionId)}/${action}`;
}

function getCentralAssignmentProofBody(transaction) {
  const baseDigest = normalizeEmployeePackageDigest(transaction?.baseDigest);
  const packageDigest = normalizeEmployeePackageDigest(transaction?.packageDigest);
  const planDigest = normalizeEmployeePackageDigest(transaction?.planDigest);
  if (!baseDigest || !packageDigest || !planDigest) {
    throw new Error("Nieprawidłowy dowód transakcji paczki od centrali.");
  }
  return JSON.stringify({ baseDigest, packageDigest, planDigest });
}

async function postCentralAssignmentAction(transaction, action) {
  const response = await apiFetch(
    getCentralAssignmentActionUrl(transaction?.transactionId, action),
    {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: getCentralAssignmentProofBody(transaction),
    },
  );
  const data = await response.json().catch(() => null);
  if (!response.ok || data?.ok !== true) {
    throw new Error("Nie udało się bezpiecznie zakończyć operacji na paczce od centrali.");
  }
  return true;
}

function confirmCentralAssignment(transaction) {
  return postCentralAssignmentAction(transaction, "confirm");
}

function rollbackCentralAssignment(transaction) {
  return postCentralAssignmentAction(transaction, "rollback");
}

async function rollbackCentralAssignmentBestEffort(transaction) {
  try {
    await rollbackCentralAssignment(transaction);
    return true;
  } catch {
    return false;
  }
}

function planCentralAssignmentPoliciesMerge(incomingPolicies, options = {}) {
  return planEmployeePoliciesMerge(
    { id: "" },
    incomingPolicies,
    { ...options, requireExactOwner: true },
  );
}

async function readCentralAssignmentFromZip(file, baseDigest) {
  const response = await apiFetch(
    `/api/konto/import-przydzialu?bazaRewizja=${encodeURIComponent(baseDigest)}`,
    {
      method: "POST",
      headers: { "Content-Type": "application/zip" },
      body: file,
    },
  );
  const data = await response.json().catch(() => ({}));
  if (!response.ok) {
    if (response.status === 403 && data?.code === "PACKAGE_PAIRING_REQUIRED") {
      throw new Error(
        "Ta instalacja nie jest sparowana z centralą. Wklej kod parowania otrzymany od właściciela agencji.",
      );
    }
    throw new Error(data?.error || "Nie udało się bezpiecznie odczytać paczki od centrali.");
  }
  const transaction = normalizeCentralAssignmentTransaction(data, {
    allowedStates: ["staged", "files_applied"],
  });
  assertCentralAssignmentBinding(transaction);
  if (transaction.baseDigest !== baseDigest) {
    throw new Error("Serwer przygotował paczkę dla innej rewizji bazy.");
  }
  return transaction;
}

async function applyCentralAssignment(stagedTransaction) {
  const response = await apiFetch(
    getCentralAssignmentActionUrl(stagedTransaction.transactionId, "apply"),
    {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: getCentralAssignmentProofBody(stagedTransaction),
    },
  );
  const data = await response.json().catch(() => null);
  if (!response.ok) throw new Error("Nie udało się zastosować plików paczki od centrali.");
  const appliedTransaction = normalizeCentralAssignmentTransaction(data, {
    allowedStates: ["files_applied"],
  });
  assertCentralAssignmentBinding(appliedTransaction);
  if (
    appliedTransaction.transactionId !== stagedTransaction.transactionId
    || appliedTransaction.sourceAccountId !== stagedTransaction.sourceAccountId
    || appliedTransaction.targetAccountId !== stagedTransaction.targetAccountId
    || appliedTransaction.baseDigest !== stagedTransaction.baseDigest
    || appliedTransaction.packageDigest !== stagedTransaction.packageDigest
    || appliedTransaction.planDigest !== stagedTransaction.planDigest
  ) {
    throw new Error("Serwer zwrócił niespójny stan zastosowanej paczki od centrali.");
  }
  return appliedTransaction;
}

async function rollbackConflictingCentralAssignment(transaction, message) {
  const rolledBack = await rollbackCentralAssignmentBestEffort(transaction);
  showToast(
    rolledBack
      ? message
      : `${message} Cofnięcie plików wymaga ponownej próby; transakcja pozostaje oczekująca.`,
    rolledBack ? "warning" : "error",
  );
  return { status: rolledBack ? "rolled-back" : "rollback-pending" };
}

async function persistAndFinalizeCentralAssignment(appliedTransaction, { recovery = false } = {}) {
  let rollbackSnapshot = captureEmployeePackageRollbackSnapshot();
  let mergePlan = planCentralAssignmentPoliciesMerge(appliedTransaction.policies);
  if (mergePlan.report.conflictCount > 0) {
    return rollbackConflictingCentralAssignment(
      appliedTransaction,
      "W najświeższej bazie wykryto konflikt właściciela, polisy, TU, duplikatu, załącznika lub kosza. Niczego nie zapisano.",
    );
  }
  policies = mergePlan.policies;
  addEmployeePackageImportReceipt(appliedTransaction);
  await persistPolicies({
    employeePackageImportLockHeld: true,
    reapplyAfterConflict: () => {
      rollbackSnapshot = captureEmployeePackageRollbackSnapshot();
      mergePlan = planCentralAssignmentPoliciesMerge(appliedTransaction.policies);
      if (mergePlan.report.conflictCount > 0) return false;
      policies = mergePlan.policies;
      addEmployeePackageImportReceipt(appliedTransaction);
      return true;
    },
  });

  const readback = await inspectEmployeePackageDataFile(appliedTransaction);
  if (readback.status !== "verified" || readback.receiptStatus === "mismatch") {
    restoreEmployeePackageRollbackSnapshot(rollbackSnapshot);
    render();
    showToast(
      "Nie można jednoznacznie odczytać zapisanej bazy. Paczka od centrali pozostaje oczekująca.",
      "warning",
    );
    return { status: "readback-uncertain", report: mergePlan.report };
  }
  if (readback.receiptStatus !== "exact") {
    restoreEmployeePackageRollbackSnapshot(rollbackSnapshot);
    render();
    return rollbackConflictingCentralAssignment(
      appliedTransaction,
      "Odczytana baza nie zawiera trwałego potwierdzenia importu. Zmiany w pamięci cofnięto.",
    );
  }
  if (!(await loadVerifiedEmployeePackageDataFile(readback))) {
    showToast(
      "Potwierdzenie zapisano, ale ponowne wczytanie bazy nie powiodło się. Paczka pozostaje oczekująca.",
      "warning",
    );
    return { status: "readback-load-pending", report: mergePlan.report };
  }

  render();
  const reportParts = getEmployeePackageReportParts(mergePlan.report, appliedTransaction);
  if (getEmployeePackageChangesCount(mergePlan.report) === 0) reportParts.unshift("baza bez zmian");
  try {
    await confirmCentralAssignment(appliedTransaction);
    setAgencyStatus(
      elements.agencyAssignmentImportStatus,
      recovery
        ? "Oczekująca paczka od centrali została bezpiecznie dokończona."
        : `Gotowe: ${reportParts.join(", ")}.`,
    );
    showToast("Polisy od centrali zostały bezpiecznie zapisane.", "success");
    return { status: "confirmed", report: mergePlan.report };
  } catch {
    showToast(
      "Baza i potwierdzenie są zapisane; serwer dokończy confirm przy następnym uruchomieniu.",
      "warning",
    );
    return { status: "confirm-pending", report: mergePlan.report };
  }
}

async function applyStagedCentralAssignment(stagedTransaction, { recovery = false } = {}) {
  const dryMergePlan = planCentralAssignmentPoliciesMerge(stagedTransaction.policies);
  if (dryMergePlan.report.conflictCount > 0) {
    return rollbackConflictingCentralAssignment(
      stagedTransaction,
      "Paczka od centrali zawiera konflikt. Nie zastosowano plików ani zmian bazy.",
    );
  }
  const baseBeforeApply = await inspectEmployeePackageDataFile(stagedTransaction);
  if (
    baseBeforeApply.status !== "verified"
    || baseBeforeApply.baseDigest !== stagedTransaction.baseDigest
    || !(await loadVerifiedEmployeePackageDataFile(baseBeforeApply))
  ) {
    return rollbackConflictingCentralAssignment(
      stagedTransaction,
      "Baza zmieniła się po przygotowaniu paczki. Stage cofnięto; uruchom import ponownie.",
    );
  }
  const repeatedPlan = planCentralAssignmentPoliciesMerge(stagedTransaction.policies);
  if (repeatedPlan.report.conflictCount > 0) {
    return rollbackConflictingCentralAssignment(
      stagedTransaction,
      "Po odczycie aktualnej bazy wykryto konflikt. Stage cofnięto bez kopiowania plików.",
    );
  }
  let appliedTransaction;
  try {
    appliedTransaction = await applyCentralAssignment(stagedTransaction);
  } catch {
    return rollbackConflictingCentralAssignment(
      stagedTransaction,
      "Nie udało się zastosować przygotowanej paczki. Baza pozostała bez zmian.",
    );
  }
  const latestDatabase = await inspectEmployeePackageDataFile(appliedTransaction);
  if (
    latestDatabase.status !== "verified"
    || !(await loadVerifiedEmployeePackageDataFile(latestDatabase))
  ) {
    return rollbackConflictingCentralAssignment(
      appliedTransaction,
      "Nie udało się zweryfikować najświeższej bazy. Niczego nie zapisano.",
    );
  }
  return persistAndFinalizeCentralAssignment(appliedTransaction, { recovery });
}

async function resumeFilesAppliedCentralAssignment(appliedTransaction, { recovery = false } = {}) {
  const verifiedDatabase = await inspectEmployeePackageDataFile(appliedTransaction);
  if (verifiedDatabase.status !== "verified" || verifiedDatabase.receiptStatus === "mismatch") {
    showToast("Nie można jednoznacznie powiązać oczekującej paczki z bazą.", "warning");
    return { status: "readback-uncertain" };
  }
  if (verifiedDatabase.receiptStatus === "exact") {
    if (!(await loadVerifiedEmployeePackageDataFile(verifiedDatabase))) {
      return { status: "readback-load-pending" };
    }
    try {
      await confirmCentralAssignment(appliedTransaction);
      return { status: "confirmed" };
    } catch {
      return { status: "confirm-pending" };
    }
  }
  if (verifiedDatabase.baseDigest !== appliedTransaction.baseDigest) {
    showToast("Oczekująca paczka nie pasuje do bieżącej rewizji bazy.", "warning");
    return { status: "base-mismatch-pending" };
  }
  if (!(await loadVerifiedEmployeePackageDataFile(verifiedDatabase))) {
    return { status: "readback-load-pending" };
  }
  return persistAndFinalizeCentralAssignment(appliedTransaction, { recovery });
}

async function recoverPendingCentralAssignmentsInternal() {
  if (!isEmployeeAccount()) return true;
  
  
  if (currentAccount?.pairingReady !== true) return true;
  let transactions;
  try {
    const response = await apiFetch("/api/konto/import-przydzialu/pending", { cache: "no-store" });
    const data = await response.json().catch(() => null);
    if (!response.ok || !Array.isArray(data?.transactions) || data.transactions.length > 1) {
      throw new Error("pending-assignments-invalid");
    }
    transactions = data.transactions;
  } catch {
    showToast("Nie udało się sprawdzić oczekujących paczek od centrali.", "warning");
    return false;
  }
  let allResolved = true;
  for (const rawTransaction of transactions) {
    let transaction;
    try {
      transaction = normalizeCentralAssignmentTransaction(rawTransaction);
      assertCentralAssignmentBinding(transaction);
    } catch {
      showToast("Oczekująca paczka nie jest przypisana do tej instalacji.", "warning");
      allResolved = false;
      continue;
    }
    const verifiedDatabase = await inspectEmployeePackageDataFile(transaction);
    if (verifiedDatabase.status !== "verified" || verifiedDatabase.receiptStatus === "mismatch") {
      showToast("Nie można potwierdzić bazy dla oczekującej paczki od centrali.", "warning");
      allResolved = false;
      continue;
    }
    if (verifiedDatabase.receiptStatus === "exact") {
      if (
        transaction.state !== "files_applied"
        || !(await loadVerifiedEmployeePackageDataFile(verifiedDatabase))
      ) {
        allResolved = false;
        continue;
      }
      try {
        await confirmCentralAssignment(transaction);
      } catch {
        allResolved = false;
      }
      continue;
    }
    if (
      transaction.state === "rollback_blocked"
      || verifiedDatabase.baseDigest !== transaction.baseDigest
      || !(await loadVerifiedEmployeePackageDataFile(verifiedDatabase))
    ) {
      allResolved = false;
      continue;
    }
    const result = transaction.state === "staged"
      ? await applyStagedCentralAssignment(transaction, { recovery: true })
      : await persistAndFinalizeCentralAssignment(transaction, { recovery: true });
    if (result.status !== "confirmed" && result.status !== "rolled-back") allResolved = false;
  }
  return allResolved;
}

function recoverPendingCentralAssignments() {
  return runEmployeePackageImportExclusive(recoverPendingCentralAssignmentsInternal);
}

async function importCentralAssignmentFromFileInternal(file) {
  try {
    if (!isEmployeeAccount() || currentAccount?.pairingReady !== true) {
      throw new Error("Najpierw sparuj tę instalację z centralą.");
    }
    if (!(await ensureWritableDataFile({ employeePackageImportLockHeld: true }))) {
      throw new Error("Najpierw połącz aplikację z Twoim plikiem bazy.");
    }
    if (!dataFileHandle) {
      throw new Error("Import ZIP wymaga stałego połączenia z plikiem bazy.");
    }
    if (!(await recoverPendingCentralAssignmentsInternal())) {
      throw new Error("Najpierw trzeba dokończyć oczekujący import paczki od centrali.");
    }
    if (hasUnsavedPolicyChanges) {
      throw new Error("Przed importem zapisz bieżące zmiany w bazie.");
    }
    const verifiedDatabase = await inspectEmployeePackageDataFile();
    if (
      verifiedDatabase.status !== "verified"
      || !(await loadVerifiedEmployeePackageDataFile(verifiedDatabase))
    ) {
      throw new Error("Nie udało się zweryfikować właściwego pliku bazy przed wysłaniem paczki.");
    }
    const transaction = await readCentralAssignmentFromZip(file, verifiedDatabase.baseDigest);
    const result = transaction.state === "staged"
      ? await applyStagedCentralAssignment(transaction)
      : await resumeFilesAppliedCentralAssignment(transaction);
    return result;
  } catch (error) {
    setAgencyStatus(
      elements.agencyAssignmentImportStatus,
      error?.message || "Nie udało się zaimportować paczki od centrali.",
      "error",
    );
    showToast(error?.message || "Nie udało się zaimportować paczki od centrali.", "error");
    return { status: "failed" };
  }
}

function importCentralAssignmentFromFile(file) {
  return runEmployeePackageImportExclusive(async () => {
    showAppBusyOverlay("Bezpieczny import polis od centrali…");
    try {
      return await importCentralAssignmentFromFileInternal(file);
    } finally {
      hideAppBusyOverlay();
    }
  });
}

function getPendingAgencyServedInsurers() {
  return [...(elements.agencyInsurersList?.querySelectorAll("[data-agency-insurer]:checked") || [])]
    .map((checkbox) => normalizeInsurerId(checkbox.value))
    .filter(Boolean);
}

async function persistAgencyInsurerSelection({ showSuccess = true } = {}) {
  if (isEmployeeAccount()) return true;
  const servedInsurers = getPendingAgencyServedInsurers();
  if (servedInsurers.length === 0) {
    setAgencyStatus(elements.agencyInsurersStatus, "Zaznacz co najmniej jedno obsługiwane towarzystwo.", "error");
    return false;
  }
  const currentSelection = Array.isArray(currentAccount?.servedInsurers)
    ? currentAccount.servedInsurers.map(normalizeInsurerId).filter(Boolean)
    : [];
  const selectionUnchanged = currentSelection.length === servedInsurers.length
    && currentSelection.every((insurerId) => servedInsurers.includes(insurerId));
  if (selectionUnchanged) {
    if (showSuccess) setAgencyStatus(elements.agencyInsurersStatus, "Zakres obsługiwanych towarzystw jest aktualny.");
    return true;
  }
  try {
    applyAccountSnapshot(await postAccountJson("/api/konto/towarzystwa", { servedInsurers }));
    if (showSuccess) {
      setAgencyStatus(elements.agencyInsurersStatus, "Zakres obsługiwanych towarzystw został zapisany.");
    }
    render();
    return true;
  } catch (error) {
    setAgencyStatus(
      elements.agencyInsurersStatus,
      error?.message || "Nie udało się zapisać obsługiwanych towarzystw.",
      "error",
    );
    return false;
  }
}

function initializeAgencySettingsUi() {
  if (!elements.settingsAgencyPanel) return;

  elements.agencyInsurersSave?.addEventListener("click", async () => {
    elements.agencyInsurersSave.disabled = true;
    try {
      await persistAgencyInsurerSelection();
    } finally {
      elements.agencyInsurersSave.disabled = false;
    }
  });

  elements.agencyAccountId?.addEventListener("click", () => {
    void copyAgencyIdToClipboard(elements.agencyAccountId.textContent, "Skopiowano identyfikator konta");
  });

  elements.agencyAccountNameSave?.addEventListener("click", async () => {
    const name = elements.agencyAccountName?.value?.trim() || "";
    if (!name) {
      setAgencyStatus(elements.agencyAccountStatus, "Podaj nazwę konta.", "error");
      return;
    }
    try {
      applyAccountSnapshot(await postAccountJson("/api/konto/name", { name }));
      setAgencyStatus(elements.agencyAccountStatus, "Nazwa konta została zapisana.");
    } catch (error) {
      setAgencyStatus(elements.agencyAccountStatus, error?.message || "Nie udało się zapisać nazwy.", "error");
    }
  });

  elements.agencyPinChange?.addEventListener("click", async () => {
    const currentPin = elements.agencyPinCurrent?.value?.trim() || "";
    const newPin = elements.agencyPinNew?.value?.trim() || "";
    const repeatPin = elements.agencyPinRepeat?.value?.trim() || "";
    if (!/^\d{4,8}$/.test(newPin)) {
      setAgencyStatus(elements.agencyPinStatus, "Nowy PIN musi mieć od 4 do 8 cyfr.", "error");
      return;
    }
    if (newPin !== repeatPin) {
      setAgencyStatus(elements.agencyPinStatus, "Nowe PIN-y różnią się od siebie.", "error");
      return;
    }
    try {
      await postAccountJson("/api/konto/change-pin", { currentPin, newPin });
      elements.agencyPinCurrent.value = "";
      elements.agencyPinNew.value = "";
      elements.agencyPinRepeat.value = "";
      setAgencyStatus(elements.agencyPinStatus, "PIN został zmieniony.");
    } catch (error) {
      setAgencyStatus(elements.agencyPinStatus, error?.message || "Nie udało się zmienić PIN-u.", "error");
    }
  });

  elements.agencyAddMemberForm?.addEventListener("submit", async (event) => {
    event.preventDefault();
    const id = elements.agencyNewMemberId?.value || "";
    const label = elements.agencyNewMemberLabel?.value || "";
    elements.agencyMembersError.hidden = true;
    try {
      applyAccountSnapshot(await postAccountJson("/api/konto/pracownicy", { id, label }));
      elements.agencyNewMemberId.value = "";
      elements.agencyNewMemberLabel.value = "";
      showToast("Dodano pracownika");
    } catch (error) {
      elements.agencyMembersError.textContent = error?.message || "Nie udało się dodać pracownika.";
      elements.agencyMembersError.hidden = false;
    }
  });

  elements.agencyMembersList?.addEventListener("click", async (event) => {
    const card = event.target.closest("[data-member-id]");
    if (!card) return;
    const member = getAgencyMemberById(card.dataset.memberId);
    if (!member) return;
    if (event.target.closest("[data-member-copy]")) {
      void copyAgencyIdToClipboard(member.id, "Skopiowano identyfikator pracownika");
      return;
    }
    if (event.target.closest("[data-member-assign]")) {
      if (member.pairingReady !== true) {
        showToast(
          "Najpierw pokaż kod parowania i poproś pracownika o sparowanie starszej instalacji.",
          "warning",
        );
        return;
      }
      openAgencyAssignmentPanel(member);
      return;
    }
    if (event.target.closest("[data-member-pairing]")) {
      try {
        const data = await postAccountJson(
          `/api/konto/pracownicy/${encodeURIComponent(member.id)}/parowanie`,
          {},
        );
        const pairingCode = String(data?.pairingCode || "").trim();
        if (!/^SEK2\.[A-Z2-9]{12}\.[A-Z2-9]{12}\.[A-Za-z0-9_-]{43}$/.test(pairingCode)) {
          throw new Error("Serwer zwrócił nieprawidłowy kod parowania.");
        }
        const snapshotResponse = await apiFetch("/api/konto/snapshot", { cache: "no-store" });
        const snapshot = await snapshotResponse.json().catch(() => null);
        if (!snapshotResponse.ok || !snapshot?.account) {
          throw new Error("Kod utworzono, ale nie udało się odświeżyć stanu pracownika. Spróbuj ponownie.");
        }
        applyAccountSnapshot(snapshot);
        if (elements.agencyPairingCodeOutput) {
          elements.agencyPairingCodeOutput.textContent = pairingCode;
        }
        elements.agencyPairingCodeDialog?.showModal?.();
      } catch (error) {
        clearAgencyPairingCodeDialog();
        showToast(error?.message || "Nie udało się pobrać kodu parowania.", "error");
      }
      return;
    }
    if (event.target.closest("[data-member-import]")) {
      card.querySelector("[data-member-file]")?.click();
      return;
    }
    if (event.target.closest("[data-member-remove]")) {
      const confirmed = typeof globalThis.confirm !== "function" || globalThis.confirm(
        `Usunąć pracownika „${member.label}” z listy?\n\nJego polisy pozostaną w bazie z dotychczasowym oznaczeniem, ale nie wgrasz już jego bazy, dopóki nie dodasz identyfikatora ponownie.`,
      );
      if (!confirmed) return;
      try {
        const response = await apiFetch(`/api/konto/pracownicy/${encodeURIComponent(member.id)}`, {
          method: "DELETE",
          headers: { "Content-Type": "application/json" },
          body: "{}",
        });
        const data = await response.json().catch(() => ({}));
        if (!response.ok) throw new Error(data?.error || "Nie udało się usunąć pracownika.");
        applyAccountSnapshot(data);
        showToast("Usunięto pracownika");
      } catch (error) {
        showToast(error?.message || "Nie udało się usunąć pracownika", "error");
      }
    }
  });

  elements.agencyMembersList?.addEventListener("change", async (event) => {
    const card = event.target.closest("[data-member-id]");
    if (!card) return;
    const member = getAgencyMemberById(card.dataset.memberId);
    if (!member) return;
    if (event.target.matches("[data-member-label]")) {
      const label = event.target.value.trim();
      if (!label || label === member.label) {
        event.target.value = member.label;
        return;
      }
      try {
        applyAccountSnapshot(await postAccountJson("/api/konto/pracownicy/etykieta", { id: member.id, label }));
        showToast("Zmieniono nazwę pracownika");
      } catch (error) {
        event.target.value = member.label;
        showToast(error?.message || "Nie udało się zmienić nazwy", "error");
      }
      return;
    }
    if (event.target.matches("[data-member-file]")) {
      const [file] = event.target.files || [];
      event.target.value = "";
      if (file) void importEmployeeDatabaseFromFile(member, file);
    }
  });

  elements.agencyGenerateSeedEmpty?.addEventListener("change", () => {
    if (elements.agencyGenerateSeedEmpty.checked) {
      setAgencyStatus(elements.agencyGenerateStatus, "");
      renderAgencySeedPicker();
    }
  });

  elements.agencyGenerateSeedSelected?.addEventListener("change", () => {
    if (elements.agencyGenerateSeedSelected.checked) {
      setAgencyStatus(elements.agencyGenerateStatus, "");
      renderAgencySeedPicker();
    }
  });

  elements.agencyGenerateSeedChoose?.addEventListener("click", () => {
    if (!agencySeedGenerationActive) openAgencyPolicyPicker("seed");
  });

  elements.agencyAssignmentChoose?.addEventListener("click", () => {
    if (!agencyAssignmentActive) openAgencyPolicyPicker("assignment");
  });

  elements.agencyPolicyPickerClose?.addEventListener("click", closeAgencyPolicyPicker);
  elements.agencyPolicyPickerCancel?.addEventListener("click", closeAgencyPolicyPicker);
  elements.agencyPolicyPickerConfirm?.addEventListener("click", confirmAgencyPolicyPickerSelection);
  elements.agencyPolicyPickerDialog?.addEventListener("close", () => {
    
    agencyPolicyPickerMode = "";
    agencyPolicyPickerWorkingSelection.clear();
  });

  elements.agencyPolicyPickerSearch?.addEventListener("input", scheduleAgencyPolicyPickerRender);
  elements.agencyPolicyPickerPeriod?.addEventListener("change", () => {
    syncAgencyPolicyPickerCustomRangeVisibility();
    renderAgencyPolicyPickerGroups();
  });
  elements.agencyPolicyPickerFrom?.addEventListener("change", renderAgencyPolicyPickerGroups);
  elements.agencyPolicyPickerTo?.addEventListener("change", renderAgencyPolicyPickerGroups);

  elements.agencyPolicyPickerSelectVisible?.addEventListener("click", () => {
    setAgencyPolicyPickerPolicies(getAgencyPolicyPickerVisiblePolicies(), true);
  });
  elements.agencyPolicyPickerUnselectVisible?.addEventListener("click", () => {
    setAgencyPolicyPickerPolicies(getAgencyPolicyPickerVisiblePolicies(), false);
  });
  elements.agencyPolicyPickerClearAll?.addEventListener("click", () => {
    agencyPolicyPickerWorkingSelection.clear();
    renderAgencyPolicyPickerGroups();
  });

  
  
  elements.agencyPolicyPickerGroups?.addEventListener("change", (event) => {
    const groupToggle = event.target.closest("[data-agency-picker-group-toggle]");
    if (groupToggle) {
      const group = groupToggle.closest("[data-agency-picker-group]");
      if (!group) return;
      const shouldSelect = groupToggle.checked;
      group.querySelectorAll("[data-agency-seed-policy-token]").forEach((checkbox) => {
        checkbox.checked = shouldSelect;
        const policyToken = String(checkbox.dataset.agencySeedPolicyToken || "");
        if (!policyToken) return;
        if (shouldSelect) agencyPolicyPickerWorkingSelection.add(policyToken);
        else agencyPolicyPickerWorkingSelection.delete(policyToken);
      });
      refreshAgencyPolicyPickerGroupHeader(group);
      updateAgencyPolicyPickerSummary();
      return;
    }
    const checkbox = event.target.closest("[data-agency-seed-policy-token]");
    if (!checkbox) return;
    const policyToken = String(checkbox.dataset.agencySeedPolicyToken || "");
    if (!policyToken) return;
    if (checkbox.checked) agencyPolicyPickerWorkingSelection.add(policyToken);
    else agencyPolicyPickerWorkingSelection.delete(policyToken);
    const group = checkbox.closest("[data-agency-picker-group]");
    if (group) refreshAgencyPolicyPickerGroupHeader(group);
    updateAgencyPolicyPickerSummary();
  });

  
  elements.agencyPolicyPickerGroups?.addEventListener("toggle", (event) => {
    const group = event.target;
    if (!(group instanceof HTMLElement)) return;
    const groupName = String(group.dataset?.agencyPickerGroup || "");
    if (!groupName) return;
    if (group.open) agencyPolicyPickerOpenGroups.add(groupName);
    else agencyPolicyPickerOpenGroups.delete(groupName);
  }, true);

  elements.agencyAssignmentClose?.addEventListener("click", () => {
    if (!agencyAssignmentActive) closeAgencyAssignmentPanel();
  });

  elements.agencyAssignmentDownload?.addEventListener("click", async () => {
    const target = getAgencyAssignmentTarget();
    const selectedPolicies = getAgencyAssignmentSelection();
    if (!target || target.id !== agencyAssignmentTargetId) {
      closeAgencyAssignmentPanel();
      showToast("Wybrany pracownik nie jest już dostępny. Otwórz wybór ponownie.", "error");
      return;
    }
    if (target.pairingReady !== true) {
      setAgencyStatus(
        elements.agencyAssignmentStatus,
        "Ta instalacja wymaga najpierw parowania. Pokaż pracownikowi jego kod parowania.",
        "error",
      );
      return;
    }
    if (selectedPolicies.length === 0) {
      updateAgencyAssignmentSummary();
      return;
    }
    if (selectedPolicies.some((policy) => !normalizePolicyOwnerId(policy?.ownerId))) {
      setAgencyStatus(
        elements.agencyAssignmentStatus,
        "Jedna z polis nie ma prawidłowego właściciela. Paczka nie została utworzona.",
        "error",
      );
      return;
    }
    setAgencyAssignmentActive(true);
    setAgencyStatus(
      elements.agencyAssignmentStatus,
      "Przygotowywanie podpisanej paczki z pełnymi danymi i załącznikami…",
    );
    try {
      const databaseContents = createAgencySeedDatabaseContents(selectedPolicies);
      const requestBody = createAgencySeedRequestBody({ databaseContents });
      await downloadZipFromEndpoint(
        `/api/konto/przydzialy-polis/${encodeURIComponent(target.id)}`,
        {
          method: "POST",
          headers: { "Content-Type": "application/json" },
          body: requestBody,
        },
        `Iseca-polisy-${target.label}.zip`,
      );
      setAgencyStatus(
        elements.agencyAssignmentStatus,
        `Gotowe — pobrano paczkę dla „${target.label}”. Przekaż ją wyłącznie temu pracownikowi.`,
      );
      agencyAssignmentSelectedPolicyTokens.clear();
      renderAgencyAssignmentPicker();
    } catch (error) {
      setAgencyStatus(
        elements.agencyAssignmentStatus,
        error?.message || "Nie udało się przygotować paczki polis.",
        "error",
      );
    } finally {
      setAgencyAssignmentActive(false);
    }
  });

  elements.agencyPairingCodeCopy?.addEventListener("click", () => {
    const pairingCode = elements.agencyPairingCodeOutput?.textContent || "";
    if (pairingCode) void copyAgencyIdToClipboard(pairingCode, "Skopiowano kod parowania");
  });

  elements.agencyPairingCodeClose?.addEventListener("click", clearAgencyPairingCodeDialog);
  elements.agencyPairingCodeDialog?.addEventListener("close", clearAgencyPairingCodeDialog);
  elements.agencyPairingCodeDialog?.addEventListener("cancel", () => {
    globalThis.setTimeout(clearAgencyPairingCodeDialog, 0);
  });

  elements.agencyPairingSubmit?.addEventListener("click", async () => {
    const pairingCode = String(elements.agencyPairingCode?.value || "").trim();
    if (!/^SEK2\.[A-Z2-9]{12}\.[A-Z2-9]{12}\.[A-Za-z0-9_-]{43}$/.test(pairingCode)) {
      setAgencyStatus(
        elements.agencyAssignmentImportStatus,
        "Kod parowania ma nieprawidłowy format. Skopiuj go ponownie bez zmiany wielkości liter.",
        "error",
      );
      return;
    }
    elements.agencyPairingSubmit.disabled = true;
    try {
      await postAccountJson("/api/konto/parowanie-centrali", { pairingCode });
      elements.agencyPairingCode.value = "";
      const snapshotResponse = await apiFetch("/api/konto/snapshot", { cache: "no-store" });
      const snapshot = await snapshotResponse.json().catch(() => null);
      if (!snapshotResponse.ok || !snapshot?.account) {
        throw new Error("Parowanie zapisano, ale nie udało się odświeżyć stanu konta.");
      }
      applyAccountSnapshot(snapshot);
      setAgencyStatus(
        elements.agencyAssignmentImportStatus,
        "Instalacja została bezpiecznie sparowana z centralą. Możesz teraz wczytywać jej paczki.",
      );
    } catch (error) {
      if (elements.agencyPairingCode) elements.agencyPairingCode.value = "";
      setAgencyStatus(
        elements.agencyAssignmentImportStatus,
        error?.message || "Nie udało się sparować instalacji.",
        "error",
      );
    } finally {
      elements.agencyPairingSubmit.disabled = false;
    }
  });

  elements.agencyAssignmentImportButton?.addEventListener("click", () => {
    if (currentAccount?.pairingReady === true) elements.agencyAssignmentImportFile?.click();
  });

  elements.agencyAssignmentImportFile?.addEventListener("change", (event) => {
    const [file] = event.target.files || [];
    event.target.value = "";
    if (!file) return;
    if (!/\.zip$/i.test(String(file.name || ""))) {
      setAgencyStatus(elements.agencyAssignmentImportStatus, "Wybierz paczkę ZIP od centrali.", "error");
      return;
    }
    setAgencyStatus(elements.agencyAssignmentImportStatus, "Sprawdzanie podpisu i przygotowywanie importu…");
    void importCentralAssignmentFromFile(file);
  });

  elements.agencyGenerateButton?.addEventListener("click", async () => {
    const label = elements.agencyGenerateName?.value?.trim() || "";
    if (!label) {
      setAgencyStatus(elements.agencyGenerateStatus, "Podaj nazwę pracownika.", "error");
      return;
    }
    const selectedMode = getAgencySeedMode() === "selected";
    const selectedPolicies = selectedMode ? getSelectedAgencySeedPolicies() : [];
    if (selectedMode && selectedPolicies.length === 0) {
      setAgencyStatus(
        elements.agencyGenerateStatus,
        "Wybierz co najmniej jedną polisę przyciskiem „Wybierz polisy…”.",
        "error",
      );
      updateAgencySeedSummary();
      return;
    }
    if (selectedPolicies.length > MAX_AGENCY_SEED_POLICIES) {
      setAgencyStatus(
        elements.agencyGenerateStatus,
        `Jedna paczka może zawierać maksymalnie ${MAX_AGENCY_SEED_POLICIES.toLocaleString("pl-PL")} polis.`,
        "error",
      );
      return;
    }
    const policyWithoutOwner = selectedPolicies.find(
      (policy) => !normalizePolicyOwnerId(policy?.ownerId),
    );
    if (policyWithoutOwner) {
      setAgencyStatus(
        elements.agencyGenerateStatus,
        "Jedna z wybranych polis nie ma zapisanego właściciela. Zapisz ponownie bazę i spróbuj jeszcze raz.",
        "error",
      );
      return;
    }
    setAgencySeedGenerationLoading(true);
    setAgencyStatus(elements.agencyGenerateStatus, "Przygotowywanie bazy pracownika… To może potrwać minutę.");
    try {
      const payload = { label };
      
      
      payload.allowInsurerImports = elements.agencyGenerateAllowImports?.checked === true;
      if (selectedMode) {
        
        
        const databaseContents = createAgencySeedDatabaseContents(selectedPolicies);
        payload.databaseContents = databaseContents;
      }
      const requestBody = createAgencySeedRequestBody(payload);
      await downloadZipFromEndpoint("/api/konto/paczka-pracownika", {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: requestBody,
      }, `Iseca-${label}.zip`);
      try {
        const snapshotResponse = await apiFetch("/api/konto/snapshot");
        if (snapshotResponse.ok) applyAccountSnapshot(await snapshotResponse.json());
      } catch {
      }
      elements.agencyGenerateName.value = "";
      agencySeedSelectedPolicyTokens.clear();
      if (elements.agencyGenerateSeedEmpty) elements.agencyGenerateSeedEmpty.checked = true;
      if (elements.agencyGenerateSeedSelected) elements.agencyGenerateSeedSelected.checked = false;
      
      if (elements.agencyGenerateAllowImports) elements.agencyGenerateAllowImports.checked = false;
      renderAgencySeedPicker();
      setAgencyStatus(
        elements.agencyGenerateStatus,
        `Gotowe - plik ZIP został pobrany. Przekaż go pracownikowi „${label}”. Jego identyfikator jest już na Twojej liście.`,
      );
    } catch (error) {
      setAgencyStatus(elements.agencyGenerateStatus, error?.message || "Nie udało się przygotować bazy pracownika.", "error");
    } finally {
      setAgencySeedGenerationLoading(false);
    }
  });

  
  
  [
    elements.agencyExportInsurer,
    elements.agencyExportPeriod,
    elements.agencyExportFrom,
    elements.agencyExportTo,
    elements.agencyExportClient,
  ].forEach((control) => {
    if (!control) return;
    const onFilterChange = () => {
      if (control === elements.agencyExportPeriod) syncAgencyExportCustomRangeVisibility();
      updateAgencyExportSummary();
    };
    control.addEventListener("input", onFilterChange);
    control.addEventListener("change", onFilterChange);
  });

  elements.agencyExportReset?.addEventListener("click", () => {
    if (elements.agencyExportInsurer) elements.agencyExportInsurer.value = "";
    if (elements.agencyExportPeriod) elements.agencyExportPeriod.value = "";
    if (elements.agencyExportFrom) elements.agencyExportFrom.value = "";
    if (elements.agencyExportTo) elements.agencyExportTo.value = "";
    if (elements.agencyExportClient) elements.agencyExportClient.value = "";
    syncAgencyExportCustomRangeVisibility();
    updateAgencyExportSummary();
  });

  elements.agencyExportButton?.addEventListener("click", async () => {
    const selection = getAgencyExportSelection();
    if (selection.matchedPolicies.length === 0) {
      setAgencyStatus(elements.agencyExportStatus, "Żadna polisa nie pasuje do wybranych filtrów.", "error");
      return;
    }
    elements.agencyExportButton.disabled = true;
    setAgencyStatus(elements.agencyExportStatus, "Przygotowywanie paczki… Przy wielu załącznikach może to potrwać.");
    try {
      const datePart = formatDateForInput(new Date());
      
      
      const endpoint = selection.filtered
        ? "/api/konto/paczka-centrali?zakres=wybrane"
        : "/api/konto/paczka-centrali";
      const body = selection.filtered
        ? createDataFileContents(selection.matchedPolicies, new Date().toISOString(), [], [], [], [])
        : createDataFileContents();
      const nameSuffix = selection.filtered ? "-wybrane" : "";
      await downloadZipFromEndpoint(endpoint, {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body,
      }, `Baza-${currentAccount?.name || "Iseca"}-${datePart}${nameSuffix}.zip`);
      try {
        const snapshotResponse = await apiFetch("/api/konto/snapshot");
        if (snapshotResponse.ok) applyAccountSnapshot(await snapshotResponse.json());
      } catch {
      }
      setAgencyStatus(
        elements.agencyExportStatus,
        selection.filtered
          ? `Gotowe - paczka ZIP z wybranymi polisami (${pluralizePolicies(selection.matchedPolicies.length)}) została pobrana. Prześlij ją centrali.`
          : "Gotowe - paczka ZIP z całą bazą została pobrana. Prześlij ją centrali.",
      );
    } catch (error) {
      setAgencyStatus(elements.agencyExportStatus, error?.message || "Nie udało się przygotować paczki.", "error");
    } finally {
      elements.agencyExportButton.disabled = false;
      updateAgencyExportSummary();
    }
  });
}


async function downloadZipFromEndpoint(path, fetchOptions, downloadName) {
  const response = await apiFetch(path, fetchOptions);
  if (!response.ok) {
    const data = await response.json().catch(() => ({}));
    throw new Error(data?.error || "Nie udało się przygotować paczki.");
  }
  const blob = await response.blob();
  const url = URL.createObjectURL(blob);
  const link = document.createElement("a");
  link.href = url;
  link.download = downloadName;
  link.click();
  URL.revokeObjectURL(url);
}

initializeAgencySettingsUi();

async function postAccountJsonWith(fetchRequest, path, payload) {
  const response = await fetchRequest(path, {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify(payload || {}),
  });
  const data = await response.json().catch(() => ({}));
  if (!response.ok) {
    const error = new Error(data?.error || "Operacja nie powiodła się.");
    error.data = data;
    error.status = response.status;
    throw error;
  }
  return data;
}

function postAccountJson(path, payload) {
  return postAccountJsonWith(apiFetch, path, payload);
}

const RAW_ACCOUNT_GATE_POST_PATHS = new Set([
  "/api/konto/create",
  "/api/konto/set-pin",
  "/api/konto/verify",
]);

function postGateAccountJson(path, payload) {
  if (!RAW_ACCOUNT_GATE_POST_PATHS.has(path)) {
    return Promise.reject(new Error("Ta operacja konta nie może omijać ochrony sesji PIN."));
  }
  return postAccountJsonWith(
    (requestPath, requestInit) => globalThis.fetch(requestPath, requestInit),
    path,
    payload,
  );
}









function runAccountGate() {
  if (accountGateInitialized) return activeAccountGatePromise || Promise.resolve();
  const overlay = document.querySelector("#accountGateOverlay");
  const form = document.querySelector("#accountGateForm");
  if (!overlay || !form) return Promise.resolve();
  accountGateInitialized = true;
  const appShell = document.querySelector(".page-shell");
  const title = overlay.querySelector("#accountGateTitle");
  const subtitle = overlay.querySelector("#accountGateSubtitle");
  const nameField = overlay.querySelector("#accountGateNameField");
  const nameInput = overlay.querySelector("#accountGateName");
  const licenseLoginField = overlay.querySelector("#accountGateLicenseLoginField");
  const licenseLoginInput = overlay.querySelector("#accountGateLicenseLogin");
  const licensePasswordField = overlay.querySelector("#accountGateLicensePasswordField");
  const licensePasswordInput = overlay.querySelector("#accountGateLicensePassword");
  const pinField = overlay.querySelector("#accountGatePinField");
  const pinLabel = overlay.querySelector("#accountGatePinLabel");
  const pinInput = overlay.querySelector("#accountGatePin");
  const pinRepeatField = overlay.querySelector("#accountGatePinRepeatField");
  const pinRepeatInput = overlay.querySelector("#accountGatePinRepeat");
  const insurersField = overlay.querySelector("#accountGateInsurersField");
  const insurersList = overlay.querySelector("#accountGateInsurersList");
  const errorLabel = overlay.querySelector("#accountGateError");
  const submitButton = overlay.querySelector("#accountGateSubmit");
  const successPanel = overlay.querySelector("#accountGateSuccess");
  const idCode = overlay.querySelector("#accountGateId");
  const copyButton = overlay.querySelector("#accountGateCopyId");
  const enterButton = overlay.querySelector("#accountGateEnter");
  let busy = false;
  let quickLockPending = false;
  let quickLockArmId = 0;
  let focusBeforeGate = null;
  let startupGatePending = true;

  const startupGatePromise = beginAccountGateSession();
  {
    function showGate({ preserveBusyOverlay = false } = {}) {
      if (!globalThis.__startupGateShownAtMs) {
        globalThis.__startupGateShownAtMs = Math.round(globalThis.performance?.now?.() || 0);
      }
      if (!preserveBusyOverlay) hideAppBusyOverlay();
      const activeElement = document.activeElement;
      focusBeforeGate = activeElement
        && activeElement !== document.body
        && typeof activeElement.focus === "function"
        && appShell?.contains?.(activeElement)
        ? activeElement
        : null;
      if (appShell) {
        appShell.inert = true;
        appShell.setAttribute("aria-hidden", "true");
      }
      overlay.dataset.hidden = "false";
    }

    function closeGate() {
      quickLockPending = false;
      quickLockArmId += 1;
      if (startupGatePending) {
        startupGatePending = false;
        globalThis.__startupGateClosedAtMs = Math.round(globalThis.performance?.now?.() || 0);
        showAppBusyOverlay("Uruchamianie…");
      }
      overlay.dataset.hidden = "true";
      if (appShell) {
        appShell.inert = false;
        appShell.removeAttribute("aria-hidden");
      }
      const elementToFocus = focusBeforeGate;
      focusBeforeGate = null;
      elementToFocus?.focus?.({ preventScroll: true });
      completeAccountGateSession();
    }

    function setGateError(message) {
      errorLabel.textContent = message || "";
      errorLabel.hidden = !message;
    }

    function showIdentityPanel(accountId) {
      form.hidden = true;
      successPanel.hidden = false;
      title.textContent = "Konto gotowe";
      subtitle.textContent = "";
      idCode.textContent = accountId;
      enterButton.focus();
    }

    function showGateView(mode, status) {
      const isQuickLock = mode === "login" && status?.quickLock === true;
      const sessionRevokedPromise = isQuickLock
        && status?.sessionRevokedPromise
        && typeof status.sessionRevokedPromise.then === "function"
        ? status.sessionRevokedPromise
        : null;
      const armId = ++quickLockArmId;
      quickLockPending = Boolean(sessionRevokedPromise);
      accountGateMode = mode;
      
      
      
      const licenseMode = mode === "licencja";
      if (licenseLoginField) licenseLoginField.hidden = !licenseMode;
      if (licensePasswordField) licensePasswordField.hidden = !licenseMode;
      if (pinField) pinField.hidden = licenseMode;
      nameField.hidden = mode !== "create";
      pinRepeatField.hidden = mode === "login" || licenseMode;
      insurersField.hidden = mode !== "create";
      if (mode === "create" && !insurersList.childElementCount) {
        insurersList.innerHTML = createAgencyInsurerChoicesMarkup({ selectedIds: new Set() });
      }
      form.hidden = false;
      successPanel.hidden = true;
      setGateError("");
      pinInput.value = "";
      pinRepeatInput.value = "";
      if (licenseMode) {
        title.textContent = "Zaloguj się do programu";
        const contactLink = document.createElement("a");
        contactLink.href = "mailto:baza@iseca.pl";
        contactLink.textContent = "napisz do nas";
        subtitle.replaceChildren(
          document.createTextNode("Podaj login i hasło. Jeżeli jeszcze go nie otrzymałeś, "),
          contactLink,
          document.createTextNode(".")
        );
        submitButton.textContent = "Dalej";
      } else if (mode === "create") {
        title.textContent = "Załóż konto";
        subtitle.textContent = "Pierwsze uruchomienie: nadaj nazwę konta i ustaw PIN, którym będziesz otwierać aplikację.";
        submitButton.textContent = "Załóż konto";
      } else if (mode === "set-pin") {
        title.textContent = `Witaj, ${status?.name || ""}!`;
        subtitle.textContent = "Twoje konto przygotowała centrala. Ustaw własny PIN, którym będziesz otwierać aplikację.";
        submitButton.textContent = "Ustaw PIN";
      } else {
        title.textContent = isQuickLock ? "Ekran zablokowany" : (status?.name ? `Witaj, ${status.name}!` : "Witaj!");
        subtitle.textContent = isQuickLock
          ? (quickLockPending
            ? "Trwa zabezpieczanie sesji. Ekran pozostaje zablokowany."
            : "Podaj PIN")
          : "Podaj PIN";
        submitButton.textContent = isQuickLock ? "Odblokuj" : "Zaloguj się";
      }
      pinInput.disabled = quickLockPending;
      submitButton.disabled = quickLockPending;
      showGate({ preserveBusyOverlay: isQuickLock });
      if (!quickLockPending) {
        if (licenseMode) licenseLoginInput?.focus();
        else (mode === "create" ? nameInput : pinInput).focus();
      } else {
        sessionRevokedPromise.then(() => {
          if (armId !== quickLockArmId || !quickLockPending) return;
          quickLockPending = false;
          pinInput.disabled = false;
          submitButton.disabled = false;
          subtitle.textContent = "Podaj PIN";
          pinInput.focus();
        });
      }
    }

    showAccountLoginGate = (options = {}) => showGateView("login", {
      name: currentAccount?.name || "",
      quickLock: options.quickLock === true,
      sessionRevokedPromise: options.sessionRevokedPromise,
    });

    function showConnectionProblem() {
      form.hidden = true;
      successPanel.hidden = true;
      title.textContent = "Brak połączenia z aplikacją";
      subtitle.textContent = "Uruchom Iseca ikoną przy zegarku i chwilę poczekaj - spróbuję połączyć się ponownie.";
      showGate();
    }

    async function boot() {
      let status = null;
      try {
        const response = await globalThis.fetch("/api/konto/status");
        if (response.ok) status = await response.json();
      } catch {
      }
      if (!status) {
        showConnectionProblem();
        globalThis.setTimeout(boot, 4000);
        return;
      }
      applyStartupTheme(status.motyw);
      if (!status.exists) {
        
        
        
        let licencjaSkonfigurowana = !(licenseLoginInput && licensePasswordInput);
        if (!licencjaSkonfigurowana) {
          try {
            const licencja = await globalThis.fetch("/api/licencja/status");
            if (licencja.ok) {
              licencjaSkonfigurowana = (await licencja.json())?.skonfigurowana === true;
            }
          } catch {
          }
        }
        showGateView(licencjaSkonfigurowana ? "create" : "licencja", status);
        return;
      }
      if (!status.pinSet) {
        showGateView("set-pin", status);
        return;
      }
      if (status.authenticated === true) {
        try {
          
          
          const response = await globalThis.fetch("/api/konto/snapshot");
          if (response.ok) {
            applyAccountSnapshot(await response.json());
            closeGate();
            return;
          }
        } catch {
        }
      }
      showGateView("login", status);
    }

    
    
    async function submitLicenseStep() {
      if (!licenseLoginInput || !licensePasswordInput) {
        showGateView("create", {});
        return;
      }
      const login = licenseLoginInput.value.trim().toLowerCase();
      const haslo = licensePasswordInput.value;
      if (!login || !haslo) {
        setGateError("Podaj login i hasło.");
        (login ? licensePasswordInput : licenseLoginInput).focus();
        return;
      }
      busy = true;
      submitButton.disabled = true;
      submitButton.textContent = "Sprawdzanie…";
      try {
        const response = await globalThis.fetch("/api/licencja/zapisz", {
          method: "POST",
          headers: { "Content-Type": "application/json" },
          body: JSON.stringify({ login, haslo }),
        });
        const data = await response.json().catch(() => ({}));
        if (!response.ok) {
          setGateError(data?.error || "Nie udało się potwierdzić loginu i hasła.");
          licensePasswordInput.value = "";
          licensePasswordInput.focus();
          return;
        }
        licensePasswordInput.value = "";
        void refreshLicenseStatus().catch(() => {});
        showGateView("create", { name: data?.nazwa || "" });
      } catch {
        setGateError("Nie udało się połączyć z internetem. Sprawdź połączenie i spróbuj ponownie.");
        licensePasswordInput.focus();
      } finally {
        busy = false;
        submitButton.disabled = false;
        if (accountGateMode === "licencja") submitButton.textContent = "Dalej";
      }
    }

    form.addEventListener("submit", async (event) => {
      event.preventDefault();
      if (busy || quickLockPending) return;
      if (accountGateMode === "licencja") {
        await submitLicenseStep();
        return;
      }
      const pin = pinInput.value.trim();
      if (!/^\d{4,8}$/.test(pin)) {
        setGateError("PIN musi mieć od 4 do 8 cyfr.");
        pinInput.focus();
        return;
      }
      if (accountGateMode === "create" && !nameInput.value.trim()) {
        setGateError("Podaj nazwę konta.");
        nameInput.focus();
        return;
      }
      if (accountGateMode !== "login" && pin !== pinRepeatInput.value.trim()) {
        setGateError("PIN-y różnią się od siebie. Wpisz je jeszcze raz.");
        pinRepeatInput.value = "";
        pinRepeatInput.focus();
        return;
      }
      const servedInsurers = accountGateMode === "create"
        ? [...insurersList.querySelectorAll("[data-agency-insurer]:checked")]
          .map((checkbox) => normalizeInsurerId(checkbox.value))
          .filter(Boolean)
        : [];
      if (accountGateMode === "create" && servedInsurers.length === 0) {
        setGateError("Zaznacz co najmniej jedno towarzystwo obsługiwane przez agencję.");
        insurersField.scrollIntoView({ block: "nearest" });
        return;
      }
      busy = true;
      submitButton.disabled = true;
      try {
        if (accountGateMode === "create") {
          const snapshot = await postGateAccountJson("/api/konto/create", {
            name: nameInput.value,
            pin,
            servedInsurers,
          });
          applyAccountSnapshot(snapshot);
          showIdentityPanel(snapshot?.account?.id || "");
        } else if (accountGateMode === "set-pin") {
          const snapshot = await postGateAccountJson("/api/konto/set-pin", { pin });
          applyAccountSnapshot(snapshot);
          showIdentityPanel(snapshot?.account?.id || "");
        } else {
          const snapshot = await postGateAccountJson("/api/konto/verify", { pin });
          applyAccountSnapshot(snapshot);
          closeGate();
        }
      } catch (error) {
        const lockedForSeconds = Number(error?.data?.lockedForSeconds) || 0;
        if (lockedForSeconds > 0) {
          setGateError(`Zbyt wiele błędnych prób. Spróbuj ponownie za ${lockedForSeconds} s.`);
        } else if (accountGateMode === "login" && error?.status === 401) {
          setGateError("Nieprawidłowy PIN.");
        } else {
          setGateError(error?.message || "Operacja nie powiodła się.");
        }
        pinInput.value = "";
        pinRepeatInput.value = "";
        pinInput.focus();
      } finally {
        busy = false;
        submitButton.disabled = quickLockPending;
      }
    });

    copyButton.addEventListener("click", async () => {
      try {
        await globalThis.navigator?.clipboard?.writeText(idCode.textContent || "");
        copyButton.textContent = "Skopiowano";
        globalThis.setTimeout(() => {
          copyButton.textContent = "Kopiuj";
        }, 1600);
      } catch {
      }
    });

    enterButton.addEventListener("click", closeGate);

    void boot();
  }
  return startupGatePromise;
}

async function initializeFileSetup() {
  const resetBrowserFileConnections = new URLSearchParams(globalThis.location.search)
    .get(BROWSER_FILE_CONNECTIONS_RESET_QUERY) === "1";
  if (resetBrowserFileConnections) {
    try {
      await resetPolicyBrowserFileConnections();
      globalThis.location.replace(getUrlWithoutBrowserFileConnectionsReset());
    } catch (error) {
      globalThis.alert(error?.message || "Nie udało się wyczyścić pamięci Bazy Polis w przeglądarce.");
    }
    return;
  }
  try {
    globalThis.navigator?.storage?.persist?.()?.catch?.(() => {});
  } catch {
  }
  await migrateScopedFileCacheEntries();
  try {
    await restoreRememberedAppDirectory({ deferAttachmentReconcile: true });
  } catch {
  }
  if (!initialDataFileReady) await restoreRememberedDataFile();
  if (!initialSettingsFileReady) await restoreRememberedSettingsFile();
  await getRememberedAttachmentsDirectoryHandle();
  showRequiredFileSetup();
}




function reportStartupTimings(czasy) {
  try {
    void apiFetch("/api/diagnostyka/zdarzenie", {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({ rodzaj: "rozruch-frontu", dane: czasy }),
    }).catch(() => {});
  } catch {
  }
}



globalThis.initialSetupReady = runAccountGate()
  .then(async () => {
    const initStartedAt = globalThis.performance?.now?.() || 0;
    const gateShownAtMs = Number(globalThis.__startupGateShownAtMs) || 0;
    const gateClosedAtMs = Number(globalThis.__startupGateClosedAtMs) || 0;
    const czasy = {
      
      
      doOknaLogowaniaMs: gateShownAtMs,
      wpisywaniePinuMs: gateClosedAtMs > gateShownAtMs ? gateClosedAtMs - gateShownAtMs : 0,
    };
    let previousMarkAt = initStartedAt;
    const zmierzEtap = (etykieta) => {
      const now = globalThis.performance?.now?.() || 0;
      czasy[etykieta] = Math.round(now - previousMarkAt);
      previousMarkAt = now;
    };
    try {
      
      
      await refreshLicenseGuard();
      zmierzEtap("licencjaMs");
      await initializeFileSetup();
      zmierzEtap("bazaZPlikowMs");
      
      
      
      
      const employeePackageTransactionsResolved = isEmployeeAccount()
        ? await recoverPendingCentralAssignments()
        : await recoverPendingEmployeePackageImports();
      zmierzEtap("paczkiMs");
      if (!employeePackageTransactionsResolved) {
        showToast(
          "Oczekująca paczka wymaga rozstrzygnięcia. Wstrzymano inne odzyskiwanie i skan załączników.",
          "warning",
        );
        return;
      }
      await recoverUnconsumedPortfolioImports();
      zmierzEtap("importyMs");
      void reconcileAttachmentsFromFolder();
    } finally {
      czasy.poZalogowaniuRazemMs = Math.round((globalThis.performance?.now?.() || 0) - initStartedAt);
      reportStartupTimings(czasy);
    }
  })
  .catch((error) => {
    console.error("Inicjalizacja aplikacji nie powiodła się", error);
  })
  .finally(() => {
    
    
    hideAppBusyOverlay();
  });

const IDLE_RPG_SAVE_KEY = "polisyIdleRpg.v1";
const IDLE_RPG_TICK_MS = 200;
const IDLE_RPG_ATTACK_INTERVAL_TICKS = 3;
const IDLE_RPG_ACTOR_ATTACK_CYCLE_TICKS = IDLE_RPG_ATTACK_INTERVAL_TICKS * 2;
const IDLE_RPG_RESPAWN_TICKS = 12;
const IDLE_RPG_MAX_FLOATS = 24;
const IDLE_RPG_DAILY_STAT_POINT_LIMIT = 3;
const IDLE_RPG_MAX_STAT_POINTS = 300;
const IDLE_RPG_MAX_MONSTER = 100;
const IDLE_RPG_BOSS_EVERY = 5;
const IDLE_RPG_SURGE_TARGETS = 3;
const IDLE_RPG_MAX_SLOW = 0.8;
const IDLE_RPG_MONSTER_HP_GROWTH = 1.1;
const IDLE_RPG_BOSS_HP_MULTIPLIER = 2.5;
const IDLE_RPG_BOSS_ATTACK_MULTIPLIER = 2;
const IDLE_RPG_BLOCK_COOLDOWN_MS = 2_000;
const IDLE_RPG_SUPER_BLOCK_STREAK = 3;
const IDLE_RPG_SUPER_BLOCK_MULTIPLIER = 2;
const IDLE_RPG_ULTIMATE_BLOCK_STREAK = 10;
const IDLE_RPG_MONSTER_LEVEL_1_ATTACK_MIN_MS = 1_500;
const IDLE_RPG_MONSTER_LEVEL_1_ATTACK_MAX_MS = 2_500;
const IDLE_RPG_MONSTER_LEVEL_100_ATTACK_MIN_MS = 100;
const IDLE_RPG_MONSTER_LEVEL_100_ATTACK_MAX_MS = 500;
const IDLE_RPG_MONSTER_LEVEL_1_WINDUP_MS = 700;
const IDLE_RPG_MONSTER_LEVEL_100_WINDUP_MS = 300;
const IDLE_RPG_HERO_SPRITE = "🤵";
const IDLE_RPG_MONSTER_SPRITE = "🧟";
const IDLE_RPG_BOSS_SPRITE = "👹";
const IDLE_RPG_MONSTER_ATTACK_SPRITE = "🧟⚔️";
const IDLE_RPG_BOSS_ATTACK_SPRITE = "👹⚔️";
const IDLE_RPG_STATS = [
  { key: "strength", label: "Siła", icon: "💪", description: "+1,5 ataku" },
  { key: "vitality", label: "Wytrzymałość", icon: "❤️", description: "+2 zdrowia" },
  { key: "agility", label: "Zwinność", icon: "🌀", description: "+1% uniku (maks. 25%)" },
  { key: "intellect", label: "Inteligencja", icon: "🔮", description: "+2,5 do zaklęć" },
  { key: "luck", label: "Szczęście", icon: "🍀", description: "+1% krytyka (maks. 25%)" },
];
const IDLE_RPG_UPGRADES = [
  { key: "weapon", label: "Argumenty Sprzedażowe", icon: "💼", baseCost: 6, costMultiplier: 1.5, description: "+1 ataku" },
  { key: "armor", label: "OWU", icon: "📜", baseCost: 6, costMultiplier: 1.1, description: "+1 zdrowia" },
  { key: "fire", label: "Pożar", icon: "🔥", baseCost: 12, costPerLevel: 3, description: "co 5. udany blok w serii: 2 obr. za poz. + Inteligencja" },
  { key: "surge", label: "Przepięcie", icon: "⚡", baseCost: 12, costPerLevel: 3, description: "co 3. udany blok w serii: 1 obr. za poz., razi też 3 następnych" },
  { key: "flood", label: "Zalanie", icon: "💧", baseCost: 12, costPerLevel: 3, description: "zawsze: -1% szybkości ataku potwora za poz. (maks. 80%)" },
  { key: "ultimate", label: "Sprzedaż polisy życiowej!", icon: "🖋️", baseCost: 500, costPerLevel: 100, description: "co 10. udany blok w serii: 100 obr. za poz. + Argumenty + Siła + Inteligencja" },
];
const IDLE_RPG_ZONES = [
  "Las Składek",
  "Bagno Franszyz",
  "Jaskinia Regresów",
  "Pustkowie Wypowiedzeń",
  "Twierdza Ubezpieczycieli",
  "Otchłań Aneksów",
];

const idleRpgElements = {
  counter: document.querySelector("#recordCounter"),
  dialog: document.querySelector("#idleRpgDialog"),
  close: document.querySelector("#closeIdleRpg"),
  zone: document.querySelector("#idleRpgZone"),
  distance: document.querySelector("#idleRpgDistance"),
  battle: document.querySelector("#idleRpgBattle"),
  heroButton: document.querySelector("#idleRpgHeroButton"),
  heroSprite: document.querySelector("#idleRpgHeroSprite"),
  heroHp: document.querySelector("#idleRpgHeroHp"),
  heroHpLabel: document.querySelector("#idleRpgHeroHpLabel"),
  monsterButton: document.querySelector("#idleRpgMonsterButton"),
  monsterSprite: document.querySelector("#idleRpgMonsterSprite"),
  monsterHp: document.querySelector("#idleRpgMonsterHp"),
  monsterHpLabel: document.querySelector("#idleRpgMonsterHpLabel"),
  log: document.querySelector("#idleRpgLog"),
  coins: document.querySelector("#idleRpgCoins"),
  level: document.querySelector("#idleRpgLevel"),
  bestStage: document.querySelector("#idleRpgBestStage"),
  freePoints: document.querySelector("#idleRpgFreePoints"),
  stats: document.querySelector("#idleRpgStats"),
  shop: document.querySelector("#idleRpgShop"),
};

let idleRpgState = null;
let idleRpgRun = null;
let idleRpgTimer = null;
let idleRpgRespawnCountdown = 0;
let idleRpgHeroAttackProgress = IDLE_RPG_ATTACK_INTERVAL_TICKS;
let idleRpgSettingsPersistTimer = null;
let idleRpgPendingMonsterAttack = null;
let idleRpgMonsterAttackTimer = null;
let idleRpgBlockCooldownUntil = 0;

function createDefaultIdleRpgState() {
  return {
    coins: 0,
    expeditions: 0,
    totalKills: 0,
    bestKills: 0,
    victories: 0,
    statPoints: 0,
    dailyGrantDate: "",
    dailyGrantCount: 0,
    stats: { strength: 0, vitality: 0, agility: 0, intellect: 0, luck: 0 },
    upgrades: { weapon: 0, armor: 0, fire: 0, surge: 0, flood: 0, ultimate: 0 },
  };
}

function clampIdleRpgNumber(value) {
  const parsed = Math.floor(Number(value));
  return Number.isFinite(parsed) && parsed > 0 ? parsed : 0;
}

function getIdleRpgAllocatedPoints() {
  return IDLE_RPG_STATS.reduce((sum, stat) => sum + idleRpgState.stats[stat.key], 0);
}

function loadIdleRpgState() {
  const state = createDefaultIdleRpgState();
  try {
    let parsed = uiSettings?.idleRpg;
    if (!parsed || typeof parsed !== "object") {
      const raw = globalThis.localStorage?.getItem(IDLE_RPG_SAVE_KEY);
      if (!raw) return state;
      parsed = JSON.parse(raw);
    }
    state.coins = clampIdleRpgNumber(parsed?.coins);
    state.expeditions = clampIdleRpgNumber(parsed?.expeditions);
    state.totalKills = clampIdleRpgNumber(parsed?.totalKills);
    state.bestKills = Math.min(IDLE_RPG_MAX_MONSTER, clampIdleRpgNumber(parsed?.bestKills));
    state.victories = clampIdleRpgNumber(parsed?.victories);
    state.statPoints = Math.min(IDLE_RPG_MAX_STAT_POINTS, clampIdleRpgNumber(parsed?.statPoints));
    state.dailyGrantDate = typeof parsed?.dailyGrantDate === "string" ? parsed.dailyGrantDate : "";
    state.dailyGrantCount = Math.min(IDLE_RPG_DAILY_STAT_POINT_LIMIT, clampIdleRpgNumber(parsed?.dailyGrantCount));
    for (const stat of IDLE_RPG_STATS) state.stats[stat.key] = clampIdleRpgNumber(parsed?.stats?.[stat.key]);
    for (const upgrade of IDLE_RPG_UPGRADES) {
      state.upgrades[upgrade.key] = clampIdleRpgNumber(parsed?.upgrades?.[upgrade.key]);
    }
    state.upgrades.fire = Math.max(state.upgrades.fire, clampIdleRpgNumber(parsed?.upgrades?.spell));
  } catch {
  }
  const allocated = IDLE_RPG_STATS.reduce((sum, stat) => sum + state.stats[stat.key], 0);
  state.statPoints = Math.min(IDLE_RPG_MAX_STAT_POINTS, Math.max(state.statPoints, allocated));
  return state;
}

function saveIdleRpgState() {
  if (!idleRpgState) return;
  uiSettings.idleRpg = idleRpgState;
  scheduleIdleRpgSettingsPersist();
}

function scheduleIdleRpgSettingsPersist() {
  if (idleRpgSettingsPersistTimer !== null) return;
  idleRpgSettingsPersistTimer = globalThis.setTimeout(() => {
    idleRpgSettingsPersistTimer = null;
    void persistIdleRpgToSettingsFile();
  }, 2000);
}

async function persistIdleRpgToSettingsFile() {
  try {
    const handle = settingsFileHandle || rememberedSettingsFileHandle;
    if (handle) {
      const permission = handle.queryPermission
        ? await handle.queryPermission({ mode: "readwrite" })
        : "granted";
      if (permission === "granted") {
        const inspection = await inspectSettingsFile(await handle.getFile());
        if (!settingsFileRevision || inspection.revision.contentFingerprint === settingsFileRevision.contentFingerprint) {
          settingsFileRevision = inspection.revision;
          await writeSettingsToHandle(handle, uiSettings, { skipFreshnessCheck: true });
          return;
        }
      }
    }
  } catch {
  }
  try {
    await rememberSettingsFileSnapshot(uiSettings);
  } catch {
  }
}

function getIdleRpgDateKey(value) {
  const date = value === undefined ? new Date() : new Date(value);
  if (Number.isNaN(date.getTime())) return "";
  return `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, "0")}-${String(date.getDate()).padStart(2, "0")}`;
}

function grantIdleRpgDailyStatPoints() {
  const today = getIdleRpgDateKey();
  if (idleRpgState.dailyGrantDate !== today) {
    idleRpgState.dailyGrantDate = today;
    idleRpgState.dailyGrantCount = 0;
  }
  const addedToday = policies.filter((policy) => getIdleRpgDateKey(Number(policy.createdAt)) === today).length;
  let grant = Math.min(IDLE_RPG_DAILY_STAT_POINT_LIMIT, addedToday) - idleRpgState.dailyGrantCount;
  grant = Math.min(grant, IDLE_RPG_MAX_STAT_POINTS - idleRpgState.statPoints);
  if (grant <= 0) return 0;
  idleRpgState.dailyGrantCount += grant;
  idleRpgState.statPoints += grant;
  saveIdleRpgState();
  return grant;
}

function getIdleRpgFreePoints() {
  return Math.max(0, idleRpgState.statPoints - getIdleRpgAllocatedPoints());
}

function getIdleRpgCharacterLevel() {
  return Math.min(100, Math.floor(idleRpgState.statPoints / IDLE_RPG_DAILY_STAT_POINT_LIMIT));
}

function getIdleRpgBestStageReached() {
  const savedStage = Math.min(IDLE_RPG_MAX_MONSTER, idleRpgState.bestKills + 1);
  const currentStage = idleRpgRun ? idleRpgRun.monster.index + 1 : 1;
  return Math.min(IDLE_RPG_MAX_MONSTER, Math.max(1, savedStage, currentStage));
}

function getIdleRpgHeroMaxHp() {
  return 30 + idleRpgState.stats.vitality * 2 + idleRpgState.upgrades.armor;
}

function getIdleRpgHeroAttack() {
  return 2 + idleRpgState.stats.strength * 1.5 + idleRpgState.upgrades.weapon;
}

function getIdleRpgBlockDamage() {
  return idleRpgState.stats.strength
    + idleRpgState.stats.vitality
    + idleRpgState.stats.agility;
}

function getIdleRpgDodgeChance() {
  return Math.min(0.25, idleRpgState.stats.agility * 0.01);
}

function getIdleRpgCritChance() {
  return Math.min(0.25, idleRpgState.stats.luck * 0.01);
}

function getIdleRpgFireDamage() {
  if (idleRpgState.upgrades.fire <= 0) return 0;
  return idleRpgState.upgrades.fire * 2 + idleRpgState.stats.intellect * 2.5;
}

function getIdleRpgSurgeDamage() {
  return idleRpgState.upgrades.surge;
}

function getIdleRpgFloodSlow() {
  return Math.min(IDLE_RPG_MAX_SLOW, idleRpgState.upgrades.flood * 0.01);
}

function getIdleRpgMonsterAttackIntervalRange(index) {
  const levelProgress = Math.max(0, Math.min(1, index / (IDLE_RPG_MAX_MONSTER - 1)));
  return {
    minMs: Math.round(
      IDLE_RPG_MONSTER_LEVEL_1_ATTACK_MIN_MS
      + (IDLE_RPG_MONSTER_LEVEL_100_ATTACK_MIN_MS - IDLE_RPG_MONSTER_LEVEL_1_ATTACK_MIN_MS) * levelProgress,
    ),
    maxMs: Math.round(
      IDLE_RPG_MONSTER_LEVEL_1_ATTACK_MAX_MS
      + (IDLE_RPG_MONSTER_LEVEL_100_ATTACK_MAX_MS - IDLE_RPG_MONSTER_LEVEL_1_ATTACK_MAX_MS) * levelProgress,
    ),
  };
}

function rollIdleRpgMonsterAttackDelay(monster) {
  const range = getIdleRpgMonsterAttackIntervalRange(monster.index);
  const baseDelay = range.minMs + Math.random() * (range.maxMs - range.minMs);
  const attackSpeedMultiplier = Math.max(1 - getIdleRpgFloodSlow(), 0.2);
  return Math.round(baseDelay / attackSpeedMultiplier);
}

function getIdleRpgMonsterAttackWindup(monster) {
  const levelProgress = Math.max(0, Math.min(1, monster.index / (IDLE_RPG_MAX_MONSTER - 1)));
  const baseWindup = IDLE_RPG_MONSTER_LEVEL_1_WINDUP_MS
    + (IDLE_RPG_MONSTER_LEVEL_100_WINDUP_MS - IDLE_RPG_MONSTER_LEVEL_1_WINDUP_MS) * levelProgress;
  const attackSpeedMultiplier = Math.max(1 - getIdleRpgFloodSlow(), 0.2);
  return Math.round(baseWindup / attackSpeedMultiplier);
}

function getIdleRpgUltimateDamage() {
  if (idleRpgState.upgrades.ultimate <= 0) return 0;
  return idleRpgState.upgrades.ultimate * 100
    + idleRpgState.upgrades.weapon
    + idleRpgState.stats.strength
    + idleRpgState.stats.intellect;
}

function getIdleRpgUpgradeCost(upgrade) {
  if (upgrade.costMultiplier) {
    return Math.round(upgrade.baseCost * upgrade.costMultiplier ** idleRpgState.upgrades[upgrade.key]);
  }
  return upgrade.baseCost + upgrade.costPerLevel * idleRpgState.upgrades[upgrade.key];
}

function isIdleRpgBossIndex(index) {
  return (index + 1) % IDLE_RPG_BOSS_EVERY === 0;
}

function createIdleRpgMonster(index, pendingDamage = 0) {
  const boss = isIdleRpgBossIndex(index);
  const hpMultiplier = boss ? IDLE_RPG_BOSS_HP_MULTIPLIER : 1;
  const attackMultiplier = boss ? IDLE_RPG_BOSS_ATTACK_MULTIPLIER : 1;
  const maxHp = Math.round(50 * IDLE_RPG_MONSTER_HP_GROWTH ** index * hpMultiplier);
  return {
    index,
    boss,
    maxHp,
    hp: Math.max(1, maxHp - Math.round(pendingDamage)),
    attack: 6.5 * 1.0044 ** index * attackMultiplier,
    sprite: boss ? IDLE_RPG_BOSS_SPRITE : IDLE_RPG_MONSTER_SPRITE,
    attackSprite: boss ? IDLE_RPG_BOSS_ATTACK_SPRITE : IDLE_RPG_MONSTER_ATTACK_SPRITE,
  };
}

function getIdleRpgMonsterReward(monster) {
  if (monster.boss) return 3;
  return Math.random() < 0.5 ? 1 : 0;
}

function formatIdleRpgNumber(value) {
  return Math.round(value).toLocaleString("pl-PL");
}

function setIdleRpgLog(message) {
  idleRpgElements.log.textContent = message;
}

function clearIdleRpgPendingMonsterAttack() {
  const pendingAttack = idleRpgPendingMonsterAttack;
  if (idleRpgPendingMonsterAttack?.timerId != null) {
    globalThis.clearTimeout(idleRpgPendingMonsterAttack.timerId);
  }
  idleRpgPendingMonsterAttack = null;
  idleRpgElements.heroButton?.classList.remove("idle-rpg-fighter--block-window");
  idleRpgElements.heroButton?.style.removeProperty("--idle-rpg-attack-duration");
  idleRpgElements.monsterSprite?.classList.remove(
    "idle-rpg-sprite--attacking",
    "idle-rpg-sprite--lunge-left",
  );
  idleRpgElements.monsterSprite?.style.removeProperty("--idle-rpg-attack-duration");
  if (pendingAttack?.monster && idleRpgRun?.monster === pendingAttack.monster) {
    idleRpgElements.monsterSprite.textContent = pendingAttack.monster.sprite;
  }
}

function clearIdleRpgMonsterAttackTimer() {
  if (idleRpgMonsterAttackTimer !== null) {
    globalThis.clearTimeout(idleRpgMonsterAttackTimer);
  }
  idleRpgMonsterAttackTimer = null;
}

function scheduleIdleRpgMonsterAttack() {
  clearIdleRpgMonsterAttackTimer();
  const run = idleRpgRun;
  const monster = run?.monster;
  if (!run || !monster || monster.hp <= 0 || run.heroHp <= 0) return;
  const delay = rollIdleRpgMonsterAttackDelay(monster);
  idleRpgMonsterAttackTimer = globalThis.setTimeout(() => {
    idleRpgMonsterAttackTimer = null;
    if (
      idleRpgRun !== run
      || run.monster !== monster
      || monster.hp <= 0
      || run.heroHp <= 0
      || idleRpgPendingMonsterAttack
    ) return;
    performIdleRpgMonsterAttack();
  }, delay);
}

function updateIdleRpgBlockCooldown() {
  if (!idleRpgElements.heroButton) return;
  const remainingMs = Math.max(0, idleRpgBlockCooldownUntil - Date.now());
  const coolingDown = remainingMs > 0;
  idleRpgElements.heroButton.classList.toggle("idle-rpg-fighter--block-cooldown", coolingDown);
  idleRpgElements.heroButton.setAttribute("aria-disabled", String(coolingDown));
  idleRpgElements.heroButton.removeAttribute("title");
}

function startIdleRpgExpedition() {
  clearIdleRpgPendingMonsterAttack();
  clearIdleRpgMonsterAttackTimer();
  idleRpgRun = {
    heroHp: getIdleRpgHeroMaxHp(),
    kills: 0,
    coinsEarned: 0,
    blockStreak: 0,
    skillBlockStreak: 0,
    pendingSurge: {},
    monster: createIdleRpgMonster(0),
  };
  idleRpgHeroAttackProgress = IDLE_RPG_ATTACK_INTERVAL_TICKS;
  scheduleIdleRpgMonsterAttack();
  setIdleRpgLog("Heros w garniturze rusza w drogę…");
}

function spawnIdleRpgFloat(text, modifier, side) {
  const battle = idleRpgElements.battle;
  if (!battle || battle.querySelectorAll(".idle-rpg-float").length >= IDLE_RPG_MAX_FLOATS) return;
  const float = document.createElement("span");
  float.className = `idle-rpg-float idle-rpg-float--${modifier}`;
  float.textContent = text;
  float.style.left = `${(side === "monster" ? 64 : 14) + Math.random() * 16}%`;
  float.setAttribute("aria-hidden", "true");
  float.addEventListener("animationend", () => float.remove(), { once: true });
  battle.append(float);
}

function spawnIdleRpgProjectile(kind) {
  const battle = idleRpgElements.battle;
  if (!battle || battle.querySelectorAll(".idle-rpg-projectile").length >= 6) return;
  const projectile = document.createElement("span");
  projectile.className = `idle-rpg-projectile idle-rpg-projectile--${kind}`;
  projectile.textContent = kind === "surge" ? "⚡" : "";
  projectile.setAttribute("aria-hidden", "true");
  projectile.addEventListener("animationend", () => projectile.remove(), { once: true });
  battle.append(projectile);
}

function restartIdleRpgSpriteAnimation(element, className) {
  element.classList.remove("idle-rpg-sprite--hit", "idle-rpg-sprite--lunge-right", "idle-rpg-sprite--lunge-left");
  void element.offsetWidth;
  element.classList.add(className);
}

function flashRecordCounterPlusOne(count = 1) {
  const counter = idleRpgElements.counter;
  if (!counter || globalThis.matchMedia?.("(prefers-reduced-motion: reduce)").matches) return;
  counter.querySelector(".record-counter__plus")?.remove();
  const plus = document.createElement("span");
  plus.className = "record-counter__plus";
  plus.textContent = `+${Math.max(1, Number(count) || 1)}`;
  plus.setAttribute("aria-hidden", "true");
  plus.addEventListener("animationend", () => plus.remove(), { once: true });
  counter.append(plus);
}

function handleIdleRpgVictory() {
  const run = idleRpgRun;
  clearIdleRpgPendingMonsterAttack();
  clearIdleRpgMonsterAttackTimer();
  idleRpgState.victories += 1;
  idleRpgState.bestKills = IDLE_RPG_MAX_MONSTER;
  setIdleRpgLog(`🏆 OSTATNIE Wyłączenie Generalne pokonane! Gra ukończona (zwycięstwa: ${formatIdleRpgNumber(idleRpgState.victories)}). Wyprawa rusza od nowa…`);
  run.pendingSurge = {};
  run.blockStreak = 0;
  run.skillBlockStreak = 0;
  run.heroHp = getIdleRpgHeroMaxHp();
  run.monster = createIdleRpgMonster(0);
  scheduleIdleRpgMonsterAttack();
  saveIdleRpgState();
  renderIdleRpgMeta();
}

function handleIdleRpgMonsterDefeated() {
  const run = idleRpgRun;
  const monster = run.monster;
  clearIdleRpgPendingMonsterAttack();
  const reward = getIdleRpgMonsterReward(monster);
  idleRpgState.coins += reward;
  idleRpgState.totalKills += 1;
  run.kills += 1;
  idleRpgState.bestKills = Math.min(IDLE_RPG_MAX_MONSTER, Math.max(idleRpgState.bestKills, run.kills));
  run.coinsEarned += reward;
  if (reward > 0) spawnIdleRpgFloat(`+${formatIdleRpgNumber(reward)} 🪙`, "coin", "monster");
  if (monster.index >= IDLE_RPG_MAX_MONSTER - 1) {
    handleIdleRpgVictory();
    renderIdleRpgShop();
    return;
  }
  if (monster.boss) setIdleRpgLog("Wyłączenie Generalne pokonane! Wielki łup!");
  const nextIndex = monster.index + 1;
  const pendingDamage = run.pendingSurge[nextIndex] || 0;
  delete run.pendingSurge[nextIndex];
  run.monster = createIdleRpgMonster(nextIndex, pendingDamage);
  scheduleIdleRpgMonsterAttack();
  if (pendingDamage > 0) spawnIdleRpgFloat(`⚡ -${formatIdleRpgNumber(pendingDamage)}`, "surge", "monster");
  if (run.kills % 5 === 0) saveIdleRpgState();
  renderIdleRpgMeta();
  renderIdleRpgShop();
}

function damageIdleRpgMonster(amount, kind) {
  if (!idleRpgRun || idleRpgRun.monster.hp <= 0) return;
  const damage = Math.max(0, Math.round(amount));
  if (damage <= 0) return;
  idleRpgRun.monster.hp -= damage;
  spawnIdleRpgFloat(`-${formatIdleRpgNumber(damage)}`, kind, "monster");
  restartIdleRpgSpriteAnimation(idleRpgElements.monsterSprite, "idle-rpg-sprite--hit");
  if (idleRpgRun.monster.hp <= 0) handleIdleRpgMonsterDefeated();
}

function handleIdleRpgHeroDefeated() {
  const run = idleRpgRun;
  clearIdleRpgPendingMonsterAttack();
  clearIdleRpgMonsterAttackTimer();
  idleRpgState.expeditions += 1;
  idleRpgState.bestKills = Math.min(IDLE_RPG_MAX_MONSTER, Math.max(idleRpgState.bestKills, run.kills));
  const opponent = run.monster.boss
    ? "Wyłączeniu Generalnym"
    : `Wyłączeniach ${formatIdleRpgNumber(run.monster.index + 1)}`;
  setIdleRpgLog(`💀 Heros poległ na ${opponent}. Łup z wyprawy: ${formatIdleRpgNumber(run.coinsEarned)} 🪙`);
  idleRpgRun = null;
  idleRpgRespawnCountdown = IDLE_RPG_RESPAWN_TICKS;
  saveIdleRpgState();
  renderIdleRpgMeta();
  renderIdleRpgShop();
}

function performIdleRpgHeroAttack() {
  restartIdleRpgSpriteAnimation(idleRpgElements.heroSprite, "idle-rpg-sprite--lunge-right");
  const critical = Math.random() < getIdleRpgCritChance();
  const attack = getIdleRpgHeroAttack() * (0.85 + Math.random() * 0.3) * (critical ? 2 : 1);
  if (critical) setIdleRpgLog("Krytyczne trafienie!");
  damageIdleRpgMonster(attack, critical ? "crit" : "hit");
}

function performIdleRpgMonsterAttack() {
  const run = idleRpgRun;
  if (!run || idleRpgPendingMonsterAttack) return;
  const monster = run.monster;
  const attackWindupMs = getIdleRpgMonsterAttackWindup(monster);
  idleRpgElements.monsterSprite.textContent = monster.attackSprite;
  idleRpgElements.monsterSprite.classList.add("idle-rpg-sprite--attacking");
  idleRpgElements.monsterSprite.style.setProperty("--idle-rpg-attack-duration", `${attackWindupMs}ms`);
  restartIdleRpgSpriteAnimation(idleRpgElements.monsterSprite, "idle-rpg-sprite--lunge-left");
  idleRpgElements.heroButton?.classList.add("idle-rpg-fighter--block-window");
  idleRpgElements.heroButton?.style.setProperty("--idle-rpg-attack-duration", `${attackWindupMs}ms`);
  const pendingAttack = {
    run,
    monster,
    blocked: false,
    timerId: null,
  };
  idleRpgPendingMonsterAttack = pendingAttack;
  pendingAttack.timerId = globalThis.setTimeout(() => {
    if (idleRpgPendingMonsterAttack !== pendingAttack) return;
    idleRpgPendingMonsterAttack = null;
    idleRpgElements.heroButton?.classList.remove("idle-rpg-fighter--block-window");
    idleRpgElements.heroButton?.style.removeProperty("--idle-rpg-attack-duration");
    idleRpgElements.monsterSprite?.classList.remove(
      "idle-rpg-sprite--attacking",
      "idle-rpg-sprite--lunge-left",
    );
    idleRpgElements.monsterSprite?.style.removeProperty("--idle-rpg-attack-duration");
    idleRpgElements.monsterSprite.textContent = monster.sprite;
    if (idleRpgRun !== run || run.monster !== monster || monster.hp <= 0 || run.heroHp <= 0) return;
    const blockedBossAttack = pendingAttack.blocked && monster.boss;
    if (pendingAttack.blocked && !blockedBossAttack) {
      scheduleIdleRpgMonsterAttack();
      return;
    }
    if (!blockedBossAttack) {
      run.blockStreak = 0;
      run.skillBlockStreak = 0;
    }
    if (!blockedBossAttack && Math.random() < getIdleRpgDodgeChance()) {
      spawnIdleRpgFloat("unik!", "dodge", "hero");
      scheduleIdleRpgMonsterAttack();
      return;
    }
    const rolledDamage = Math.max(1, Math.round(monster.attack * (0.85 + Math.random() * 0.3)));
    const damage = blockedBossAttack ? Math.max(1, Math.round(rolledDamage / 2)) : rolledDamage;
    run.heroHp -= damage;
    spawnIdleRpgFloat(`-${formatIdleRpgNumber(damage)}`, "hurt", "hero");
    if (blockedBossAttack) {
      setIdleRpgLog(`Blok osłabił atak bossa o połowę. Otrzymano ${formatIdleRpgNumber(damage)} obrażeń.`);
    }
    restartIdleRpgSpriteAnimation(idleRpgElements.heroSprite, "idle-rpg-sprite--hit");
    if (run.heroHp <= 0) handleIdleRpgHeroDefeated();
    else scheduleIdleRpgMonsterAttack();
    updateIdleRpgScene();
  }, attackWindupMs);
}

function idleRpgTick() {
  if (!idleRpgState) return;
  if (!idleRpgRun) {
    idleRpgRespawnCountdown -= 1;
    if (idleRpgRespawnCountdown <= 0) startIdleRpgExpedition();
    updateIdleRpgScene();
    return;
  }

  idleRpgHeroAttackProgress += 1;
  if (idleRpgHeroAttackProgress >= IDLE_RPG_ACTOR_ATTACK_CYCLE_TICKS) {
    idleRpgHeroAttackProgress -= IDLE_RPG_ACTOR_ATTACK_CYCLE_TICKS;
    performIdleRpgHeroAttack();
  }

  updateIdleRpgScene();
}

function updateIdleRpgScene() {
  const maxHp = getIdleRpgHeroMaxHp();
  idleRpgElements.heroSprite.textContent = idleRpgRun ? IDLE_RPG_HERO_SPRITE : "💀";
  if (idleRpgRun) {
    const monster = idleRpgRun.monster;
    const monsterIsAttacking = idleRpgPendingMonsterAttack?.monster === monster;
    idleRpgElements.zone.textContent = IDLE_RPG_ZONES[Math.floor(monster.index / IDLE_RPG_BOSS_EVERY) % IDLE_RPG_ZONES.length];
    idleRpgElements.distance.textContent = monster.boss
      ? `⚠ Wyłączenie Generalne! ${formatIdleRpgNumber(monster.index + 1)}`
      : `Wyłączenia ${formatIdleRpgNumber(monster.index + 1)}`;
    idleRpgElements.monsterSprite.textContent = monsterIsAttacking ? monster.attackSprite : monster.sprite;
    idleRpgElements.monsterSprite.classList.toggle("idle-rpg-sprite--boss", monster.boss);
    idleRpgElements.monsterSprite.classList.toggle("idle-rpg-sprite--attacking", monsterIsAttacking);
    idleRpgElements.monsterHp.style.width = `${Math.max(0, (monster.hp / monster.maxHp) * 100)}%`;
    idleRpgElements.monsterHpLabel.textContent = `${formatIdleRpgNumber(Math.max(0, monster.hp))}/${formatIdleRpgNumber(monster.maxHp)}`;
    idleRpgElements.heroHp.style.width = `${Math.max(0, (idleRpgRun.heroHp / maxHp) * 100)}%`;
    idleRpgElements.heroHpLabel.textContent = `${formatIdleRpgNumber(Math.max(0, idleRpgRun.heroHp))}/${formatIdleRpgNumber(maxHp)}`;
  } else {
    idleRpgElements.monsterSprite.textContent = "⏳";
    idleRpgElements.monsterSprite.classList.remove("idle-rpg-sprite--boss");
    idleRpgElements.monsterHp.style.width = "0%";
    idleRpgElements.monsterHpLabel.textContent = "-";
    idleRpgElements.heroHp.style.width = "0%";
    idleRpgElements.heroHpLabel.textContent = `0/${formatIdleRpgNumber(maxHp)}`;
  }
  idleRpgElements.coins.textContent = formatIdleRpgNumber(idleRpgState.coins);
  updateIdleRpgBlockCooldown();
}

function renderIdleRpgMeta() {
  idleRpgElements.level.textContent = `Poziom: ${formatIdleRpgNumber(getIdleRpgCharacterLevel())}`;
  idleRpgElements.bestStage.textContent = `Maks. etap: ${formatIdleRpgNumber(getIdleRpgBestStageReached())}`;
}

function renderIdleRpgStats() {
  const freePoints = getIdleRpgFreePoints();
  idleRpgElements.freePoints.textContent = `wolne punkty: ${formatIdleRpgNumber(freePoints)}`;
  idleRpgElements.stats.innerHTML = IDLE_RPG_STATS.map((stat) => `
    <div class="idle-rpg-row">
      <span class="idle-rpg-row__icon" aria-hidden="true">${stat.icon}</span>
      <span class="idle-rpg-row__info">
        <strong><span>${stat.label}</span><b>${formatIdleRpgNumber(idleRpgState.stats[stat.key])}</b></strong>
        <small>${stat.description}</small>
      </span>
      <button type="button" class="idle-rpg-row__button" data-idle-rpg-stat="${stat.key}" ${freePoints > 0 ? "" : "disabled"} aria-label="Zwiększ: ${stat.label}">+</button>
    </div>
  `).join("");
}

function renderIdleRpgShop() {
  idleRpgElements.shop.innerHTML = IDLE_RPG_UPGRADES.map((upgrade) => {
    const level = idleRpgState.upgrades[upgrade.key];
    const cost = getIdleRpgUpgradeCost(upgrade);
    return `
      <div class="idle-rpg-row">
        <span class="idle-rpg-row__icon" aria-hidden="true">${upgrade.icon}</span>
        <span class="idle-rpg-row__info">
          <strong><span>${upgrade.label}</span><b>poz. ${formatIdleRpgNumber(level)}</b></strong>
          <small>${upgrade.description}</small>
        </span>
        <button type="button" class="idle-rpg-row__button idle-rpg-row__button--buy" data-idle-rpg-upgrade="${upgrade.key}" ${idleRpgState.coins < cost ? "disabled" : ""} aria-label="Kup ulepszenie: ${upgrade.label}">${formatIdleRpgNumber(cost)} 🪙</button>
      </div>
    `;
  }).join("");
}

function openIdleRpg() {
  const dialog = idleRpgElements.dialog;
  if (!dialog) {
    showToast("Nie udało się otworzyć gry. Odśwież aplikację.", "error");
    return;
  }
  try {
    if (!dialog.open) dialog.showModal();
    if (!idleRpgState) {
      idleRpgState = loadIdleRpgState();
      saveIdleRpgState();
      try {
        globalThis.localStorage?.removeItem(IDLE_RPG_SAVE_KEY);
      } catch {
      }
    }
    const grantedPoints = grantIdleRpgDailyStatPoints();
    if (!idleRpgRun) {
      idleRpgRespawnCountdown = 0;
      startIdleRpgExpedition();
    } else if (idleRpgMonsterAttackTimer === null && !idleRpgPendingMonsterAttack) {
      scheduleIdleRpgMonsterAttack();
    }
    if (grantedPoints > 0) {
      setIdleRpgLog(`🎁 +${formatIdleRpgNumber(grantedPoints)} pkt statystyk za polisy dodane dzisiaj!`);
    }
    renderIdleRpgMeta();
    renderIdleRpgStats();
    renderIdleRpgShop();
    updateIdleRpgScene();
    if (idleRpgTimer === null) idleRpgTimer = globalThis.setInterval(idleRpgTick, IDLE_RPG_TICK_MS);
  } catch (error) {
    console.error("Nie udało się otworzyć gry Polisowy Heros", error);
    if (dialog.open) dialog.close();
    showToast("Nie udało się otworzyć gry. Odśwież aplikację i spróbuj ponownie.", "error");
  }
}

idleRpgElements.counter?.addEventListener("click", openIdleRpg);

idleRpgElements.close?.addEventListener("click", () => idleRpgElements.dialog.close());

idleRpgElements.dialog?.addEventListener("close", () => {
  clearIdleRpgPendingMonsterAttack();
  clearIdleRpgMonsterAttackTimer();
  if (idleRpgTimer !== null) {
    globalThis.clearInterval(idleRpgTimer);
    idleRpgTimer = null;
  }
  saveIdleRpgState();
  if (idleRpgSettingsPersistTimer !== null) {
    globalThis.clearTimeout(idleRpgSettingsPersistTimer);
    idleRpgSettingsPersistTimer = null;
  }
  void persistIdleRpgToSettingsFile();
});

idleRpgElements.heroButton?.addEventListener("click", () => {
  if (!idleRpgState || !idleRpgRun || Date.now() < idleRpgBlockCooldownUntil) return;
  idleRpgBlockCooldownUntil = Date.now() + IDLE_RPG_BLOCK_COOLDOWN_MS;
  updateIdleRpgBlockCooldown();
  const pendingAttack = idleRpgPendingMonsterAttack;
  if (
    !pendingAttack
    || pendingAttack.blocked
    || idleRpgRun !== pendingAttack.run
    || idleRpgRun.monster !== pendingAttack.monster
  ) {
    idleRpgRun.blockStreak = 0;
    idleRpgRun.skillBlockStreak = 0;
    spawnIdleRpgFloat("za wcześnie!", "cooldown", "hero");
    return;
  }
  pendingAttack.blocked = true;
  const nextBlockInStreak = (idleRpgRun.blockStreak || 0) + 1;
  const superBlock = nextBlockInStreak >= IDLE_RPG_SUPER_BLOCK_STREAK;
  idleRpgRun.blockStreak = superBlock ? 0 : nextBlockInStreak;
  idleRpgRun.skillBlockStreak = (idleRpgRun.skillBlockStreak || 0) + 1;
  idleRpgBlockCooldownUntil = 0;
  updateIdleRpgBlockCooldown();

  const baseDamage = getIdleRpgBlockDamage();
  const blockDamage = baseDamage * (superBlock ? IDLE_RPG_SUPER_BLOCK_MULTIPLIER : 1);
  const skillStreak = idleRpgRun.skillBlockStreak;
  const monsterIndex = idleRpgRun.monster.index;
  const fireDamage = skillStreak % 5 === 0 ? getIdleRpgFireDamage() : 0;
  const surgeDamage = skillStreak % 3 === 0 ? getIdleRpgSurgeDamage() : 0;
  const ultimateDamage = skillStreak % IDLE_RPG_ULTIMATE_BLOCK_STREAK === 0
    ? getIdleRpgUltimateDamage()
    : 0;
  const effectMessages = [];

  if (fireDamage > 0) {
    spawnIdleRpgProjectile("fire");
    effectMessages.push(`🔥 Pożar: +${formatIdleRpgNumber(fireDamage)}`);
  }
  if (surgeDamage > 0) {
    spawnIdleRpgProjectile("surge");
    effectMessages.push(`⚡ Przepięcie: +${formatIdleRpgNumber(surgeDamage)} i 3 kolejne cele`);
    for (let offset = 1; offset <= IDLE_RPG_SURGE_TARGETS; offset += 1) {
      const targetIndex = monsterIndex + offset;
      if (targetIndex >= IDLE_RPG_MAX_MONSTER) break;
      idleRpgRun.pendingSurge[targetIndex] = (idleRpgRun.pendingSurge[targetIndex] || 0) + surgeDamage;
    }
  }
  if (ultimateDamage > 0) {
    spawnIdleRpgFloat("🖋️ SPRZEDANE!", "ult", "monster");
    effectMessages.push(`🖋️ Polisa życiowa: +${formatIdleRpgNumber(ultimateDamage)}`);
  }

  const blockMessage = superBlock
    ? `SUPER BLOK! Kontra zadała ${formatIdleRpgNumber(blockDamage)} obrażeń.`
    : `Skuteczny blok! Kontra zadała ${formatIdleRpgNumber(blockDamage)} obrażeń.`;
  if (superBlock) {
    spawnIdleRpgFloat("🛡️ SUPER BLOK! ×2", "super-block", "hero");
  } else {
    spawnIdleRpgFloat(`🛡️ BLOK ${nextBlockInStreak}/${IDLE_RPG_SUPER_BLOCK_STREAK}`, "block", "hero");
  }
  setIdleRpgLog([
    blockMessage,
    `Seria skilli: ${formatIdleRpgNumber(skillStreak)}.`,
    ...effectMessages,
  ].join(" • "));
  const totalDamage = blockDamage + fireDamage + surgeDamage + ultimateDamage;
  const damageKind = ultimateDamage > 0
    ? "ult"
    : fireDamage > 0
      ? "fire"
      : surgeDamage > 0
        ? "surge"
        : superBlock
          ? "super-block"
          : "block";
  damageIdleRpgMonster(totalDamage, damageKind);
  updateIdleRpgScene();
});

idleRpgElements.stats?.addEventListener("click", (event) => {
  const statKey = event.target.closest("[data-idle-rpg-stat]")?.dataset.idleRpgStat;
  if (!statKey || !idleRpgState || getIdleRpgFreePoints() <= 0) return;
  idleRpgState.stats[statKey] += 1;
  saveIdleRpgState();
  renderIdleRpgStats();
  renderIdleRpgMeta();
  updateIdleRpgScene();
});

idleRpgElements.shop?.addEventListener("click", (event) => {
  const upgradeKey = event.target.closest("[data-idle-rpg-upgrade]")?.dataset.idleRpgUpgrade;
  const upgrade = IDLE_RPG_UPGRADES.find((item) => item.key === upgradeKey);
  if (!upgrade || !idleRpgState) return;
  const cost = getIdleRpgUpgradeCost(upgrade);
  if (idleRpgState.coins < cost) return;
  idleRpgState.coins -= cost;
  idleRpgState.upgrades[upgrade.key] += 1;
  saveIdleRpgState();
  renderIdleRpgShop();
  updateIdleRpgScene();
});

globalThis.addEventListener("beforeunload", () => {
  if (!idleRpgState) return;
  saveIdleRpgState();
  void persistIdleRpgToSettingsFile();
});














const portfolioImportElements = {
  launcherCard: document.querySelector("#portfolioImportLauncher"),
  launcher: document.querySelector("#openPortfolioImportDialog"),
  credentialsButton: document.querySelector("#scrollToCalculatorCredentials"),
  credentialsStart: document.querySelector("#calculatorCredentialsStart"),
  dialog: document.querySelector("#portfolioImportDialog"),
  close: document.querySelector("#closePortfolioImport"),
  minimize: document.querySelector("#minimizePortfolioImport"),
  intro: document.querySelector("#portfolioImportIntro"),
  list: document.querySelector("#portfolioImportList"),
  empty: document.querySelector("#portfolioImportEmpty"),
  downloadPdfs: document.querySelector("#portfolioImportDownloadPdfs"),
  fullReimport: document.querySelector("#portfolioImportFullReimport"),
  totals: document.querySelector("#portfolioImportTotals"),
  totalFetched: document.querySelector("#portfolioImportTotalFetched"),
  totalAdded: document.querySelector("#portfolioImportTotalAdded"),
  totalEnriched: document.querySelector("#portfolioImportTotalEnriched"),
  totalPdf: document.querySelector("#portfolioImportTotalPdf"),
  status: document.querySelector("#portfolioImportStatus"),
  start: document.querySelector("#startPortfolioImport"),
  mini: document.querySelector("#portfolioImportMini"),
  miniArc: document.querySelector("#portfolioImportMiniArc"),
  miniPercent: document.querySelector("#portfolioImportMiniPercent"),
  miniDetail: document.querySelector("#portfolioImportMiniDetail"),
  miniAlert: document.querySelector("#portfolioImportMiniAlert"),
  reportDialog: document.querySelector("#portfolioImportReportDialog"),
  reportAdded: document.querySelector("#portfolioImportReportAdded"),
  reportEnriched: document.querySelector("#portfolioImportReportEnriched"),
  reportPdfs: document.querySelector("#portfolioImportReportPdfs"),
  reportRows: document.querySelector("#portfolioImportReportRows"),
  reportWarning: document.querySelector("#portfolioImportReportWarning"),
  closeReport: document.querySelector("#closePortfolioImportReport"),
  confirmReport: document.querySelector("#confirmPortfolioImportReport"),
};



const PORTFOLIO_IMPORT_WARTA_RECORD_KEY = "bazaPolis.importWartaRecord";
const PORTFOLIO_IMPORT_MINI_ARC_LENGTH = 125.66;


const PORTFOLIO_IMPORT_START_TIMEOUT = 20_000;




const PORTFOLIO_IMPORT_IDLE_TIMEOUT = 15_000;
const PORTFOLIO_IMPORT_IDLE_POLL = 3_000;




const PORTFOLIO_IMPORT_TARGETS = [
  {
    key: "pzu",
    label: "PZU",
    insurerId: "pzu",
    start: (options = {}) => startPzuPortfolioImport(options),
    openLogin: () => startPzuPortfolioOpen(),
    pdfCheckboxKey: "pzuPortfolioDownloadPdfs",
    statusKey: "pzuPortfolioImportStatus",
    buttonKey: "pzuPortfolioImportButton",
  },
  {
    key: "insly",
    label: "Superpolisa (Insly)",
    insurerId: "",
    start: (options = {}) => startInslyPortfolioImport(options),
    openLogin: () => startInslyPortfolioOpen(),
    pdfCheckboxKey: "inslyPortfolioDownloadPdfs",
    statusKey: "inslyPortfolioImportStatus",
    buttonKey: "inslyPortfolioImportButton",
  },
  {
    key: "hestia",
    label: "Ergo Hestia",
    insurerId: "hestia",
    hasCredentials: hasHestiaCredentials,
    start: (options = {}) => startHestiaPortfolioImport(options),
    manualRepair: () => repairHestiaPortfolioImportManually(),
    pdfCheckboxKey: "hestiaPortfolioDownloadPdfs",
    statusKey: "hestiaPortfolioImportStatus",
    buttonKey: "hestiaPortfolioImportButton",
  },
  {
    key: "mtu",
    label: "MTU",
    insurerId: "mtu",
    hasCredentials: hasMtuCredentials,
    start: (options = {}) => startMtuPortfolioImport(options),
    manualRepair: () => repairMtuPortfolioImportManually(),
    pdfCheckboxKey: "mtuPortfolioDownloadPdfs",
    statusKey: "mtuPortfolioImportStatus",
    buttonKey: "mtuPortfolioImportButton",
  },
  {
    key: "warta",
    label: "Warta",
    insurerId: "warta",
    hasCredentials: hasWartaCredentials,
    start: (options = {}) => startWartaPortfolioImportForRun(options),
    pdfCheckboxKey: "wartaPortfolioDownloadPdfs",
    statusKey: "wartaPortfolioImportStatus",
    buttonKey: "wartaPortfolioImportButton",
  },
  {
    key: "generali",
    label: "Generali",
    insurerId: "generali",
    hasCredentials: hasGeneraliCredentials,
    start: (options = {}) => startGeneraliPortfolioImport(options),
    manualRepair: () => repairGeneraliPortfolioImportManually(),
    pdfCheckboxKey: "generaliPortfolioDownloadPdfs",
    statusKey: "generaliPortfolioImportStatus",
    buttonKey: "generaliPortfolioImportButton",
  },
  {
    key: "trasti",
    label: "Trasti",
    insurerId: "trasti",
    hasCredentials: hasTrastiCredentials,
    start: (options = {}) => startTrastiPortfolioImport(options),
    manualRepair: () => repairTrastiPortfolioImportManually(),
    pdfCheckboxKey: "trastiPortfolioDownloadPdfs",
    statusKey: "trastiPortfolioImportStatus",
    buttonKey: "trastiPortfolioImportButton",
  },
  {
    key: "wiener",
    label: "Wiener",
    insurerId: "wiener",
    hasCredentials: hasWienerCredentials,
    start: (options = {}) => startWienerPortfolioImport(options),
    manualRepair: () => repairWienerPortfolioImportManually(),
    pdfCheckboxKey: "wienerPortfolioDownloadPdfs",
    statusKey: "wienerPortfolioImportStatus",
    buttonKey: "wienerPortfolioImportButton",
  },
  {
    key: "compensa",
    label: "Compensa",
    insurerId: "compensa",
    hasCredentials: hasCompensaCredentials,
    start: (options = {}) => startCompensaPortfolioImport(options),
    manualRepair: () => repairCompensaPortfolioImportManually(),
    pdfCheckboxKey: "compensaPortfolioDownloadPdfs",
    statusKey: "compensaPortfolioImportStatus",
    buttonKey: "compensaPortfolioImportButton",
  },
  {
    key: "allianz",
    label: "Allianz",
    insurerId: "allianz",
    hasCredentials: hasAllianzCredentials,
    start: (options = {}) => startAllianzPortfolioImport(options),
    manualRepair: () => repairAllianzPortfolioImportManually(),
    pdfCheckboxKey: "allianzPortfolioDownloadPdfs",
    statusKey: "allianzPortfolioImportStatus",
    buttonKey: "allianzPortfolioImportButton",
  },
];



const PORTFOLIO_IMPORT_PHASE_RANGES = {
  start: [0, 4],
  queued: [2, 4],
  login: [4, 10],
  list: [10, 22],
  save: [22, 25],
  pdf: [26, 99],
};

let portfolioImportRun = null;

function createPortfolioImportEntry(target) {
  return {
    key: target.key,
    label: target.label,
    state: "pending",
    percent: 0,
    phase: "start",
    phaseTicks: 0,
    jobId: "",
    pdfPeak: 0,
    
    
    counters: { fetched: 0, added: 0, enriched: 0, pdf: 0 },
    displayPdf: 0,
    pdfBatch: 0,
    chainPendingAt: 0,
    action: null,
    
    inputRequest: null,
    message: "",
    resolve: null,
    startTimer: 0,
    idleTimer: 0,
    idleSince: 0,
  };
}

function isPortfolioImportRunActive() {
  return portfolioImportRun?.active === true;
}

function getPortfolioImportEntry(insurerKey) {
  return portfolioImportRun?.entries?.get(String(insurerKey || "")) || null;
}

function getPortfolioImportTarget(insurerKey) {
  return PORTFOLIO_IMPORT_TARGETS.find((target) => target.key === insurerKey) || null;
}

function getAvailablePortfolioImportTargets() {
  if (isEmployeeAccount()) return [];
  return PORTFOLIO_IMPORT_TARGETS.filter((target) => (
    !target.insurerId || isInsurerServed(target.insurerId)
  ));
}






function readPortfolioImportJobCounters(job) {
  const text = `${job?.title || ""} ${job?.detail || ""}`;
  const fetchedMatch = /pobrano\s+(\d+)(?:\s+z\s+(\d+))?\s+polis/i.exec(text)
    || /nowych\s+polis:\s*(\d+)/i.exec(text)
    || /sprawdzono\s+(\d+)(?:\s+z\s+(\d+))?\s+polis/i.exec(text);
  const pdfMatch = /pobieranie\s+pdf[^(]*\((\d+)\s*\/\s*(\d+)\)/i.exec(text)
    || /zapisano\s+(\d+)\s+z\s+(\d+)\s+rozpocz/i.exec(text);
  return {
    fetched: fetchedMatch ? Number(fetchedMatch[1]) || 0 : null,
    fetchedTotal: fetchedMatch && fetchedMatch[2] ? Number(fetchedMatch[2]) || 0 : null,
    pdf: pdfMatch ? Number(pdfMatch[1]) || 0 : null,
    pdfTotal: pdfMatch ? Number(pdfMatch[2]) || 0 : null,
  };
}

function detectPortfolioImportPhase(job) {
  if (!job) return "start";
  if (job.status === "queued") return "queued";
  const text = `${job.title || ""} ${job.detail || ""}`.toLowerCase();
  
  
  const activePdfDownload = /\bpobieranie\s+(?:(?:zaległych|zaleglych|plików|plikow)\s+)?pdf(?:\b|-)/i.test(text)
    && !/(?:pominięte|pominiete|przerwane|odłożone|odlozone|zatrzymane)/i.test(text);
  if (activePdfDownload) return "pdf";
  if (/zapis|scalanie|podpinanie/.test(text)) return "save";
  if (/logowanie|otwieranie|uruchamianie|sms|kod\b|hasł/.test(text)) return "login";
  if (/pobrano|pobieranie|sprawdzono|uzupełniono|lista|rekord|składek/.test(text)) return "list";
  return "login";
}



function creepPortfolioImportRatio(ticks) {
  const safeTicks = Math.max(0, Number(ticks) || 0);
  return 1 - (1 / (1 + (safeTicks / 14)));
}

function computePortfolioImportPercent({ phase, ratio, previous = 0 }) {
  const range = PORTFOLIO_IMPORT_PHASE_RANGES[phase] || PORTFOLIO_IMPORT_PHASE_RANGES.list;
  const clampedRatio = Number.isFinite(ratio) ? Math.min(1, Math.max(0, ratio)) : 0;
  const value = range[0] + ((range[1] - range[0]) * clampedRatio);
  const previousPercent = Math.max(0, Math.min(100, Number(previous) || 0));
  return Math.max(previousPercent, Math.min(99, Math.round(value)));
}

function computePortfolioImportTotalPercent(entries) {
  const list = Array.isArray(entries) ? entries : [...(entries?.values?.() || [])];
  const counted = list.filter((entry) => entry.state !== "skipped");
  if (counted.length === 0) return 0;
  const sum = counted.reduce((total, entry) => total + (Number(entry.percent) || 0), 0);
  return Math.min(100, Math.round(sum / counted.length));
}

function describePortfolioImportCounters({ fetched = 0, added = 0, enriched = 0, pdf = 0 } = {}) {
  const parts = [];
  if (fetched > 0) parts.push(`sprawdzono ${fetched} polis`);
  if (added > 0) parts.push(`dodano ${added}`);
  if (enriched > 0) parts.push(`zaktualizowano ${enriched}`);
  if (pdf > 0) parts.push(`PDF ${pdf}`);
  return parts.join(" · ");
}

function describePortfolioImportEntryProgress(entry) {
  return describePortfolioImportCounters({
    fetched: entry.counters.fetched,
    added: entry.counters.added,
    enriched: entry.counters.enriched,
    pdf: Math.max(entry.counters.pdf, entry.displayPdf),
  });
}



function createPortfolioImportRowMarkup(entry, { selectable }) {
  const progress = describePortfolioImportEntryProgress(entry);
  const statusText = entry.state === "pending" && selectable
    ? "Gotowe do pobrania"
    : progress || entry.message || "Czeka w kolejce…";
  return `
    <div class="portfolio-import-row" data-portfolio-import-row="${escapeHtml(entry.key)}" data-state="${escapeHtml(entry.state)}" data-running="${selectable ? "false" : "true"}">
      <label class="portfolio-import-choice">
        <input
          type="checkbox"
          data-portfolio-import-choice="${escapeHtml(entry.key)}"
          ${entry.state === "skipped" ? "" : "checked"}
          ${selectable ? "" : "disabled"}
        />
        <strong>${escapeHtml(entry.label)}</strong>
      </label>
      <div class="portfolio-import-track">
        <div class="portfolio-import-bar">
          <span class="portfolio-import-bar__fill" style="width: ${entry.percent}%"></span>
        </div>
        <div class="portfolio-import-meta">
          <span class="portfolio-import-meta__counters">${escapeHtml(statusText)}</span>
          <span class="portfolio-import-meta__percent">${entry.percent}%</span>
        </div>
      </div>
    </div>
  `;
}

function renderPortfolioImportList() {
  if (!portfolioImportElements.list) return;
  const entries = [...(portfolioImportRun?.entries?.values() || [])];
  if (entries.length === 0) {
    portfolioImportElements.list.innerHTML = "";
    if (portfolioImportElements.empty) portfolioImportElements.empty.hidden = false;
    return;
  }
  if (portfolioImportElements.empty) portfolioImportElements.empty.hidden = true;
  const selectable = !isPortfolioImportRunActive();
  portfolioImportElements.list.innerHTML = entries
    .map((entry) => createPortfolioImportRowMarkup(entry, { selectable }))
    .join("");
  for (const entry of entries) {
    if (entry.action) updatePortfolioImportRow(entry);
  }
}






function askPortfolioImportChoice(entry, { title, hint, options }) {
  return new Promise((resolve) => {
    if (!entry) {
      resolve("");
      return;
    }
    entry.inputRequest = {
      local: true,
      id: `local-${entry.key}-${options.map((option) => option.value).join("|")}`,
      title,
      hint,
      options,
      resolve,
    };
    refreshPortfolioImportEntry(entry);
  });
}

function renderPortfolioImportInputForm(row, entry) {
  const existing = row.querySelector(".portfolio-import-input");
  const request = entry.inputRequest;
  const fields = Array.isArray(request?.fields) ? request.fields : [];
  const isLocalChoice = request?.local === true && Array.isArray(request.options) && request.options.length > 0;
  if (!request?.id || (!isLocalChoice && (fields.length === 0 || !entry.jobId))) {
    existing?.remove();
    return;
  }
  if (existing?.dataset.requestId === String(request.id)) return;
  existing?.remove();

  if (isLocalChoice) {
    const form = document.createElement("form");
    form.className = "portfolio-import-input";
    form.dataset.requestId = String(request.id);
    const heading = document.createElement("strong");
    heading.textContent = request.title;
    const hint = document.createElement("small");
    hint.textContent = request.hint || "";
    const label = document.createElement("label");
    const caption = document.createElement("span");
    caption.textContent = "Rekord";
    const select = document.createElement("select");
    for (const option of request.options) {
      const optionElement = document.createElement("option");
      optionElement.value = option.value;
      optionElement.textContent = option.label;
      select.append(optionElement);
    }
    label.append(caption, select);
    const buttons = document.createElement("div");
    buttons.className = "portfolio-import-input__buttons";
    const submit = document.createElement("button");
    submit.className = "settings-save-button";
    submit.type = "submit";
    submit.textContent = "Pobierz z tego rekordu";
    buttons.append(submit);
    form.append(heading, hint, label, buttons);
    form.addEventListener("submit", (event) => {
      event.preventDefault();
      const chosen = String(select.value || "");
      entry.inputRequest = null;
      form.remove();
      request.resolve(chosen);
    });
    row.append(form);
    select.focus();
    return;
  }

  const form = document.createElement("form");
  form.className = "portfolio-import-input";
  form.dataset.requestId = String(request.id);
  form.dataset.jobId = String(entry.jobId);
  form.dataset.insurerKey = entry.key;
  const heading = document.createElement("strong");
  heading.textContent = request.title || `${entry.label} prosi o kod`;
  const hint = document.createElement("small");
  hint.textContent = "Przepisz kod z telefonu - import ruszy dalej sam, nic się nie otworzy.";
  form.append(heading, hint);
  for (const field of fields) {
    const label = document.createElement("label");
    const caption = document.createElement("span");
    caption.textContent = field.required ? `${field.label} *` : String(field.label || "");
    const input = document.createElement("input");
    input.type = "text";
    input.dataset.fieldId = field.id;
    input.autocomplete = "one-time-code";
    input.inputMode = "numeric";
    input.value = String(field.currentValue || "");
    label.append(caption, input);
    form.append(label);
  }
  const buttons = document.createElement("div");
  buttons.className = "portfolio-import-input__buttons";
  const submit = document.createElement("button");
  submit.className = "settings-save-button";
  submit.type = "submit";
  submit.textContent = "Wyślij kod";
  const cancel = document.createElement("button");
  cancel.className = "settings-secondary-button";
  cancel.type = "button";
  cancel.textContent = "Pomiń";
  cancel.addEventListener("click", () => { void submitPortfolioImportInput(form, { cancel: true }); });
  buttons.append(submit, cancel);
  form.append(buttons);
  form.addEventListener("submit", (event) => {
    event.preventDefault();
    void submitPortfolioImportInput(form, { cancel: false });
  });
  row.append(form);
  form.querySelector("input")?.focus();
}

async function submitPortfolioImportInput(form, { cancel }) {
  const jobId = String(form?.dataset?.jobId || "");
  const requestId = String(form?.dataset?.requestId || "");
  if (!jobId || !requestId) return;
  const values = {};
  if (!cancel) {
    for (const control of form.querySelectorAll("[data-field-id]")) {
      const value = String(control.value || "").trim();
      if (value) values[control.dataset.fieldId] = { value, checked: false };
    }
    if (Object.keys(values).length === 0) {
      showToast("Wpisz kod albo użyj „Pomiń”", "warning");
      return;
    }
  }
  for (const button of form.querySelectorAll("button")) button.disabled = true;
  try {
    const response = await apiFetch(`/api/automation/jobs/${encodeURIComponent(jobId)}/input`, {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify(cancel ? { requestId, cancel: true } : { requestId, values }),
    });
    const data = await response.json();
    if (!response.ok) throw new Error(data?.error || "Nie udało się przekazać kodu.");
    const entry = getPortfolioImportEntry(form.dataset.insurerKey);
    if (entry) entry.inputRequest = null;
    form.remove();
  } catch (error) {
    for (const button of form.querySelectorAll("button")) button.disabled = false;
    showToast(String(error?.message || "Nie udało się przekazać kodu."), "error");
  }
}

function updatePortfolioImportRow(entry) {
  const row = portfolioImportElements.list?.querySelector(`[data-portfolio-import-row="${entry.key}"]`);
  if (!row) return;
  row.dataset.state = entry.state;
  const fill = row.querySelector(".portfolio-import-bar__fill");
  if (fill) fill.style.width = `${entry.percent}%`;
  const percentLabel = row.querySelector(".portfolio-import-meta__percent");
  if (percentLabel) percentLabel.textContent = `${entry.percent}%`;
  const counters = row.querySelector(".portfolio-import-meta__counters");
  if (counters) {
    counters.textContent = describePortfolioImportEntryProgress(entry)
      || entry.message
      || "Czeka w kolejce…";
  }
  renderPortfolioImportInputForm(row, entry);
  const existingAction = row.querySelector(".portfolio-import-action");
  if (!entry.action) {
    existingAction?.remove();
    return;
  }
  if (existingAction) {
    const label = existingAction.querySelector("span");
    const button = existingAction.querySelector("button");
    if (label) label.textContent = entry.action.message;
    if (button) button.textContent = entry.action.label;
    return;
  }
  const action = document.createElement("div");
  action.className = "portfolio-import-action";
  const message = document.createElement("span");
  message.textContent = entry.action.message;
  const button = document.createElement("button");
  button.className = "settings-secondary-button";
  button.type = "button";
  button.dataset.portfolioImportAction = entry.key;
  button.textContent = entry.action.label;
  action.append(message, button);
  row.append(action);
}

function collectPortfolioImportTotals() {
  return [...(portfolioImportRun?.entries?.values() || [])].reduce((sum, entry) => ({
    fetched: sum.fetched + (entry.counters.fetched || 0),
    added: sum.added + (entry.counters.added || 0),
    enriched: sum.enriched + (entry.counters.enriched || 0),
    pdf: sum.pdf + (entry.counters.pdf || 0),
    displayPdf: sum.displayPdf + Math.max(entry.counters.pdf || 0, entry.displayPdf || 0),
  }), { fetched: 0, added: 0, enriched: 0, pdf: 0, displayPdf: 0 });
}

function updatePortfolioImportTotals() {
  const totals = collectPortfolioImportTotals();
  if (portfolioImportElements.totals) {
    portfolioImportElements.totals.hidden = !isPortfolioImportRunActive()
      && !portfolioImportRun?.finishedAt;
  }
  if (portfolioImportElements.totalFetched) portfolioImportElements.totalFetched.textContent = String(totals.fetched);
  if (portfolioImportElements.totalAdded) portfolioImportElements.totalAdded.textContent = String(totals.added);
  if (portfolioImportElements.totalEnriched) portfolioImportElements.totalEnriched.textContent = String(totals.enriched);
  if (portfolioImportElements.totalPdf) portfolioImportElements.totalPdf.textContent = String(totals.displayPdf);
  return totals;
}

function setPortfolioImportStatus(message, state = "running") {
  const element = portfolioImportElements.status;
  if (!element) return;
  element.textContent = message || "";
  element.dataset.state = state;
}

function updatePortfolioImportMini() {
  const mini = portfolioImportElements.mini;
  if (!mini) return;
  const running = isPortfolioImportRunActive();
  const minimized = portfolioImportRun?.minimized === true;
  mini.hidden = !(running && minimized);
  if (mini.hidden) return;
  const entries = [...(portfolioImportRun?.entries?.values() || [])];
  const percent = computePortfolioImportTotalPercent(entries);
  const needsAction = entries.some((entry) => entry.state === "action");
  mini.dataset.state = needsAction ? "action" : "running";
  if (portfolioImportElements.miniPercent) portfolioImportElements.miniPercent.textContent = `${percent}%`;
  if (portfolioImportElements.miniArc) {
    const offset = PORTFOLIO_IMPORT_MINI_ARC_LENGTH * (1 - (percent / 100));
    portfolioImportElements.miniArc.style.strokeDashoffset = String(offset);
  }
  if (portfolioImportElements.miniAlert) portfolioImportElements.miniAlert.hidden = !needsAction;
  if (portfolioImportElements.miniDetail) {
    const current = entries.find((entry) => entry.state === "running");
    portfolioImportElements.miniDetail.textContent = needsAction
      ? "Któreś towarzystwo czeka na Ciebie"
      : current
        ? `${current.label}: ${current.percent}%`
        : "Kończenie…";
  }
}

function renderPortfolioImport() {
  renderPortfolioImportList();
  updatePortfolioImportTotals();
  updatePortfolioImportMini();
  const running = isPortfolioImportRunActive();
  if (portfolioImportElements.start) {
    portfolioImportElements.start.disabled = running
      || (portfolioImportRun?.entries?.size || 0) === 0;
    portfolioImportElements.start.textContent = running ? "Import trwa…" : "Pobierz polisy";
  }
  if (portfolioImportElements.minimize) portfolioImportElements.minimize.hidden = !running;
  if (portfolioImportElements.downloadPdfs) portfolioImportElements.downloadPdfs.disabled = running;
  if (portfolioImportElements.fullReimport) portfolioImportElements.fullReimport.disabled = running;
  if (portfolioImportElements.intro) {
    portfolioImportElements.intro.textContent = running
      ? "Import trwa. Możesz zminimalizować okno i pracować dalej - wrócisz do niego kręcącym się kółkiem w prawym dolnym rogu."
      : "Zaznacz towarzystwa i kliknij „Pobierz polisy”. Import zajmuje tyle, ile trzeba - możesz go zminimalizować i pracować dalej.";
  }
}

function refreshPortfolioImportEntry(entry) {
  updatePortfolioImportRow(entry);
  updatePortfolioImportTotals();
  updatePortfolioImportMini();
}



function notePortfolioImportJob(insurerKey, job) {
  const entry = getPortfolioImportEntry(insurerKey);
  if (!entry || !job || entry.state === "done" || entry.state === "action") return;
  entry.jobId = String(job.id || entry.jobId || "");
  entry.idleSince = 0;
  if (job.status === "completed" || job.status === "consumed") {
    
    
    entry.percent = Math.max(entry.percent, PORTFOLIO_IMPORT_PHASE_RANGES.save[0]);
    refreshPortfolioImportEntry(entry);
    return;
  }
  if (job.status === "manual_required" || job.status === "error") {
    entry.inputRequest = null;
    finishPortfolioImportTarget(entry, {
      state: "action",
      action: buildPortfolioImportAction(entry, job),
    });
    return;
  }
  
  
  
  if (job.status === "input_required" && job.inputRequest) {
    entry.inputRequest = job.inputRequest;
    entry.state = "running";
    entry.message = "Czeka na kod z telefonu";
    entry.chainPendingAt = Date.now();
    refreshPortfolioImportEntry(entry);
    return;
  }
  if (entry.inputRequest) entry.inputRequest = null;
  const phase = detectPortfolioImportPhase(job);
  if (phase === entry.phase) entry.phaseTicks += 1;
  else {
    entry.phase = phase;
    entry.phaseTicks = 0;
  }
  const counters = readPortfolioImportJobCounters(job);
  if (Number.isFinite(counters.fetched)) {
    entry.counters.fetched = Math.max(entry.counters.fetched, counters.fetched);
  }
  if (Number.isFinite(counters.pdf)) {
    entry.pdfBatch = Math.max(entry.pdfBatch, counters.pdf);
    entry.displayPdf = Math.max(entry.displayPdf, entry.counters.pdf + entry.pdfBatch);
  }
  let ratio = creepPortfolioImportRatio(entry.phaseTicks);
  if (phase === "list" && counters.fetchedTotal > 0) {
    ratio = counters.fetched / counters.fetchedTotal;
  }
  if (phase === "pdf") {
    const remaining = Number.isFinite(job.pdfQueueRemaining) ? job.pdfQueueRemaining : null;
    if (remaining !== null && remaining >= 0) {
      entry.pdfPeak = Math.max(entry.pdfPeak, remaining);
      if (entry.pdfPeak > 0) ratio = 1 - (remaining / entry.pdfPeak);
    } else if (counters.pdfTotal > 0) {
      ratio = counters.pdf / counters.pdfTotal;
    }
  }
  entry.percent = computePortfolioImportPercent({ phase, ratio, previous: entry.percent });
  entry.state = "running";
  entry.message = "";
  refreshPortfolioImportEntry(entry);
}



function notePortfolioImportTotals(insurerKey, chainTotals, { accumulate = false } = {}) {
  const entry = getPortfolioImportEntry(insurerKey);
  if (!entry || !chainTotals) return;
  const added = Math.max(0, Number(chainTotals.added) || 0);
  const enriched = Math.max(0, Number(chainTotals.enriched) || 0);
  const attached = Math.max(0, Number(chainTotals.attached) || 0);
  if (accumulate) {
    
    
    entry.counters.added += added;
    entry.counters.enriched += enriched;
    entry.counters.pdf += attached;
  } else {
    entry.counters.added = added;
    entry.counters.enriched = enriched;
    entry.counters.pdf = attached;
  }
  
  
  entry.pdfBatch = 0;
  entry.displayPdf = Math.max(entry.displayPdf, entry.counters.pdf);
  refreshPortfolioImportEntry(entry);
}






function notePortfolioImportAckFailure(insurerKey, detail = "") {
  const entry = getPortfolioImportEntry(insurerKey);
  if (!entry || entry.state === "done" || entry.state === "action") return;
  finishPortfolioImportTarget(entry, {
    state: "action",
    action: {
      kind: "ack",
      label: "Odśwież stronę",
      message: `${entry.label}: polisy są zapisane w bazie, ale serwer nie potwierdził zakończenia importu.`
        + " Nie uruchamiaj kolejnego importu tego towarzystwa - po odświeżeniu strony aplikacja dokończy potwierdzenie."
        + (detail ? ` (${detail})` : ""),
    },
  });
}



function notePortfolioImportChain(insurerKey, chainContinues) {
  const entry = getPortfolioImportEntry(insurerKey);
  if (!entry || entry.state === "done" || entry.state === "action") return;
  if (chainContinues === true) {
    entry.chainPendingAt = Date.now();
    entry.idleSince = 0;
    return;
  }
  finishPortfolioImportTarget(entry, { state: "done" });
}

function buildPortfolioImportAction(entry, job) {
  const target = getPortfolioImportTarget(entry.key);
  const detail = `${job?.title || ""} ${job?.detail || ""}`.toLowerCase();
  if (target?.openLogin && detail.includes("nie jesteś zalogowany")) {
    return {
      kind: "login",
      label: "Zaloguj się",
      message: `${entry.label}: otworzę okno portalu. Zaloguj się i wejdź na stronę główną - resztę zrobię sam.`,
    };
  }
  if (job?.manualAvailable === true && target?.manualRepair) {
    return {
      kind: "manual",
      label: "Popraw ścieżkę",
      message: `${entry.label} wymaga poprawienia drogi do listy polis. Po kliknięciu wyjaśnię, która ścieżka zostanie poprawiona.`,
    };
  }
  if (target?.openLogin) {
    return {
      kind: "login",
      label: "Zaloguj się",
      message: `${entry.label}: otworzę okno portalu. Zaloguj się i wejdź na stronę główną - resztę zrobię sam.`,
    };
  }
  return {
    kind: "retry",
    label: "Spróbuj ponownie",
    message: `${entry.label} nie dokończyło pobierania. Możesz spróbować jeszcze raz.`,
  };
}

function finishPortfolioImportTarget(entry, { state, action = null, message = "" }) {
  if (!entry) return;
  if (entry.startTimer) {
    globalThis.clearTimeout(entry.startTimer);
    entry.startTimer = 0;
  }
  if (entry.idleTimer) {
    globalThis.clearInterval(entry.idleTimer);
    entry.idleTimer = 0;
  }
  entry.state = state;
  entry.action = action;
  entry.message = message || entry.message;
  if (state === "done") entry.percent = 100;
  refreshPortfolioImportEntry(entry);
  const resolve = entry.resolve;
  entry.resolve = null;
  if (typeof resolve === "function") resolve();
  finishAdoptedPortfolioImportRun();
}




function finishAdoptedPortfolioImportRun() {
  if (portfolioImportRun?.adopted !== true || !portfolioImportRun.active) return;
  const pending = [...portfolioImportRun.entries.values()]
    .some((entry) => entry.state === "running" || entry.state === "pending");
  if (pending) return;
  portfolioImportRun.active = false;
  portfolioImportRun.adopted = false;
  portfolioImportRun.finishedAt = Date.now();
  portfolioImportRun.minimized = false;
  renderPortfolioImport();
  showPortfolioImportReport();
}



async function startWartaPortfolioImportForRun(options = {}) {
  const select = elements.wartaPortfolioRecordSelect;
  const remembered = String(globalThis.localStorage?.getItem(PORTFOLIO_IMPORT_WARTA_RECORD_KEY) || "").trim();
  if (select && !select.value && remembered) {
    
    
    const option = document.createElement("option");
    option.value = remembered;
    option.textContent = "Zapamiętany rekord";
    select.append(option);
    select.value = remembered;
  }
  if (!select?.value) {
    await startWartaPortfolioRecords();
    
    
    
    
    
    const recordsDeadline = Date.now() + 3 * 60 * 1000;
    while (wartaPortfolioRecordsActive && Date.now() < recordsDeadline) {
      await new Promise((resolve) => globalThis.setTimeout(resolve, 500));
    }
    const options = [...(select?.options || [])].filter((option) => option.value);
    if (options.length === 1) select.value = options[0].value;
    if (!select?.value && options.length > 1) {
      
      
      const chosen = await askPortfolioImportChoice(getPortfolioImportEntry("warta"), {
        title: "Warta: z którego rekordu pobrać polisy?",
        hint: "Zapamiętam wybór - przy kolejnych importach nie zapytam ponownie.",
        options: options.map((option) => ({ value: option.value, label: option.textContent || option.value })),
      });
      if (chosen) select.value = chosen;
    }
    if (!select?.value) {
      finishPortfolioImportTarget(getPortfolioImportEntry("warta"), {
        state: "action",
        action: {
          kind: "warta-record",
          label: "Otwórz ustawienia Warty",
          
          
          message: wartaPortfolioRecordsLastError
            ? `Nie udało się pobrać listy rekordów Warty. ${wartaPortfolioRecordsLastError}`
            : "Warta nie zwróciła żadnego rekordu do wyboru. Sprawdź dane logowania w ustawieniach Warty.",
        },
      });
      return;
    }
  }
  globalThis.localStorage?.setItem(PORTFOLIO_IMPORT_WARTA_RECORD_KEY, select.value);
  await startWartaPortfolioImport(options);
}



function syncPortfolioImportPdfChoice() {
  const wanted = portfolioImportElements.downloadPdfs?.checked === true;
  for (const target of PORTFOLIO_IMPORT_TARGETS) {
    const checkbox = elements[target.pdfCheckboxKey];
    if (!checkbox || checkbox.checked === wanted) continue;
    checkbox.checked = wanted;
    
    checkbox.dispatchEvent(new Event("change"));
  }
}

function readPortfolioImportTargetFailure(target) {
  const text = String(elements[target.statusKey]?.textContent || "").trim();
  return text || "Nie udało się dokończyć pobierania.";
}

function failPortfolioImportTarget(target, entry, kind = "retry", label = "Spróbuj ponownie") {
  finishPortfolioImportTarget(entry, {
    state: "action",
    action: {
      kind,
      label,
      message: `${entry.label}: ${readPortfolioImportTargetFailure(target)}`,
    },
  });
}





function watchPortfolioImportTargetIdle(target, entry) {
  if (entry.idleTimer) globalThis.clearInterval(entry.idleTimer);
  entry.idleTimer = globalThis.setInterval(() => {
    if (entry.state !== "running") {
      globalThis.clearInterval(entry.idleTimer);
      entry.idleTimer = 0;
      return;
    }
    if (!entry.jobId) return;
    const button = elements[target.buttonKey];
    const stopped = button ? button.disabled !== true : false;
    const chainFresh = entry.chainPendingAt > 0
      && (Date.now() - entry.chainPendingAt) < PORTFOLIO_IMPORT_IDLE_TIMEOUT;
    if (!stopped || chainFresh) {
      entry.idleSince = 0;
      return;
    }
    if (!entry.idleSince) {
      entry.idleSince = Date.now();
      return;
    }
    if ((Date.now() - entry.idleSince) < PORTFOLIO_IMPORT_IDLE_TIMEOUT) return;
    failPortfolioImportTarget(target, entry);
  }, PORTFOLIO_IMPORT_IDLE_POLL);
}

function runPortfolioImportTarget(target, entry, options = {}) {
  return new Promise((resolve) => {
    entry.resolve = resolve;
    entry.state = "running";
    entry.message = "Uruchamianie…";
    entry.chainPendingAt = 0;
    entry.idleSince = 0;
    refreshPortfolioImportEntry(entry);
    
    
    entry.startTimer = globalThis.setTimeout(() => {
      entry.startTimer = 0;
      if (entry.jobId || entry.state !== "running") return;
      failPortfolioImportTarget(target, entry);
    }, PORTFOLIO_IMPORT_START_TIMEOUT);
    watchPortfolioImportTargetIdle(target, entry);
    Promise.resolve()
      .then(() => target.start(options))
      .catch(() => {
        if (entry.state !== "running") return;
        failPortfolioImportTarget(target, entry);
      });
  });
}

async function runPortfolioImportSequence() {
  for (const target of PORTFOLIO_IMPORT_TARGETS) {
    const entry = getPortfolioImportEntry(target.key);
    if (!entry || entry.state === "skipped" || entry.state === "done" || entry.state === "action") continue;
    setPortfolioImportStatus(`Pobieranie polis: ${entry.label}…`);
    await runPortfolioImportTarget(target, entry, {
      fullReimport: portfolioImportRun?.fullReimport === true,
    });
  }
}

async function startPortfolioImportRun() {
  if (isPortfolioImportRunActive() || !portfolioImportRun) return;
  const selected = [...portfolioImportRun.entries.values()].filter((entry) => entry.state !== "skipped");
  if (selected.length === 0) {
    setPortfolioImportStatus("Zaznacz co najmniej jedno towarzystwo.", "error");
    return;
  }
  if (!(await checkWartaAutomationBridge())) {
    setPortfolioImportStatus("Automatyzacja jest nieaktywna. Uruchom aplikację plikiem „Uruchom Baza Polis.cmd”.", "error");
    return;
  }
  const missingCredentials = selected.filter((entry) => {
    const target = getPortfolioImportTarget(entry.key);
    return typeof target?.hasCredentials === "function" && !target.hasCredentials();
  });
  for (const entry of missingCredentials) {
    finishPortfolioImportTarget(entry, {
      state: "action",
      action: {
        kind: "credentials",
        label: "Uzupełnij dane",
        message: `${entry.label}: sprawdź login, wpisz hasło i zapisz ustawienia ponownie.`,
      },
    });
  }
  const runnable = selected.filter((entry) => entry.state !== "action");
  if (runnable.length === 0) {
    setPortfolioImportStatus("Uzupełnij dane logowania zaznaczonych towarzystw.", "error");
    renderPortfolioImport();
    return;
  }
  portfolioImportRun.active = true;
  portfolioImportRun.startedAt = Date.now();
  portfolioImportRun.finishedAt = 0;
  portfolioImportRun.fullReimport = portfolioImportElements.fullReimport?.checked === true;
  syncPortfolioImportPdfChoice();
  renderPortfolioImport();
  try {
    await runPortfolioImportSequence();
  } finally {
    portfolioImportRun.active = false;
    portfolioImportRun.finishedAt = Date.now();
    portfolioImportRun.minimized = false;
    renderPortfolioImport();
    showPortfolioImportReport();
  }
}

function showPortfolioImportReport() {
  const entries = [...(portfolioImportRun?.entries?.values() || [])]
    .filter((entry) => entry.state !== "skipped");
  const totals = updatePortfolioImportTotals();
  const blocked = entries.filter((entry) => entry.state === "action");
  setPortfolioImportStatus(
    blocked.length > 0
      ? `Import zakończony. ${blocked.length === 1 ? "Jedno towarzystwo wymaga" : `${blocked.length} towarzystw wymaga`} Twojego działania.`
      : "Import zakończony.",
    blocked.length > 0 ? "error" : "success",
  );
  if (portfolioImportElements.reportAdded) portfolioImportElements.reportAdded.textContent = String(totals.added);
  if (portfolioImportElements.reportEnriched) portfolioImportElements.reportEnriched.textContent = String(totals.enriched);
  if (portfolioImportElements.reportPdfs) portfolioImportElements.reportPdfs.textContent = String(totals.pdf);
  if (portfolioImportElements.reportRows) {
    portfolioImportElements.reportRows.innerHTML = entries.map((entry) => {
      const summary = entry.state === "action"
        ? "wymaga działania"
        : describePortfolioImportCounters(entry.counters) || "brak nowych polis";
      return `
        <li data-state="${escapeHtml(entry.state)}">
          <strong>${escapeHtml(entry.label)}</strong>
          <span>${escapeHtml(summary)}</span>
        </li>
      `;
    }).join("");
  }
  if (portfolioImportElements.reportWarning) {
    const warning = blocked.length > 0
      ? `Otwórz okno importu i dokończ: ${blocked.map((entry) => entry.label).join(", ")}.`
      : "";
    portfolioImportElements.reportWarning.hidden = !warning;
    portfolioImportElements.reportWarning.textContent = warning;
  }
  const dialog = portfolioImportElements.reportDialog;
  if (dialog?.showModal && !dialog.open) dialog.showModal();
}



function preparePortfolioImportRun() {
  const previous = portfolioImportRun?.entries;
  const entries = new Map();
  for (const target of getAvailablePortfolioImportTargets()) {
    const entry = createPortfolioImportEntry(target);
    
    if (previous?.get(target.key)?.state === "skipped") entry.state = "skipped";
    entries.set(target.key, entry);
  }
  portfolioImportRun = {
    entries,
    active: false,
    minimized: false,
    startedAt: 0,
    finishedAt: 0,
    fullReimport: false,
  };
  if (portfolioImportElements.fullReimport) portfolioImportElements.fullReimport.checked = false;
}

function openPortfolioImportDialog() {
  if (isEmployeeAccount()) {
    showToast("Pobieranie polis z towarzystw jest dostępne tylko w bazie głównej agencji.", "warning");
    return;
  }
  if (!isPortfolioImportRunActive()) {
    preparePortfolioImportRun();
    setPortfolioImportStatus("");
  } else if (portfolioImportRun) {
    portfolioImportRun.minimized = false;
  }
  renderPortfolioImport();
  const dialog = portfolioImportElements.dialog;
  if (dialog?.showModal && !dialog.open) dialog.showModal();
}

function scrollToCalculatorCredentials() {
  portfolioImportElements.credentialsStart?.scrollIntoView({
    behavior: globalThis.matchMedia?.("(prefers-reduced-motion: reduce)").matches ? "auto" : "smooth",
    block: "start",
  });
}

function minimizePortfolioImportDialog() {
  if (portfolioImportRun) portfolioImportRun.minimized = true;
  portfolioImportElements.dialog?.close();
  
  elements.settingsDialog?.close();
  updatePortfolioImportMini();
}

function closePortfolioImportDialog() {
  
  if (isPortfolioImportRunActive()) {
    minimizePortfolioImportDialog();
    return;
  }
  portfolioImportElements.dialog?.close();
}

async function handlePortfolioImportAction(insurerKey) {
  const entry = getPortfolioImportEntry(insurerKey);
  const target = getPortfolioImportTarget(insurerKey);
  if (!entry?.action || !target) return;
  const action = entry.action;
  if (action.kind === "warta-record") {
    portfolioImportElements.dialog?.close();
    if (elements.settingsDialog?.showModal && !elements.settingsDialog.open) elements.settingsDialog.showModal();
    elements.wartaPortfolioRecordSelect?.focus?.();
    return;
  }
  if (action.kind === "credentials") {
    portfolioImportElements.dialog?.close();
    const card = document.querySelector(`.calculator-account-card[data-insurer="${target.key}"]`);
    card?.scrollIntoView({
      behavior: globalThis.matchMedia?.("(prefers-reduced-motion: reduce)").matches ? "auto" : "smooth",
      block: "center",
    });
    card?.querySelector('input[type="password"]')?.focus?.();
    return;
  }
  if (
    action.kind === "manual"
    && target.manualRepair
    && !(await requestPortfolioPathRepairConfirmation(entry.label))
  ) {
    return;
  }
  entry.action = null;
  entry.state = "running";
  entry.message = "Uruchamianie…";
  refreshPortfolioImportEntry(entry);
  
  
  const restartOptions = { fullReimport: portfolioImportRun?.fullReimport === true };
  if (action.kind === "login" && target.openLogin) {
    
    try {
      await target.openLogin();
    } catch {
      failPortfolioImportTarget(target, entry, "login", "Zaloguj się");
      return;
    }
    await runPortfolioImportTarget(target, entry, restartOptions);
    return;
  }
  if (action.kind === "manual" && target.manualRepair) {
    
    
    await new Promise((resolve) => {
      entry.resolve = resolve;
      watchPortfolioImportTargetIdle(target, entry);
      Promise.resolve()
        .then(() => target.manualRepair())
        .catch(() => {
          if (entry.state === "running") failPortfolioImportTarget(target, entry, "manual", "Popraw ścieżkę");
        });
    });
    return;
  }
  await runPortfolioImportTarget(target, entry, restartOptions);
}

portfolioImportElements.launcher?.addEventListener("click", openPortfolioImportDialog);
portfolioImportElements.credentialsButton?.addEventListener("click", scrollToCalculatorCredentials);
portfolioImportElements.close?.addEventListener("click", closePortfolioImportDialog);
portfolioImportElements.minimize?.addEventListener("click", minimizePortfolioImportDialog);
portfolioImportElements.start?.addEventListener("click", () => {
  void startPortfolioImportRun();
});
portfolioImportElements.mini?.addEventListener("click", openPortfolioImportDialog);
portfolioImportElements.closeReport?.addEventListener("click", () => portfolioImportElements.reportDialog?.close());
portfolioImportElements.confirmReport?.addEventListener("click", () => portfolioImportElements.reportDialog?.close());

portfolioImportElements.list?.addEventListener("change", (event) => {
  const key = event.target?.dataset?.portfolioImportChoice;
  if (!key || isPortfolioImportRunActive()) return;
  const entry = getPortfolioImportEntry(key);
  if (!entry) return;
  entry.state = event.target.checked ? "pending" : "skipped";
  const row = portfolioImportElements.list?.querySelector(`[data-portfolio-import-row="${key}"]`);
  if (row) row.dataset.state = entry.state;
  if (portfolioImportElements.start) {
    portfolioImportElements.start.disabled = ![...portfolioImportRun.entries.values()]
      .some((item) => item.state !== "skipped");
  }
});

portfolioImportElements.list?.addEventListener("click", (event) => {
  const key = event.target?.closest?.("[data-portfolio-import-action]")?.dataset?.portfolioImportAction;
  if (!key) return;
  void handlePortfolioImportAction(key);
});


portfolioImportElements.dialog?.addEventListener("close", () => {
  if (!isPortfolioImportRunActive() || !portfolioImportRun) return;
  portfolioImportRun.minimized = true;
  updatePortfolioImportMini();
});




function adoptRecoveredPortfolioImport(insurerKey, job) {
  if (isEmployeeAccount()) return;
  const target = getPortfolioImportTarget(insurerKey);
  if (!target) return;
  if (!portfolioImportRun || !portfolioImportRun.active) preparePortfolioImportRun();
  const entry = getPortfolioImportEntry(insurerKey);
  if (!entry || entry.state === "running") return;
  for (const other of portfolioImportRun.entries.values()) {
    if (other.key !== insurerKey && other.state === "pending") other.state = "skipped";
  }
  entry.state = "running";
  entry.jobId = String(job?.id || "");
  portfolioImportRun.active = true;
  portfolioImportRun.adopted = true;
  portfolioImportRun.minimized = true;
  watchPortfolioImportTargetIdle(target, entry);
  notePortfolioImportJob(insurerKey, job);
  renderPortfolioImport();
}




globalThis.setInterval(() => {
  void processManualOverlayActions();
}, 1200);
