import type { MarriageActiveCase, MarriageActiveSubscription, MarriageField, MarriageMatchSummary, MarriageProfileResponse, MarriageRecommendedPlan, } from "@/hooks/marriage/types"; export const REQUIRED_PROFILE_SECTION_COUNT = 9; /** * Normalizes a single MarriageField from various potential backend or Flutter bridge formats. */ export function normalizeMarriageField(raw: any): MarriageField | null { if (!raw || typeof raw !== "object") return null; const key = raw.key ?? raw.field_key ?? raw.fieldKey ?? raw.name ?? ""; const label = raw.label ?? raw.title ?? ""; const value = raw.value ?? raw.val ?? ""; const type = raw.type ?? raw.field_type ?? raw.fieldType ?? "text"; return { key: String(key), label: String(label), type: String(type), value: value ?? "", option_id: raw.option_id ?? raw.optionId ?? null, private: Boolean(raw.private ?? raw.is_private ?? false), }; } /** * Normalizes a match_summary object supporting snake_case, camelCase, and candidate structures. */ export function normalizeMatchSummary(raw: any): MarriageMatchSummary | null { if (!raw || typeof raw !== "object") return null; const rawPublicInfo = raw.public_info ?? raw.publicInfo ?? raw.fields ?? raw.public_fields ?? raw.publicFields ?? []; const publicInfo: MarriageField[] = Array.isArray(rawPublicInfo) ? rawPublicInfo .map(normalizeMarriageField) .filter((f): f is MarriageField => f !== null) : []; const rawId = raw.id ?? raw.candidate_id ?? raw.candidateId ?? 0; const rawGender = raw.gender ?? "female"; const rawPercent = raw.overall_completion_percent ?? raw.overallCompletionPercent ?? raw.completion_percent ?? raw.completionPercent ?? 0; return { id: Number(rawId) || 0, gender: rawGender, overall_completion_percent: Number(rawPercent) || 0, public_info: publicInfo, }; } /** * Normalizes a full MarriageProfileResponse from server, Flutter bridge, or localStorage. * Guarantees consistent snake_case format and type safety. */ export function normalizeMarriageProfile( raw: any, ): MarriageProfileResponse | null { if (!raw || typeof raw !== "object") return null; // Handle nested data wrappers e.g. { marriage: ... }, { profile: ... }, or { data: { marriage: ... } } const data = raw.marriage ?? raw.profile ?? raw.data?.marriage ?? raw.data?.profile ?? raw.data ?? raw; if (!data || typeof data !== "object") return null; const rawMatch = data.match_summary ?? data.matchSummary ?? data.match ?? data.candidate ?? null; const match_summary = normalizeMatchSummary(rawMatch); const rawActiveCase = data.active_case ?? data.activeCase ?? null; const active_case: MarriageActiveCase | null = rawActiveCase && typeof rawActiveCase === "object" ? { case_id: Number( rawActiveCase.case_id ?? rawActiveCase.caseId ?? rawActiveCase.id ?? 0, ), status: rawActiveCase.status ?? rawActiveCase.case_status ?? rawActiveCase.caseStatus ?? "introduced", introduced_at: rawActiveCase.introduced_at ?? rawActiveCase.introducedAt ?? new Date().toISOString(), contact_shared_at: rawActiveCase.contact_shared_at ?? rawActiveCase.contactSharedAt ?? null, payment_done_at: rawActiveCase.payment_done_at ?? rawActiveCase.paymentDoneAt ?? null, minutes_since_contact_shared: rawActiveCase.minutes_since_contact_shared ?? rawActiveCase.minutesSinceContactShared ?? null, can_report_no_contact: Boolean( rawActiveCase.can_report_no_contact ?? rawActiveCase.canReportNoContact ?? false, ), can_report_outcome: Boolean( rawActiveCase.can_report_outcome ?? rawActiveCase.canReportOutcome ?? false, ), has_outcome_reported: Boolean( rawActiveCase.has_outcome_reported ?? rawActiveCase.hasOutcomeReported ?? false, ), outcome_reason: rawActiveCase.outcome_reason ?? rawActiveCase.outcomeReason ?? null, outcome_note: rawActiveCase.outcome_note ?? rawActiveCase.outcomeNote ?? null, outcome_reported_by: rawActiveCase.outcome_reported_by ?? rawActiveCase.outcomeReportedBy ?? null, my_action: rawActiveCase.my_action ?? rawActiveCase.myAction ?? "pending", other_action: rawActiveCase.other_action ?? rawActiveCase.otherAction ?? undefined, } : null; const rawActiveSub = data.active_subscription ?? data.activeSubscription ?? null; const active_subscription: MarriageActiveSubscription | null = rawActiveSub && typeof rawActiveSub === "object" ? { id: Number(rawActiveSub.id ?? 1), plan: { id: Number(rawActiveSub.plan?.id ?? 1), title: String(rawActiveSub.plan?.title ?? "Subscription"), price: String(rawActiveSub.plan?.price ?? "0"), plan_type: String(rawActiveSub.plan?.plan_type ?? "standard"), duration_days: rawActiveSub.plan?.duration_days !== undefined ? Number(rawActiveSub.plan.duration_days) : null, usage_limit: rawActiveSub.plan?.usage_limit !== undefined ? Number(rawActiveSub.plan.usage_limit) : null, }, start_date: String(rawActiveSub.start_date ?? new Date().toISOString()), end_date: rawActiveSub.end_date ? String(rawActiveSub.end_date) : null, total_usages: Number(rawActiveSub.total_usages ?? 0), is_active: Boolean( rawActiveSub.is_active ?? rawActiveSub.isActive ?? rawActiveSub.valid ?? true, ), is_valid: Boolean( rawActiveSub.is_valid ?? rawActiveSub.isValid ?? rawActiveSub.valid ?? true, ), remaining_days: rawActiveSub.remaining_days !== undefined ? Number(rawActiveSub.remaining_days) : undefined, } : null; const rawRecommendedPlan = data.recommended_plan ?? data.recommendedPlan ?? null; const recommended_plan: MarriageRecommendedPlan | null = rawRecommendedPlan && typeof rawRecommendedPlan === "object" ? { id: Number(rawRecommendedPlan.id ?? 1), title: String(rawRecommendedPlan.title ?? ""), price: String(rawRecommendedPlan.price ?? "50"), } : null; return { id: Number(data.id ?? data.profile_id ?? data.profileId ?? 0), status: data.status ?? "pending_onboarding", gender: data.gender ?? null, age: data.age !== undefined && data.age !== null ? Number(data.age) : null, is_registering_for_self: data.is_registering_for_self !== undefined ? Boolean(data.is_registering_for_self) : data.isRegisteringForSelf !== undefined ? Boolean(data.isRegisteringForSelf) : null, can_edit_profile: data.can_edit_profile !== undefined ? Boolean(data.can_edit_profile) : data.canEditProfile !== undefined ? Boolean(data.canEditProfile) : true, can_message_expert: data.can_message_expert !== undefined ? Boolean(data.can_message_expert) : data.canMessageExpert !== undefined ? Boolean(data.canMessageExpert) : true, active_subscription, is_ready_for_match: data.is_ready_for_match !== undefined ? Boolean(data.is_ready_for_match) : data.isReadyForMatch !== undefined ? Boolean(data.isReadyForMatch) : true, active_case, needs_subscription: Boolean( data.needs_subscription ?? data.needsSubscription ?? false, ), recommended_plan, match_summary, intro_video_url: data.intro_video_url ?? data.introVideoUrl ?? null, intro_video_thumbnail_url: data.intro_video_thumbnail_url ?? data.introVideoThumbnailUrl ?? null, unseen_rejection: data.unseen_rejection ?? data.unseenRejection ?? null, }; }