import { Router } from 'express' import { optionalRenterAuth } from '../../middleware/requireRenterAuth' import { parseBody, parseParams, parseQuery } from '../../http/validate' import { ok, created } from '../../http/respond' import { isDatabaseUnavailableError } from '../../lib/isDatabaseUnavailable' import * as service from './marketplace.service' import { paginationSchema, searchSchema, companiesQuerySchema, marketplaceReservationSchema, reviewBodySchema, slugParamSchema, vehicleParamSchema, reviewTokenSchema, offerCodeParamSchema, vehicleAvailabilityQuerySchema, marketplaceFunnelEventSchema, } from './marketplace.schemas' const router = Router() router.use(optionalRenterAuth) router.get('/offers', async (_req, res, next) => { try { ok(res, await service.getPublicOffers()) } catch (err) { if (isDatabaseUnavailableError(err)) return res.json({ data: [] }) next(err) } }) router.get('/cities', async (_req, res, next) => { try { ok(res, await service.getCities()) } catch (err) { if (isDatabaseUnavailableError(err)) return res.json({ data: [] }) next(err) } }) router.get('/companies', async (req, res, next) => { try { const { city, hasOffer } = parseQuery(companiesQuerySchema, req) const { page, pageSize } = parseQuery(paginationSchema, req) ok(res, await service.getListedCompanies({ city, hasOffer, page, pageSize })) } catch (err) { if (isDatabaseUnavailableError(err)) return res.json({ data: [] }) next(err) } }) router.get('/search', async (req, res, next) => { try { const filters = parseQuery(searchSchema, req) const pagination = parseQuery(paginationSchema, req) ok(res, await service.searchVehicles({ ...filters, ...pagination })) } catch (err) { if (isDatabaseUnavailableError(err)) return res.json({ data: [] }) next(err) } }) router.post('/reservations', async (req, res, next) => { try { const body = parseBody(marketplaceReservationSchema, req) const result = await service.createMarketplaceReservation(body) created(res, result) } catch (err) { if (isDatabaseUnavailableError(err)) { return res.status(503).json({ error: 'database_unavailable', message: 'Service temporarily unavailable', statusCode: 503 }) } next(err) } }) router.post('/events', async (req, res, next) => { try { const body = parseBody(marketplaceFunnelEventSchema, req) ok(res, await service.trackMarketplaceFunnelEvent(body, req.renterId)) } catch (err) { if (isDatabaseUnavailableError(err)) { return res.status(503).json({ error: 'database_unavailable', message: 'Analytics events are temporarily unavailable', statusCode: 503 }) } next(err) } }) router.get('/review/:token', async (req, res, next) => { try { const { token } = parseParams(reviewTokenSchema, req) ok(res, await service.getReviewContext(token)) } catch (err) { next(err) } }) router.post('/review/:token', async (req, res, next) => { try { const { token } = parseParams(reviewTokenSchema, req) const body = parseBody(reviewBodySchema, req) const result = await service.submitReview(token, body) created(res, result) } catch (err) { next(err) } }) router.post('/offers/:code/validate', async (req, res, next) => { try { const { code } = parseParams(offerCodeParamSchema, req) ok(res, await service.validateOfferCode(code)) } catch (err) { if (isDatabaseUnavailableError(err)) { return res.status(503).json({ error: 'database_unavailable', message: 'Offer validation is temporarily unavailable', statusCode: 503 }) } next(err) } }) router.get('/:slug', async (req, res, next) => { try { const { slug } = parseParams(slugParamSchema, req) ok(res, await service.getCompanyPage(slug)) } catch (err) { if (isDatabaseUnavailableError(err)) { return res.status(503).json({ error: 'database_unavailable', message: 'Marketplace data is temporarily unavailable', statusCode: 503 }) } next(err) } }) router.get('/:slug/reviews', async (req, res, next) => { try { const { slug } = parseParams(slugParamSchema, req) ok(res, await service.getCompanyReviews(slug)) } catch (err) { if (isDatabaseUnavailableError(err)) return res.json({ data: [] }) next(err) } }) router.get('/:slug/vehicles', async (req, res, next) => { try { const { slug } = parseParams(slugParamSchema, req) ok(res, await service.getCompanyVehicles(slug)) } catch (err) { if (isDatabaseUnavailableError(err)) return res.json({ data: [] }) next(err) } }) router.get('/:slug/vehicles/:id', async (req, res, next) => { try { const { slug, id } = parseParams(vehicleParamSchema, req) ok(res, await service.getVehicleDetail(slug, id)) } catch (err) { if (isDatabaseUnavailableError(err)) { return res.status(503).json({ error: 'database_unavailable', message: 'Vehicle details are temporarily unavailable', statusCode: 503 }) } next(err) } }) router.get('/:slug/vehicles/:id/availability', async (req, res, next) => { try { const { slug, id } = parseParams(vehicleParamSchema, req) const { startDate, endDate } = parseQuery(vehicleAvailabilityQuerySchema, req) ok(res, await service.getMarketplaceVehicleAvailability(slug, id, { startDate, endDate })) } catch (err) { if (isDatabaseUnavailableError(err)) { return res.status(503).json({ error: 'database_unavailable', message: 'Availability checks are temporarily unavailable', statusCode: 503 }) } next(err) } }) router.get('/:slug/offers', async (req, res, next) => { try { const { slug } = parseParams(slugParamSchema, req) ok(res, await service.getCompanyOffers(slug)) } catch (err) { if (isDatabaseUnavailableError(err)) return res.json({ data: [] }) next(err) } }) export default router