import { Router } from 'express' import { z } from 'zod' import { prisma } from '../lib/prisma' import { requireCompanyAuth } from '../middleware/requireCompanyAuth' import { requireTenant } from '../middleware/requireTenant' import { requireSubscription } from '../middleware/requireSubscription' import { requireRole } from '../middleware/requireRole' const router = Router() router.use(requireCompanyAuth, requireTenant, requireSubscription) const offerSchema = z.object({ title: z.string().min(1), description: z.string().optional(), termsAndConds: z.string().optional(), type: z.enum(['PERCENTAGE','FIXED_AMOUNT','FREE_DAY','SPECIAL_RATE']), discountValue: z.number().int().min(0), specialRate: z.number().int().optional(), appliesToAll: z.boolean().default(true), categories: z.array(z.enum(['ECONOMY','COMPACT','MIDSIZE','FULLSIZE','SUV','LUXURY','VAN','TRUCK'])).default([]), minRentalDays: z.number().int().optional(), maxRentalDays: z.number().int().optional(), promoCode: z.string().optional(), maxRedemptions: z.number().int().optional(), validFrom: z.string().datetime(), validUntil: z.string().datetime(), isActive: z.boolean().default(true), isPublic: z.boolean().default(true), isFeatured: z.boolean().default(false), vehicleIds: z.array(z.string()).default([]), }) router.get('/', async (req, res, next) => { try { const { active, public: pub } = req.query as Record const where: any = { companyId: req.companyId } if (active !== undefined) where.isActive = active === 'true' if (pub !== undefined) where.isPublic = pub === 'true' const offers = await prisma.offer.findMany({ where, orderBy: { createdAt: 'desc' } }) res.json({ data: offers }) } catch (err) { next(err) } }) router.post('/', requireRole('MANAGER'), async (req, res, next) => { try { const { vehicleIds, ...body } = offerSchema.parse(req.body) const offer = await prisma.offer.create({ data: { ...body, companyId: req.companyId, validFrom: new Date(body.validFrom), validUntil: new Date(body.validUntil), vehicles: vehicleIds.length > 0 ? { create: vehicleIds.map((id) => ({ vehicleId: id })) } : undefined }, include: { vehicles: true }, }) res.status(201).json({ data: offer }) } catch (err) { next(err) } }) router.get('/:id', async (req, res, next) => { try { const offer = await prisma.offer.findFirstOrThrow({ where: { id: req.params.id, companyId: req.companyId }, include: { vehicles: true } }) res.json({ data: offer }) } catch (err) { next(err) } }) router.patch('/:id', requireRole('MANAGER'), async (req, res, next) => { try { const { id } = z.object({ id: z.string() }).parse(req.params) const { vehicleIds, ...body } = offerSchema.partial().parse(req.body) const existing = await prisma.offer.findFirst({ where: { id, companyId: req.companyId } }) if (!existing) return res.status(404).json({ error: 'not_found', message: 'Offer not found', statusCode: 404 }) await prisma.$transaction(async (tx) => { await tx.offer.update({ where: { id }, data: { ...body, validFrom: body.validFrom ? new Date(body.validFrom) : undefined, validUntil: body.validUntil ? new Date(body.validUntil) : undefined } }) if (vehicleIds !== undefined) { await tx.offerVehicle.deleteMany({ where: { offerId: id } }) if (vehicleIds.length > 0) { await tx.offerVehicle.createMany({ data: vehicleIds.map((vehicleId) => ({ offerId: id, vehicleId })) }) } } }) const updated = await prisma.offer.findUniqueOrThrow({ where: { id }, include: { vehicles: true } }) res.json({ data: updated }) } catch (err) { next(err) } }) router.delete('/:id', requireRole('MANAGER'), async (req, res, next) => { try { await prisma.offer.deleteMany({ where: { id: req.params.id, companyId: req.companyId } }) res.json({ data: { success: true } }) } catch (err) { next(err) } }) router.post('/:id/activate', requireRole('MANAGER'), async (req, res, next) => { try { await prisma.offer.updateMany({ where: { id: req.params.id, companyId: req.companyId }, data: { isActive: true } }) res.json({ data: { success: true } }) } catch (err) { next(err) } }) router.post('/:id/deactivate', requireRole('MANAGER'), async (req, res, next) => { try { await prisma.offer.updateMany({ where: { id: req.params.id, companyId: req.companyId }, data: { isActive: false } }) res.json({ data: { success: true } }) } catch (err) { next(err) } }) router.get('/:id/stats', async (req, res, next) => { try { const offer = await prisma.offer.findFirstOrThrow({ where: { id: req.params.id, companyId: req.companyId } }) const reservations = await prisma.reservation.count({ where: { offerId: offer.id } }) res.json({ data: { redemptions: offer.redemptionCount, reservations } }) } catch (err) { next(err) } }) export default router