import { toEnglishDigits } from "src/lookups/fanavaran-last-car-policy"; import { parseJalaliDateParts, pickPersonBirthday, pickPersonNationalCode, } from "./fanavaran-driver-inquiry"; export type FanavaranLookupRow = { Id?: unknown; Caption?: unknown; Name?: unknown; IsActive?: unknown; }; export type FanavaranOtherPeopleLookups = { cities?: unknown; gender?: unknown; maritalStatus?: unknown; ans?: unknown; countries?: unknown; personKind?: unknown; }; export type FanavaranOtherPeopleSource = { nationalCode?: unknown; birthday?: unknown; fullName?: unknown; fatherName?: unknown; mobile?: unknown; tel?: unknown; email?: unknown; address?: unknown; jobAddress?: unknown; postalCode?: unknown; cityName?: unknown; gender?: unknown; isIranian?: boolean; naturalizedCode?: unknown; identityNo?: unknown; identityNoIssuPlace?: unknown; passportNo?: unknown; companyCode?: unknown; economicCode?: unknown; registerNo?: unknown; }; export type FanavaranOtherPeoplePayload = { NationalCode: string | null; Name: string | null; LastName: string | null; FatherName: string | null; BirthYear: number | null; BirthMonth: number | null; BirthDay: number | null; ADBirthYear: null; ADBirthMonth: null; ADBirthDay: null; IdentityNoIssuPlace: string | null; PassportNo: string | null; Address: string | null; PostalCode: string | null; Tel: string | null; Mobile: string | null; Email: string | null; JobAddress: string | null; EconomicCode: string | null; NaturalizedCode: string | null; CompanyCode: string | null; IdentityNo: string | null; RegisterNo: string | null; CityId: number | null; GenderId: number | null; MaritalStatus: number | null; IsIranian: number | string | null; NationalityId: number | null; PersonKindId: number | null; }; const GENDER_MALE_TEXTS = ["مرد", "آقا", "male", "m"]; const GENDER_FEMALE_TEXTS = ["زن", "خانم", "female", "f"]; const ANS_YES_TEXTS = ["بله", "بلی", "yes", "1"]; const NATURAL_PERSON_TEXTS = ["حقیقی", "شخص حقیقی", "طبيعي", "natural"]; const IRAN_COUNTRY_TEXTS = ["ایران", "ايران", "iran"]; function asLookupRows(value: unknown): FanavaranLookupRow[] { if (!Array.isArray(value)) return []; return value.filter( (row): row is FanavaranLookupRow => !!row && typeof row === "object" && !Array.isArray(row), ); } function asPositiveId(value: unknown): number | null { if (value === null || value === undefined) return null; const id = Number(value); return Number.isFinite(id) && id > 0 ? id : null; } function normalizeLookupText(value: unknown): string { return toEnglishDigits(value) .toLowerCase() .replace(/[ي]/g, "ی") .replace(/[ك]/g, "ک") .replace(/[\u200c\s_\-\/]+/g, "") .replace(/[^\p{L}\p{N}]/gu, ""); } function lookupRowId(row: FanavaranLookupRow): number | null { return asPositiveId(row.Id); } function lookupRowTexts(row: FanavaranLookupRow): string[] { return [row.Caption, row.Name] .filter((value): value is string => typeof value === "string") .filter(Boolean); } export function pickLookupIdByCaption( rows: unknown, texts: unknown[], ): number | null { const wanted = texts .map((text) => normalizeLookupText(text)) .filter(Boolean); if (!wanted.length) return null; for (const row of asLookupRows(rows)) { if (row.IsActive === 0) continue; const rowTexts = lookupRowTexts(row).map(normalizeLookupText); const matched = rowTexts.some((rowText) => wanted.some( (want) => rowText === want || rowText.includes(want) || want.includes(rowText), ), ); if (matched) return lookupRowId(row); } return null; } export function splitPersianFullName( fullName: unknown, ): { name: string | null; lastName: string | null } { const trimmed = String(fullName ?? "").trim().replace(/\s+/g, " "); if (!trimmed) return { name: null, lastName: null }; const parts = trimmed.split(" "); if (parts.length === 1) return { name: parts[0], lastName: null }; return { name: parts[0], lastName: parts.slice(1).join(" ") }; } export function normalizeIranMobile(value: unknown): string | null { const digits = toEnglishDigits(value).replace(/\D/g, ""); if (!digits) return null; if (digits.length === 10 && digits.startsWith("9")) return `0${digits}`; if (digits.length === 11 && digits.startsWith("09")) return digits; if (digits.length === 12 && digits.startsWith("989")) { return `0${digits.slice(2)}`; } return digits.length >= 8 ? digits : null; } export function pickFanavaranRecordId(value: unknown): number | null { if (value == null) return null; if (typeof value === "number" || typeof value === "string") { return asPositiveId(value); } if (Array.isArray(value)) { for (const item of value) { const id = pickFanavaranRecordId(item); if (id != null) return id; } return null; } if (typeof value !== "object") return null; const record = value as Record; const direct = asPositiveId(record.Id ?? record.id); if (direct != null) return direct; for (const key of ["value", "Value", "data", "Data", "item", "Item"]) { const nested = pickFanavaranRecordId(record[key]); if (nested != null) return nested; } return null; } function emptyToNull(value: unknown): string | null { if (value == null) return null; const text = String(value).trim(); return text ? text : null; } export function buildFanavaranOtherPeoplePayload( source: FanavaranOtherPeopleSource, lookups: FanavaranOtherPeopleLookups = {}, ): FanavaranOtherPeoplePayload | null { const nationalCode = pickPersonNationalCode({ nationalCode: source.nationalCode, nationalCodeOfDriver: source.nationalCode, }); const birthday = parseJalaliDateParts( source.birthday ?? pickPersonBirthday({ birthday: source.birthday }), ); if (!nationalCode || !birthday) return null; const isIranian = source.isIranian !== false && !emptyToNull(source.naturalizedCode); const names = splitPersianFullName(source.fullName); const genderTexts = source.gender === "male" || source.gender === "m" ? GENDER_MALE_TEXTS : source.gender === "female" || source.gender === "f" ? GENDER_FEMALE_TEXTS : [source.gender]; return { NationalCode: nationalCode, Name: names.name, LastName: names.lastName, FatherName: emptyToNull(source.fatherName), BirthYear: birthday.year, BirthMonth: birthday.month, BirthDay: birthday.day, ADBirthYear: null, ADBirthMonth: null, ADBirthDay: null, IdentityNoIssuPlace: emptyToNull(source.identityNoIssuPlace), PassportNo: emptyToNull(source.passportNo), Address: emptyToNull(source.address), PostalCode: emptyToNull(source.postalCode), Tel: normalizeIranMobile(source.tel) ?? emptyToNull(source.tel), Mobile: normalizeIranMobile(source.mobile), Email: emptyToNull(source.email), JobAddress: emptyToNull(source.jobAddress), EconomicCode: emptyToNull(source.economicCode), NaturalizedCode: emptyToNull(source.naturalizedCode), CompanyCode: emptyToNull(source.companyCode), IdentityNo: emptyToNull(source.identityNo), RegisterNo: emptyToNull(source.registerNo), CityId: pickLookupIdByCaption(lookups.cities, [source.cityName]), GenderId: pickLookupIdByCaption(lookups.gender, genderTexts), MaritalStatus: pickLookupIdByCaption(lookups.maritalStatus, []), IsIranian: isIranian ? (pickLookupIdByCaption(lookups.ans, ANS_YES_TEXTS) ?? 1) : (pickLookupIdByCaption(lookups.ans, ["خیر", "no", "0"]) ?? 0), NationalityId: isIranian ? null : pickLookupIdByCaption(lookups.countries, IRAN_COUNTRY_TEXTS), PersonKindId: pickLookupIdByCaption( lookups.personKind, NATURAL_PERSON_TEXTS, ), }; }