import {useCallback, useState} from 'react' import {useMutation, useQuery, useQueryClient} from '@tanstack/react-query' import {addressAdd, addressDelete, addressEdit, addressList} from '@/api/address.ts' import {validateAddressFormSubmission} from '@/features/addressBook/addressValidation' import {notifyError} from '@/features/notifications' import {ensureSessionForAction} from '@/lib/authGuard' import {queryKeys} from '@/lib/queryKeys.ts' import {useUserStore} from '@/store/user.ts' import type {AddressListItem} from '@/types/address.type.ts' import type {AddAddressForm, AddressOption} from '@/types' type UseAddressBookOptions = { autoLoad?: boolean } const emptyAddressForm: AddAddressForm = { name: '', phone: '', detailedAddress: '', isDefault: false, } export function getAddressText(item: AddressListItem) { const regionText = item.region_text || item.region.map((part) => part.trim()).join(', ') return [regionText, item.detail_address].filter(Boolean).join(', ') } export function mapAddressToOption(item: AddressListItem): AddressOption { return { id: String(item.id), name: item.receiver_name, phone: item.phone, address: getAddressText(item), isDefault: item.default_setting === 1, } } export function mapAddressToForm(item: AddressListItem): AddAddressForm { return { name: item.receiver_name, phone: item.phone, detailedAddress: item.detail_address, isDefault: item.default_setting === 1, } } export function useAddressBook(options?: UseAddressBookOptions) { const queryClient = useQueryClient() const sessionId = useUserStore((state) => state.authInfo?.session_id ?? '') const [addressForm, setAddressForm] = useState(emptyAddressForm) const [loadAddressesLoading, setLoadAddressesLoading] = useState(false) const addressListQuery = useQuery({ queryKey: queryKeys.addressList(sessionId), enabled: Boolean(sessionId) && Boolean(options?.autoLoad), queryFn: async () => { const response = await addressList({session_id: sessionId!}) return response.data.list }, }) const saveAddressMutation = useMutation({ mutationFn: async (editingAddress?: AddressListItem | null) => { const payload = { session_id: sessionId!, receiver_name: addressForm.name.trim(), phone: addressForm.phone.trim(), detail_address: addressForm.detailedAddress.trim(), default_setting: addressForm.isDefault ? '1' : '0', } as const if (editingAddress) { return await addressEdit({ ...payload, id: String(editingAddress.id), }) } return await addressAdd(payload) }, }) const deleteAddressMutation = useMutation({ mutationFn: async (addressId: string) => { return await addressDelete({ id: addressId, session_id: sessionId!, }) }, }) const addresses = addressListQuery.data ?? [] const addressOptions = addresses.map(mapAddressToOption) const isAddressFormValid = validateAddressFormSubmission(addressForm).valid const loadAddresses = useCallback(async () => { if (!sessionId) { queryClient.removeQueries({queryKey: queryKeys.addressList(sessionId)}) return [] } setLoadAddressesLoading(true) try { const result = await queryClient.fetchQuery({ queryKey: queryKeys.addressList(sessionId), queryFn: async () => { const response = await addressList({session_id: sessionId}) return response.data.list }, }) return result } catch { return [] } finally { setLoadAddressesLoading(false) } }, [queryClient, sessionId]) const resetAddressForm = () => { setAddressForm(emptyAddressForm) saveAddressMutation.reset() } const fillAddressForm = (address?: AddressListItem | null) => { setAddressForm(address ? mapAddressToForm(address) : emptyAddressForm) saveAddressMutation.reset() } const changeAddressForm = (field: keyof AddAddressForm, value: AddAddressForm[keyof AddAddressForm]) => { setAddressForm((previous) => ({ ...previous, [field]: value, })) } const saveAddress = async (editingAddress?: AddressListItem | null) => { if (!ensureSessionForAction() || !sessionId) { return null } const validation = validateAddressFormSubmission(addressForm) if (!validation.valid) { notifyError(validation.message) return null } try { const response = await saveAddressMutation.mutateAsync(editingAddress) await queryClient.invalidateQueries({ queryKey: queryKeys.addressList(sessionId), }) return { addresses: await loadAddresses(), response, } } catch { return null } } const removeAddress = async (addressId: string) => { if (!ensureSessionForAction() || !sessionId) { return null } try { const response = await deleteAddressMutation.mutateAsync(addressId) await queryClient.invalidateQueries({ queryKey: queryKeys.addressList(sessionId), }) return response } catch { return null } } return { sessionId, addresses, addressOptions, loading: Boolean(sessionId) && (addressListQuery.isPending || loadAddressesLoading), addressForm, isAddressFormValid, submitLoading: saveAddressMutation.isPending, deleteLoading: deleteAddressMutation.isPending, loadAddresses, resetAddressForm, fillAddressForm, changeAddressForm, saveAddress, removeAddress, } }