import { useMemo } from 'react'; import { useQuery } from '@tanstack/react-query'; import { api } from '../lib/api'; import type { ApiResponse } from '../lib/api'; import { breakdownOf, type BillableLine, type ShareBreakdown, type TenantContract } from '../lib/insuranceShares'; interface ServiceCategoryRow { key: string; label: string; enabled: boolean; } interface PricingPayload { service_categories?: ServiceCategoryRow[]; default_service_category?: string | null; /** «قیمت ویزیت آزاد» tenant — سرور وقتی نوبت قیمت ندارد همین را می‌گذارد. */ free_visit_price_rials?: number; } /** * انتخاب بیمهٔ یک نوبت: نوع خدماتِ فعالِ همین پزشک/کلینیک و قراردادهای بیمهٔ پایهٔ فعال، * به‌همراه محاسبهٔ سهم — مشترک بین مودال «قطعی کردن نوبت» و صفحهٔ ویرایش نوبت تا * هر دو یک قاعده را نشان دهند. */ export function useAppointmentInsurance(enabled: boolean) { const pricingQuery = useQuery>({ queryKey: ['insurance-pricing'], queryFn: () => api.get('/api/v1/insurance-pricing'), enabled, }); const contractsQuery = useQuery>({ queryKey: ['tenant-insurances'], queryFn: () => api.get('/api/v1/billing/tenant-insurances'), enabled, }); const pricing = (pricingQuery.data?.data ?? {}) as PricingPayload; const enabledCategories = useMemo( () => (pricing.service_categories ?? []).filter((c) => c.enabled), [pricing.service_categories], ); const contracts: TenantContract[] = useMemo( () => ((contractsQuery.data?.data as any)?.data ?? []) as TenantContract[], [contractsQuery.data], ); const activeContracts = useMemo(() => contracts.filter((c) => c.is_active !== false), [contracts]); const basicContracts = useMemo( () => activeContracts.filter((c) => c.insurance_kind !== 'supplementary'), [activeContracts], ); const supplementaryContracts = useMemo( () => activeContracts.filter((c) => c.insurance_kind === 'supplementary'), [activeContracts], ); const optionsOf = (list: TenantContract[]) => list.map((c) => ({ value: String(c.insurance_id), label: c.insurance_name ?? `#${c.insurance_id}` })); return { /** * هزینهٔ ویزیتِ مؤثر — آینهٔ همان fallback سرور: قیمت خودِ نوبت، در نبودش * «قیمت ویزیت آزاد» تنظیمات همین tenant. */ visitPriceOf: (appointmentVisitPrice: number | null | undefined): number => Number(appointmentVisitPrice ?? 0) > 0 ? Number(appointmentVisitPrice) : Number(pricing.free_visit_price_rials ?? 0), /** فقط وقتی بیش از یک نوع فعال است، انتخاب از کاربر پرسیده می‌شود. */ needsCategoryChoice: enabledCategories.length > 1, categoryOptions: enabledCategories.map((c) => ({ value: c.key, label: c.label })), /** تنها نوع فعال (یا null اگر چند نوع فعال باشد) — همان قاعدهٔ سرور. */ defaultCategory: pricing.default_service_category ?? enabledCategories[0]?.key ?? null, categoryLabelOf: (key: string | null | undefined) => (pricing.service_categories ?? []).find((c) => c.key === key)?.label ?? null, insuranceOptions: optionsOf(basicContracts), /** قراردادهای تکمیلیِ فعال — روی باقیماندهٔ بعد از بیمهٔ پایه اعمال می‌شوند. */ supplementaryOptions: optionsOf(supplementaryContracts), hasSupplementary: supplementaryContracts.length > 0, contractOf: (insuranceId: string | number | null | undefined): TenantContract | null => basicContracts.find((c) => String(c.insurance_id) === String(insuranceId)) ?? null, insuranceNameOf: (insuranceId: string | number | null | undefined): string | null => contracts.find((c) => String(c.insurance_id) === String(insuranceId))?.insurance_name ?? null, /** تفکیک زنجیره‌ای سهم‌ها: پایه روی کل، تکمیلی روی باقیمانده. */ breakdown: ( lines: BillableLine[], insuranceId: string | number | null | undefined, supplementaryId: string | number | null | undefined = null, ): ShareBreakdown => breakdownOf( lines, basicContracts.find((c) => String(c.insurance_id) === String(insuranceId)) ?? null, supplementaryContracts.find((c) => String(c.insurance_id) === String(supplementaryId)) ?? null, ), isLoading: pricingQuery.isLoading || contractsQuery.isLoading, }; }