import type { BuyerDocument, PersonGroup } from "./types.ts"; const text = (value: unknown) => typeof value === "string" ? value.trim() : ""; const normalize = (value: unknown) => text(value).toLocaleLowerCase(); export function validateDocuments(value: unknown): BuyerDocument[] { if (!Array.isArray(value)) throw new Error("JSON root must be an array."); return value.map((item, index) => { if (!item || typeof item !== "object") throw new Error(`Record ${index + 1} is not an object.`); const doc = item as Partial; if (!text(doc.file_name) || !text(doc.name_from_filename) || !text(doc._letter)) { throw new Error(`Record ${index + 1} is missing file_name, name_from_filename, or _letter.`); } return doc as BuyerDocument; }); } export function groupDocuments(documents: BuyerDocument[]): PersonGroup[] { const groups = new Map(); for (const doc of documents) { const key = doc.name_from_filename.trim(); const bucket = groups.get(key) ?? []; bucket.push(doc); groups.set(key, bucket); } return [...groups.entries()] .map(([key, docs]) => { docs.sort((a, b) => a.file_name.localeCompare(b.file_name)); const preferred = docs.find((d) => text(d.prospective_buyer))?.prospective_buyer; const searchText = normalize([ key, preferred, ...docs.flatMap((d) => [d.types_of_business_raw, d.notes_business_raw, d.address]), ].filter(Boolean).join("\n")); return { key, displayName: text(preferred) || key, documents: docs, searchText }; }) .sort((a, b) => a.key.localeCompare(b.key)); } export function filterGroups(groups: PersonGroup[], query: string): PersonGroup[] { const terms = normalize(query).split(/\s+/).filter(Boolean); if (!terms.length) return groups; return groups.filter((group) => terms.every((term) => group.searchText.includes(term))); }