import type { AdminReviewResponseDto, CreateReviewDto, HostReplyDto, OrganizerReviewResponseDto, ReviewResponseDto, UpdateReviewDto, } from '@/api/generated/models' import { getAdminReviews } from '@/api/generated/admin-reviews/admin-reviews' import { getReviews } from '@/api/generated/reviews/reviews' import { unwrapApiPayload } from '@/helpers/listResponse' import { parseRemittanceList } from '@/helpers/listResponse' import { errorResult, handleServiceError, type ServiceCallOptions, type ServiceResult, shouldBubbleErrorToParent, successResult, } from '@/services/errorHandler' export type EventReview = ReviewResponseDto export type AdminEventReview = AdminReviewResponseDto export type OrganizerReview = OrganizerReviewResponseDto const reviewsApi = getReviews() const adminReviewsApi = getAdminReviews() export const EVENT_REVIEWS_PAGE_SIZE = 10 export const ORGANIZER_REVIEWS_PAGE_SIZE = 10 interface PaginatedReviews { items: T[] response?: { totalItemsCount?: number; totalPages?: number; page?: number } } const unwrapItems = (payload: unknown): T[] => { if (Array.isArray(payload)) return payload as T[] if (payload && typeof payload === 'object' && Array.isArray((payload as PaginatedReviews).items)) { return (payload as PaginatedReviews).items } return [] } export const LIST_EVENT_REVIEWS_PAGE = async ( eventId: string, page = 1, pageSize = EVENT_REVIEWS_PAGE_SIZE, options?: ServiceCallOptions ): Promise> => { try { const res = await reviewsApi.reviewsControllerListByEvent(eventId, { sort: '-createdAt', page, pageSize, }) const parsed = parseRemittanceList(res.data, 'items', page, pageSize) return successResult({ items: parsed.items, page: parsed.pagination.page, totalItemsCount: parsed.pagination.totalItemsCount, totalPages: parsed.pagination.totalPages ?? 0, }) } catch (error) { const normalizedError = handleServiceError(error, options) if (shouldBubbleErrorToParent(options)) throw normalizedError return errorResult(normalizedError) } } /** Admin list for one event — includes published, hidden, and deleted reviews. */ export const LIST_ADMIN_EVENT_REVIEWS_PAGE = async ( eventId: string, page = 1, pageSize = EVENT_REVIEWS_PAGE_SIZE, options?: ServiceCallOptions ): Promise> => { try { const res = await adminReviewsApi.adminReviewsControllerList({ sort: '-createdAt', page, pageSize, 'filters[eventId]': eventId, }) const parsed = parseRemittanceList(res.data, 'items', page, pageSize) return successResult({ items: parsed.items, page: parsed.pagination.page, totalItemsCount: parsed.pagination.totalItemsCount, totalPages: parsed.pagination.totalPages ?? 0, }) } catch (error) { const normalizedError = handleServiceError(error, options) if (shouldBubbleErrorToParent(options)) throw normalizedError return errorResult(normalizedError) } } export const LIST_EVENT_REVIEWS = async (eventId: string, options?: ServiceCallOptions): Promise> => { const result = await LIST_EVENT_REVIEWS_PAGE(eventId, 1, 50, options) return result.ok ? successResult(result.data.items) : result } export const LIST_ORGANIZER_REVIEWS = async ( organizerId: string, options?: ServiceCallOptions ): Promise> => { try { const res = await reviewsApi.reviewsControllerListByOrganizer(organizerId, { sort: '-createdAt', page: 1, pageSize: 50, }) return successResult(unwrapItems(unwrapApiPayload(res.data))) } catch (error) { const normalizedError = handleServiceError(error, options) if (shouldBubbleErrorToParent(options)) throw normalizedError return errorResult(normalizedError) } } export const LIST_ORGANIZER_REVIEWS_PAGE = async ( organizerId: string, page = 1, pageSize = ORGANIZER_REVIEWS_PAGE_SIZE, options?: ServiceCallOptions ): Promise> => { try { const res = await reviewsApi.reviewsControllerListByOrganizer(organizerId, { sort: '-createdAt', page, pageSize, }) const parsed = parseRemittanceList(res.data, 'items', page, pageSize) return successResult({ items: parsed.items, page: parsed.pagination.page, totalItemsCount: parsed.pagination.totalItemsCount, totalPages: parsed.pagination.totalPages ?? 0, }) } catch (error) { const normalizedError = handleServiceError(error, options) if (shouldBubbleErrorToParent(options)) throw normalizedError return errorResult(normalizedError) } } /** Published review by this user for the event, if any (from the public event list). */ export const FIND_MY_EVENT_REVIEW = async ( eventId: string, userId: string, options?: ServiceCallOptions ): Promise> => { const result = await LIST_EVENT_REVIEWS(eventId, options) if (!result.ok) return result return successResult(result.data.find((review) => review.userId === userId) ?? null) } export const CREATE_REVIEW = async ( eventId: string, dto: CreateReviewDto, options?: ServiceCallOptions ): Promise> => { try { const res = await reviewsApi.reviewsControllerCreate(eventId, dto) return successResult(unwrapApiPayload(res.data)) } catch (error) { const normalizedError = handleServiceError(error, options) if (shouldBubbleErrorToParent(options)) throw normalizedError return errorResult(normalizedError) } } export const UPDATE_REVIEW = async ( reviewId: string, dto: UpdateReviewDto, options?: ServiceCallOptions ): Promise> => { try { const res = await reviewsApi.reviewsControllerUpdate(reviewId, dto) return successResult(unwrapApiPayload(res.data)) } catch (error) { const normalizedError = handleServiceError(error, options) if (shouldBubbleErrorToParent(options)) throw normalizedError return errorResult(normalizedError) } } export const HOST_REPLY_REVIEW = async ( reviewId: string, dto: HostReplyDto, options?: ServiceCallOptions ): Promise> => { try { const res = await reviewsApi.reviewsControllerHostReply(reviewId, dto) return successResult(unwrapApiPayload(res.data)) } catch (error) { const normalizedError = handleServiceError(error, options) if (shouldBubbleErrorToParent(options)) throw normalizedError return errorResult(normalizedError) } }