import { createPortfolioIssueIdentityHash } from "./xombeztlyiegtybxtzkg.mjs";

const MAX_FRAMES = 12;
const MAX_ROWS_PER_PAGE = 400;
const POLISA_ONLINE_URL = "https://polisaonline.ergohestia.pl/";
const POLISA_ONLINE_HOST = "polisaonline.ergohestia.pl";
export const MTU_POLICY_PDF_SYMBOLS = ["POLISA", "POLISA-ELEKTRONICZNA", "POLISA-KOPIA"];
const MTU_POLICIES_API_PATH = "/api/insurance/v1/policies/searches";
const MTU_API_WINDOW_LIMIT = 500;
const MTU_API_MAX_SPLIT_DEPTH = 8;
export const MTU_PORTFOLIO_COMPLETENESS_ERROR = "PORTFOLIO_COMPLETENESS_FAILED";

function throwMtuCompletenessError(reason) {
  const error = new Error("Nie można potwierdzić kompletności portfela MTU/Hestii. Import został przerwany.");
  error.code = MTU_PORTFOLIO_COMPLETENESS_ERROR;
  error.reason = reason;
  throw error;
}

export function classifyMtuApiSlice({ itemCount, fromDate, toDate, depth = 0 }) {
  if (itemCount < MTU_API_WINDOW_LIMIT) return "complete";
  if (fromDate === toDate) throwMtuCompletenessError("daily_window_saturated");
  if (depth >= MTU_API_MAX_SPLIT_DEPTH) throwMtuCompletenessError("split_depth_saturated");
  return "split";
}
const MTU_API_HEADERS = {
  "Content-Type": "application/json;charset=utf-8",
  "Accept": "application/json, text/plain, */*",
  "X-Requested-With": "XMLHttpRequest",
};

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

function normalizeText(value) {
  return compactText(value)
    .normalize("NFD")
    .replace(/[̀-ͯ]/g, "")
    .toLowerCase();
}

export function normalizeMtuPolicyNumber(value) {
  return compactText(value).replace(/\s+/g, "").toUpperCase();
}

export function normalizeMtuDate(value) {
  const text = compactText(value);
  const isoMatch = text.match(/\b(\d{4})-(\d{2})-(\d{2})\b/);
  if (isoMatch) return `${isoMatch[1]}-${isoMatch[2]}-${isoMatch[3]}`;
  const plMatch = text.match(/\b(\d{2})[./-](\d{2})[./-](\d{4})\b/);
  if (plMatch) return `${plMatch[3]}-${plMatch[2]}-${plMatch[1]}`;
  return "";
}

export function normalizeMtuAmount(value) {
  const match = compactText(value).match(/(\d{1,3}(?:[ . ]\d{3})*|\d+)(?:,(\d{1,2}))?/);
  if (!match) return "";
  const wholePart = match[1].replace(/[ . ]/g, "");
  const decimalPart = match[2] ? match[2].padEnd(2, "0") : "";
  if (!/^\d+$/.test(wholePart)) return "";
  return decimalPart && decimalPart !== "00" ? `${wholePart},${decimalPart}` : wholePart;
}

function buildRowExtractionScript() {
  return ({ maxRows }) => {
    const compact = (value) => String(value || "").replace(/\s+/g, " ").trim();
    const normalize = (value) => compact(value)
      .normalize("NFD")
      .replace(/[̀-ͯ]/g, "")
      .toLowerCase();
    const visible = (element) => element instanceof HTMLElement
      && element.getClientRects().length > 0
      && getComputedStyle(element).visibility !== "hidden";
    const datePattern = /\b(?:\d{2}[./-]\d{2}[./-]\d{4}|\d{4}-\d{2}-\d{2})\b/;
    const policyNumberPattern = /\b[A-Z]{0,4}[ -]?\d{7,15}\b/i;

    const headerKind = (headerText) => {
      const text = normalize(headerText);
      if (!text) return "";
      if (/(numer|nr)[^a-z]*(polisy|umowy|dokumentu)|polisa\b|umowa\b/.test(text)) return "policyNumber";
      if (/klient|ubezpieczajac|ubezpieczony|kontrahent|nazwa\b|nazwisko|wlasciciel/.test(text)) return "clientName";
      if (/pesel|nip|regon|identyfikator/.test(text)) return "identityNumber";
      if (/rejestracyj/.test(text)) return "registration";
      if (/produkt|ryzyk|pakiet|rodzaj|zakres|przedmiot/.test(text)) return "productName";
      if (/status|stan\b/.test(text)) return "status";
      if (/skladk|przypis|kwota|naleznosc|do zaplaty|brutto/.test(text)) return "premium";
      if (/(poczatek|start|od)\b|data (zawarcia|poczatku|startu)|obowiazuje od/.test(text)) return "validFrom";
      if (/(koniec|do)\b|data (konca|zakonczenia|wygasniecia)|obowiazuje do|wznowien/.test(text)) return "validUntil";
      if (/okres|ochrona|obowiazywan/.test(text)) return "validityRange";
      return "";
    };

    const collectRowGroups = () => {
      const groups = [];
      for (const table of document.querySelectorAll("table")) {
        if (!visible(table)) continue;
        const headerCells = [...table.querySelectorAll("thead th, thead td")];
        const headers = headerCells.length > 0
          ? headerCells.map((cell) => compact(cell.innerText))
          : [...(table.querySelector("tr")?.querySelectorAll("th") || [])].map((cell) => compact(cell.innerText));
        const rows = [...table.querySelectorAll("tbody tr")]
          .filter((row) => visible(row) && row.querySelectorAll("td").length > 1)
          .map((row) => [...row.querySelectorAll("td")].map((cell) => compact(cell.innerText)));
        if (rows.length > 0) groups.push({ headers, rows });
      }
      const gridContainers = new Set();
      for (const rowElement of document.querySelectorAll("[role='row']")) {
        if (rowElement.closest("table")) continue;
        const container = rowElement.parentElement;
        if (container) gridContainers.add(container);
      }
      for (const container of gridContainers) {
        const rowElements = [...container.querySelectorAll(":scope [role='row']")].filter(visible);
        if (rowElements.length === 0) continue;
        const headers = [...container.closest("[role='grid'], [role='table']")?.querySelectorAll("[role='columnheader']") || []]
          .map((cell) => compact(cell.innerText));
        const rows = rowElements
          .map((rowElement) => [...rowElement.querySelectorAll("[role='cell'], [role='gridcell']")]
            .map((cell) => compact(cell.innerText)))
          .filter((cells) => cells.length > 1);
        if (rows.length > 0) groups.push({ headers, rows });
      }
      return groups;
    };

    const results = [];
    for (const group of collectRowGroups()) {
      const kinds = group.headers.map(headerKind);
      const knownKinds = new Set(kinds.filter(Boolean));
      const strongHeaders = knownKinds.has("policyNumber")
        && (knownKinds.has("validUntil") || knownKinds.has("validityRange") || knownKinds.has("premium") || knownKinds.has("clientName"));
      for (const cells of group.rows) {
        if (results.length >= maxRows) break;
        const rowText = compact(cells.join(" | "));
        if (!policyNumberPattern.test(rowText)) continue;
        if (!strongHeaders && !datePattern.test(rowText)) continue;
        const record = {
          policyNumber: "",
          clientName: "",
          identityNumber: "",
          registration: "",
          productName: "",
          status: "",
          premium: "",
          validFrom: "",
          validUntil: "",
          validityRange: "",
          strongHeaders,
          rowText: rowText.slice(0, 600),
        };
        kinds.forEach((kind, index) => {
          if (!kind || index >= cells.length || record[kind]) return;
          record[kind] = compact(cells[index]).slice(0, 240);
        });
        if (!record.policyNumber) {
          const fallback = rowText.match(policyNumberPattern);
          record.policyNumber = fallback ? compact(fallback[0]) : "";
        }
        if (record.policyNumber) results.push(record);
      }
      if (results.length >= maxRows) break;
    }
    return results;
  };
}

export async function collectMtuPortfolioRows(page) {
  const collected = [];
  for (const frame of page.frames().slice(0, MAX_FRAMES)) {
    try {
      const frameRows = await frame.evaluate(buildRowExtractionScript(), { maxRows: MAX_ROWS_PER_PAGE });
      collected.push(...frameRows);
    } catch {
    }
    if (collected.length >= MAX_ROWS_PER_PAGE) break;
  }
  return collected.slice(0, MAX_ROWS_PER_PAGE);
}

export async function hasMtuPortfolioRows(page, minimumRows = 1) {
  const rows = await collectMtuPortfolioRows(page);
  return rows.filter((row) => row.strongHeaders).length >= minimumRows;
}

export function getMtuPortfolioPageSignature(rows) {
  return rows
    .slice(0, 5)
    .map((row) => `${normalizeMtuPolicyNumber(row.policyNumber)}#${normalizeText(row.rowText).slice(0, 80)}`)
    .join("||");
}

export async function clickMtuPortfolioNextPage(page) {
  for (const frame of page.frames().slice(0, MAX_FRAMES)) {
    try {
      const clicked = await frame.evaluate(() => {
        const compact = (value) => String(value || "").replace(/\s+/g, " ").trim();
        const normalize = (value) => compact(value)
          .normalize("NFD")
          .replace(/[̀-ͯ]/g, "")
          .toLowerCase();
        const visible = (element) => element instanceof HTMLElement
          && element.getClientRects().length > 0
          && getComputedStyle(element).visibility !== "hidden";
        const isDisabled = (element) => element.disabled === true
          || element.getAttribute("aria-disabled") === "true"
          || /(^|\s)(disabled|p-disabled|ui-state-disabled)(\s|$)/.test(String(element.className || ""));
        const candidates = [...document.querySelectorAll(
          "button, a, [role='button'], li.pagination-next > a, li.pagination-next > button",
        )].filter((element) => visible(element) && !isDisabled(element));
        const scoreCandidate = (element) => {
          const text = normalize(element.innerText);
          const label = normalize(`${element.getAttribute("aria-label") || ""} ${element.getAttribute("title") || ""}`);
          const className = normalize(String(element.className || ""));
          if (/nastepna|nastepny|next/.test(label)) return 3;
          if (/^(nastepna|nastepny|dalej ?>|>|»|›)$/.test(text)) return 2;
          if (/(p-paginator-next|pagination-next|next-page|paginator-next)/.test(className)) return 2;
          return 0;
        };
        const best = candidates
          .map((element) => ({ element, score: scoreCandidate(element) }))
          .filter((candidate) => candidate.score > 0)
          .sort((first, second) => second.score - first.score)[0];
        if (!best) return false;
        best.element.click();
        return true;
      });
      if (clicked) return true;
    } catch {
    }
  }
  return false;
}

export async function collectMtuPortfolioDiagnostics(page) {
  const frames = [];
  for (const frame of page.frames().slice(0, MAX_FRAMES)) {
    try {
      const summary = await frame.evaluate(() => {
        const compact = (value) => String(value || "").replace(/\s+/g, " ").trim();
        const visible = (element) => element instanceof HTMLElement
          && element.getClientRects().length > 0;
        const tables = [...document.querySelectorAll("table")].filter(visible).slice(0, 6).map((table) => ({
          headerTexts: [...table.querySelectorAll("thead th, thead td")].map((cell) => compact(cell.innerText)).slice(0, 20),
          rowCount: table.querySelectorAll("tbody tr").length,
        }));
        const gridHeaderTexts = [...document.querySelectorAll("[role='columnheader']")]
          .filter(visible)
          .map((cell) => compact(cell.innerText))
          .slice(0, 20);
        const headingTexts = [...document.querySelectorAll("h1, h2, h3")]
          .filter(visible)
          .map((heading) => compact(heading.innerText))
          .filter(Boolean)
          .slice(0, 8);
        return { tables, gridHeaderTexts, headingTexts };
      });
      let frameHint = "";
      try {
        const frameUrl = new URL(frame.url());
        frameHint = `${frameUrl.hostname}${frameUrl.pathname}`.slice(0, 200);
      } catch {
      }
      frames.push({ frameHint, ...summary });
    } catch {
    }
  }
  return { kind: "mtu-portfel", frames };
}

function parseValidityRange(rangeText) {
  const dates = compactText(rangeText).match(/\b(?:\d{2}[./-]\d{2}[./-]\d{4}|\d{4}-\d{2}-\d{2})\b/g) || [];
  return {
    validFrom: dates.length > 0 ? normalizeMtuDate(dates[0]) : "",
    validUntil: dates.length > 1 ? normalizeMtuDate(dates[1]) : "",
  };
}

function pickLonger(currentValue, candidateValue) {
  const current = compactText(currentValue);
  const candidate = compactText(candidateValue);
  return candidate.length > current.length ? candidate : current;
}

function sumPremiums(amounts) {
  let totalCents = 0;
  for (const amount of amounts) {
    const normalized = normalizeMtuAmount(amount);
    if (!normalized) continue;
    const [whole, cents = "0"] = normalized.split(",");
    totalCents += Number(whole) * 100 + Number(cents.padEnd(2, "0"));
  }
  if (totalCents === 0) return "";
  const whole = Math.trunc(totalCents / 100);
  const cents = totalCents % 100;
  return cents === 0 ? String(whole) : `${whole},${String(cents).padStart(2, "0")}`;
}

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

function getPageHostname(page) {
  try {
    return new URL(page.url()).hostname.toLowerCase();
  } catch {
    return "";
  }
}

export async function warmUpPolisaOnline(page) {
  if (getPageHostname(page) === POLISA_ONLINE_HOST) return true;
  try {
    await page.goto(POLISA_ONLINE_URL, { waitUntil: "domcontentloaded", timeout: 60000 });
  } catch {
  }
  const deadline = Date.now() + 60000;
  while (Date.now() < deadline) {
    if (getPageHostname(page) === POLISA_ONLINE_HOST) {
      await portfelDelay(1200);
      return true;
    }
    await portfelDelay(600);
  }
  return getPageHostname(page) === POLISA_ONLINE_HOST;
}

export async function downloadMtuPolicyPdfBase64(page, policyNumber, symbols = MTU_POLICY_PDF_SYMBOLS, printoutsHost = POLISA_ONLINE_HOST) {
  return page.evaluate(async ({ policyNumber: number, symbols: symbolList, host }) => {
    const toBase64 = (buffer) => {
      const bytes = new Uint8Array(buffer);
      let binary = "";
      const chunkSize = 0x8000;
      for (let offset = 0; offset < bytes.length; offset += chunkSize) {
        binary += String.fromCharCode.apply(null, bytes.subarray(offset, offset + chunkSize));
      }
      return btoa(binary);
    };
    for (const symbol of symbolList) {
      try {
        const response = await fetch(
          `https://${host}/api/printouts/v1/policies/${encodeURIComponent(number)}/symbols/${encodeURIComponent(symbol)}`,
          { headers: { Accept: "application/pdf", "X-Requested-With": "XMLHttpRequest" }, credentials: "include" },
        );
        if (!response.ok) continue;
        const contentType = response.headers.get("content-type") || "";
        if (!/pdf|octet-stream/i.test(contentType)) continue;
        const buffer = await response.arrayBuffer();
        const bytes = new Uint8Array(buffer);
        if (bytes.length < 1000) continue;
        if (!(bytes[0] === 0x25 && bytes[1] === 0x50 && bytes[2] === 0x44 && bytes[3] === 0x46)) continue;
        return { symbol, base64: toBase64(buffer), size: buffer.byteLength };
      } catch {
      }
    }
    return null;
  }, { policyNumber: String(policyNumber), symbols, host: printoutsHost });
}

function formatLocalDate(date) {
  return `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, "0")}-${String(date.getDate()).padStart(2, "0")}`;
}

function addDays(isoDate, days) {
  const [year, month, day] = isoDate.split("-").map(Number);
  const date = new Date(year, month - 1, day + days);
  return formatLocalDate(date);
}

function endOfMonth(isoDate) {
  const [year, month] = isoDate.split("-").map(Number);
  return formatLocalDate(new Date(year, month, 0));
}

function nextMonthStart(isoDate) {
  const [year, month] = isoDate.split("-").map(Number);
  return formatLocalDate(new Date(year, month, 1));
}

async function fetchMtuPortfolioApiSlice(page, dynamicFilters) {
  return page.evaluate(async ({ apiPath, headers, dynamicFilters: filters, top }) => {
    try {
      const response = await fetch(apiPath, {
        method: "POST",
        headers,
        credentials: "include",
        body: JSON.stringify({ sortBy: "", sortDirection: "ASC", top, count: top, skip: 0, dynamicFilters: filters }),
      });
      if (!response.ok) return { ok: false, status: response.status, items: [] };
      const data = await response.json().catch(() => null);
      if (!data || !Array.isArray(data.items)) return { ok: false, status: response.status, items: [] };
      return { ok: true, status: response.status, items: data.items };
    } catch (error) {
      return { ok: false, status: 0, items: [], error: String(error?.message || error) };
    }
  }, {
    apiPath: MTU_POLICIES_API_PATH,
    headers: MTU_API_HEADERS,
    dynamicFilters,
    top: MTU_API_WINDOW_LIMIT,
  });
}

async function fetchMtuPortfolioApiRange(page, fromDate, toDate, collected, depth = 0) {
  const slice = await fetchMtuPortfolioApiSlice(page, { endDateFrom: fromDate, endDateTo: toDate });
  if (!slice.ok) {
    console.error(`Import portfela: API polis odpowiedziało błędem (status ${slice.status || "sieciowy"}) dla zakresu ${fromDate}..${toDate}.`);
    throw new Error("Nie udało się pobrać polis. Spróbuj ponownie za chwilę.");
  }
  const sliceDisposition = classifyMtuApiSlice({
    itemCount: slice.items.length,
    fromDate,
    toDate,
    depth,
  });
  if (sliceDisposition === "split") {
    const [fromYear, fromMonth, fromDay] = fromDate.split("-").map(Number);
    const [toYear, toMonth, toDay] = toDate.split("-").map(Number);
    const middle = new Date((new Date(fromYear, fromMonth - 1, fromDay).getTime() + new Date(toYear, toMonth - 1, toDay).getTime()) / 2);
    const middleDate = formatLocalDate(middle);
    const firstHalfEnd = middleDate < fromDate ? fromDate : middleDate;
    await fetchMtuPortfolioApiRange(page, fromDate, firstHalfEnd, collected, depth + 1);
    await fetchMtuPortfolioApiRange(page, addDays(firstHalfEnd, 1), toDate, collected, depth + 1);
    return;
  }
  
  
  collected.push(...slice.items);
}

export async function fetchMtuPortfolioFromApi(page, { fromDate, onProgress = () => {}, maxMonths = 48 } = {}) {
  const startDate = fromDate || formatLocalDate(new Date());
  const probe = await fetchMtuPortfolioApiSlice(page, { endDateFrom: startDate, endDateTo: startDate });
  if (!probe.ok) {
    console.error(`Import portfela: API polis jest niedostępne (status ${probe.status || "sieciowy"}${probe.error ? `: ${probe.error}` : ""}).`);
    throw new Error("Nie udało się pobrać polis. Spróbuj ponownie za chwilę.");
  }
  const collected = [];
  let rangeFrom = startDate;
  let rangeTo = endOfMonth(startDate);
  for (let monthIndex = 0; monthIndex < maxMonths; monthIndex += 1) {
    const before = collected.length;
    await fetchMtuPortfolioApiRange(page, rangeFrom, rangeTo, collected);
    const added = collected.length - before;
    onProgress({
      rangeFrom,
      rangeTo,
      added,
      total: collected.length,
    });
    rangeFrom = nextMonthStart(rangeTo);
    rangeTo = endOfMonth(rangeFrom);
  }
  return collected;
}

function formatApiPremium(premium) {
  const value = Number(premium);
  if (!Number.isFinite(value) || value <= 0) return "";
  const fixed = value.toFixed(2);
  return fixed.endsWith(".00") ? fixed.slice(0, -3) : fixed.replace(".", ",");
}

const MTU_TYPE_FALLBACK_LABELS = {
  Property: "Majątek",
  PropertyPersonal: "Majątek",
  Travel: "Podróż",
  Personal: "NNW",
};



const HESTIA_PROPERTY_PRODUCTS = new Set(["ne7mienie", "e1mienie", "nmfmienie"]);





export function resolveErgoInsurerByPolicyNumber(policyNumber, fallbackInsurer = "") {
  const digits = String(policyNumber ?? "").replace(/\D/g, "");
  if (/^911\d{7,}$/.test(digits)) return "MTU";
  if (/^(?:909|922)\d{7,}$/.test(digits)) return "Hestia";
  return fallbackInsurer;
}





export function resolveApiPolicyInsurer(item) {
  return resolveErgoInsurerByPolicyNumber(
    item?.policyNumber,
    compactText(item?.brand).toUpperCase() === "MTU" ? "MTU" : "Hestia",
  );
}

function resolveApiPolicyLabel(item, insurer, registrationRaw) {
  if (registrationRaw.length >= 4 && registrationRaw.length <= 10) return registrationRaw;
  const typeCode = compactText(item?.typeCode);
  if (insurer === "Hestia") {
    const product = compactText(item?.product).toLowerCase();
    if (product === "ergobiznes") return "Firma";
    if (HESTIA_PROPERTY_PRODUCTS.has(product)) return "Mieszkanie";
    if (typeCode === "Property" || typeCode === "PropertyPersonal") return "Mieszkanie";
  }
  return MTU_TYPE_FALLBACK_LABELS[typeCode] || "Inne";
}

export function mapMtuApiPolicyItems(items, { mappingCollector = null } = {}) {
  const records = [];
  const seen = new Set();
  for (const item of Array.isArray(items) ? items : []) {
    const policyNumber = compactText(item?.policyNumber);
    const clientName = compactText(item?.policyholderName);
    const statusCode = compactText(item?.statusCode);
    if (statusCode && statusCode !== "Accepted") {
      mappingCollector?.recordFiltered(
        /cancel|anulowan|storn/i.test(statusCode)
          ? "CANCELLED_POLICY"
          : "NON_ACCEPTED_POLICY",
      );
      continue;
    }
    const insurer = resolveApiPolicyInsurer(item);
    const validFrom = compactText(item?.startDate).slice(0, 10);
    const validUntil = compactText(item?.endDate).slice(0, 10);
    const normalizedPolicyNumber = policyNumber.replace(/[^0-9A-Za-z]/g, "").toLowerCase();
    if (!normalizedPolicyNumber || !clientName) {
      let identityHash = "";
      try {
        identityHash = createPortfolioIssueIdentityHash({
          insurer,
          sourceId: compactText(item?.id ?? item?.policyId),
          policyNumber,
          validFrom,
          validUntil,
        });
      } catch {
      }
      mappingCollector?.recordRejected("MISSING_REQUIRED_FIELDS", { identityHash });
      continue;
    }
    const key = `${normalizeText(insurer)}\0${normalizedPolicyNumber}\0${validFrom}\0${validUntil}`;
    if (seen.has(key)) {
      mappingCollector?.recordDuplicate();
      continue;
    }
    seen.add(key);
    const pesel = compactText(item?.policyholderPesel).replace(/\D/g, "");
    const nip = compactText(item?.policyholderNip).replace(/\D/g, "");
    const regon = compactText(item?.policyholderRegon).replace(/\D/g, "");
    const phone = compactText(item?.policyholderPhoneNumbers);
    const email = compactText(item?.policyholderEmail);
    const contactParts = [];
    if (phone) contactParts.push(`Telefon: ${phone}`);
    if (email) contactParts.push(`E-mail: ${email}`);
    const registrationRaw = compactText(item?.vehicleRegistrationNumber).replace(/[^A-Za-z0-9]/g, "").toUpperCase();
    const registration = resolveApiPolicyLabel(item, insurer, registrationRaw);
    records.push({
      insurer,
      policyNumber,
      clientName: clientName.slice(0, 160),
      identityNumber: pesel || nip || regon,
      contact: contactParts.join("\n"),
      registration,
      vehicleMake: compactText(item?.vehicleBrand).slice(0, 60),
      vehicleModel: compactText(item?.vehicleModel).slice(0, 60),
      vin: compactText(item?.vehicleVin).replace(/[^A-Za-z0-9]/g, "").toUpperCase().slice(0, 24),
      validFrom,
      validUntil,
      issueDate: compactText(item?.acceptedDate).slice(0, 10),
      premium: formatApiPremium(item?.premium),
      status: compactText(item?.status).slice(0, 80),
      product: compactText(item?.product).slice(0, 80),
      renewalType: compactText(item?.renewalType).slice(0, 60),
    });
    mappingCollector?.recordMapped();
  }
  return records;
}




export function filterJupiterItemsSince(items, sinceDate) {
  const list = Array.isArray(items) ? items : [];
  if (!sinceDate) return list;
  return list.filter((item) => {
    const acceptedDate = compactText(item?.acceptedDate).slice(0, 10);
    if (acceptedDate) return acceptedDate >= sinceDate;
    const startDate = compactText(item?.startDate).slice(0, 10);
    if (startDate) return startDate >= sinceDate;
    return true;
  });
}

export function aggregateMtuPortfolioRows(rows) {
  const policies = new Map();
  for (const row of rows) {
    const policyKey = normalizeMtuPolicyNumber(row.policyNumber);
    if (!policyKey) continue;
    const rangeDates = parseValidityRange(row.validityRange);
    const validFrom = normalizeMtuDate(row.validFrom) || rangeDates.validFrom;
    const validUntil = normalizeMtuDate(row.validUntil) || rangeDates.validUntil;
    const premium = normalizeMtuAmount(row.premium);
    const riskLabel = compactText(row.productName).slice(0, 120);
    let policy = policies.get(policyKey);
    if (!policy) {
      policy = {
        policyNumber: compactText(row.policyNumber),
        clientName: "",
        identityNumber: "",
        registration: "",
        status: "",
        validFrom: "",
        validUntil: "",
        risks: [],
        riskKeys: new Set(),
        premiumAmounts: [],
        directPremium: "",
      };
      policies.set(policyKey, policy);
    }
    policy.clientName = pickLonger(policy.clientName, row.clientName);
    policy.status = policy.status || compactText(row.status).slice(0, 80);
    const identity = compactText(row.identityNumber).replace(/\D/g, "");
    if (!policy.identityNumber && /^\d{10,11}$/.test(identity)) policy.identityNumber = identity;
    const registration = compactText(row.registration).replace(/[^A-Za-z0-9]/g, "").toUpperCase();
    if (!policy.registration && registration.length >= 4 && registration.length <= 10) policy.registration = registration;
    if (validFrom && (!policy.validFrom || validFrom < policy.validFrom)) policy.validFrom = validFrom;
    if (validUntil && (!policy.validUntil || validUntil > policy.validUntil)) policy.validUntil = validUntil;
    const riskKey = `${normalizeText(riskLabel)}|${premium}`;
    if ((riskLabel || premium) && !policy.riskKeys.has(riskKey)) {
      policy.riskKeys.add(riskKey);
      if (riskLabel) policy.risks.push({ label: riskLabel, amount: premium ? `${premium} zł` : "" });
      if (premium) policy.premiumAmounts.push(premium);
    }
    if (premium && !riskLabel) policy.directPremium = policy.directPremium || premium;
  }
  return [...policies.values()].map((policy) => {
    const premium = policy.premiumAmounts.length === 1
      ? policy.premiumAmounts[0]
      : (policy.premiumAmounts.length > 1 ? sumPremiums(policy.premiumAmounts) : policy.directPremium);
    const riskSummary = policy.risks
      .map((risk) => (risk.amount ? `${risk.label} ${risk.amount}` : risk.label))
      .filter(Boolean)
      .join(" • ")
      .slice(0, 400);
    return {
      
      
      
      insurer: "",
      policyNumber: policy.policyNumber,
      clientName: policy.clientName.slice(0, 160),
      identityNumber: policy.identityNumber,
      registration: policy.registration || (policy.risks[0]?.label || "").slice(0, 40),
      validFrom: policy.validFrom,
      validUntil: policy.validUntil,
      premium,
      status: policy.status,
      risks: policy.risks.slice(0, 20),
      riskSummary,
    };
  });
}
