import { toAdminMarketValuationDto, toAdminPricingObservationDto } from '@pokemon-inventory/contracts/pricing'; import { createMarketValueOverrideSchema, createPricingObservationSchema } from '@pokemon-inventory/validation/pricing'; import { createApplicationError } from '../../../shared/errors/application-error.js'; function validationError(reply, result) { return reply.code(400).send({ error: { code: 'VALIDATION_ERROR', message: 'Request validation failed.', details: result.error.issues.map(({ message, path }) => ({ message, path })), }, }); } export async function registerAdminPricingRoutes(app, options) { const { authenticateAdmin = async () => { throw createApplicationError('UNAUTHORIZED', 'Authentication is required.', 401); }, authorizeUnsafeRequest, sessionCookieName = 'pokemon_inventory_session', pricingService, } = options; app.addHook('preHandler', async (request) => { const admin = await authenticateAdmin(request); if (!admin?.sellerId) throw createApplicationError('UNAUTHORIZED', 'Authentication is required.', 401); request.admin = admin; }); app.post('/pricing/observations', async (request, reply) => { await authorizeUnsafeRequest?.(request.cookies[sessionCookieName], request.headers['x-csrf-token']); const result = createPricingObservationSchema.safeParse(request.body); if (!result.success) return validationError(reply, result); const observation = await pricingService.addObservation({ ...result.data, sellerId: request.admin.sellerId }); return reply.code(201).send({ data: toAdminPricingObservationDto(observation) }); }); app.post('/inventory/:id/valuation', async (request, reply) => { await authorizeUnsafeRequest?.(request.cookies[sessionCookieName], request.headers['x-csrf-token']); const valuation = await pricingService.calculate({ sellerId: request.admin.sellerId, inventoryItemId: request.params.id }); return reply.code(200).send({ data: toAdminMarketValuationDto(valuation) }); }); app.post('/inventory/:id/valuation/override', async (request, reply) => { await authorizeUnsafeRequest?.(request.cookies[sessionCookieName], request.headers['x-csrf-token']); const result = createMarketValueOverrideSchema.safeParse(request.body); if (!result.success) return validationError(reply, result); const override = await pricingService.override({ ...result.data, inventoryItemId: request.params.id, sellerId: request.admin.sellerId, actorUserId: request.admin.userId, }); return reply.code(201).send({ data: override }); }); }