import { BirthProfileTimezoneError, resolveMissingBirthTimezoneOffset } from "./birth-profile-timezone.ts"; import { resolveServerOwnedChartBirth, unresolvedChartBirth, type ChartBirthFailureReason, type ServerOwnedChartBirth, } from "./chart-birth-truth.ts"; import type { ChartViewProfileInput } from "./chart-view-mapper.ts"; export type ChartViewProfileRead = | { ok: true; profile: ChartViewProfileInput; birth: ServerOwnedChartBirth } | { ok: false; failure: ChartBirthFailureReason; birth: ServerOwnedChartBirth }; function text(value: unknown): string | undefined { if (typeof value !== "string") return undefined; const trimmed = value.trim(); return trimmed.length > 0 ? trimmed : undefined; } function isTimezoneFailure(error: unknown): boolean { return error instanceof BirthProfileTimezoneError || (error instanceof Error && error.name === "BirthProfileTimezoneError"); } function chartInput(row: unknown, birth: ServerOwnedChartBirth): ChartViewProfileInput | null { if (!birth.chartable || birth.date == null || birth.time == null || birth.timezoneOffset == null) return null; const source = row !== null && typeof row === "object" && !Array.isArray(row) ? row as Record : {}; const latitude = typeof source.latitude === "number" ? source.latitude : Number(source.latitude); const longitude = typeof source.longitude === "number" ? source.longitude : Number(source.longitude); if (!Number.isFinite(latitude) || !Number.isFinite(longitude)) return null; return { name: text(source.name), date: birth.date, time: birth.time, placeLabel: text(source.birth_place_label), latitude, longitude, timezoneOffset: birth.timezoneOffset, timezoneId: birth.timezoneId ?? undefined, ayanamsa: typeof source.ayanamsa === "string" ? source.ayanamsa : undefined, birthTimeStatus: birth.status ?? undefined, }; } export async function prepareChartViewProfile(input: { row: unknown; queryError?: unknown; resolveTimezone?: typeof resolveMissingBirthTimezoneOffset; }): Promise { if (input.queryError) { return { ok: false, failure: "profile_query_error", birth: unresolvedChartBirth("profile_query_error"), }; } const stored = resolveServerOwnedChartBirth(input.row); if (stored.failure === "adopted_calculation_incomplete") { return { ok: false, failure: stored.failure, birth: stored }; } const resolveTimezone = input.resolveTimezone ?? resolveMissingBirthTimezoneOffset; let resolved: unknown; try { resolved = await resolveTimezone(input.row, { useActiveDate: true }); } catch (error) { if (!isTimezoneFailure(error)) throw error; return { ok: false, failure: "timezone_resolver_failure", birth: { ...stored, failure: "timezone_resolver_failure", chartable: false, timezoneOffset: null, }, }; } const filled = resolveServerOwnedChartBirth(resolved); // Keep the stored-row fingerprint so account GET and chart-view name the // same profile even when a missing declared offset was filled in memory. const birth = { ...filled, fingerprint: stored.fingerprint }; if (birth.failure === "adopted_calculation_incomplete") { return { ok: false, failure: birth.failure, birth }; } const profile = chartInput(resolved, birth); if (!profile || birth.failure) { return { ok: false, failure: birth.failure ?? "profile_incomplete", birth: { ...birth, failure: birth.failure ?? "profile_incomplete", chartable: false }, }; } return { ok: true, profile, birth }; }