const express = require('express'); const prisma = require('../db'); const { asyncHandler, httpError } = require('../lib/errors'); const { isValidPhone, normalizePhone } = require('../lib/phone'); const { canAccessDealer } = require('../lib/access'); const { userPublicSelect, publicUser } = require('../lib/users'); const { requireAuth, requireRole } = require('../middleware/auth'); const router = express.Router(); router.use(requireAuth); router.get( '/dealers', requireRole('superAdmin'), asyncHandler(async (req, res) => { const dealers = await prisma.dealer.findMany({ orderBy: { name: 'asc' } }); return res.json({ success: true, data: dealers }); }) ); router.post( '/dealers', requireRole('superAdmin'), asyncHandler(async (req, res) => { const name = String(req.body?.name || '').trim(); const code = String(req.body?.code || '').trim(); const district = String(req.body?.district || '').trim() || null; const address = String(req.body?.address || '').trim() || null; const rawPhone = String(req.body?.phone || '').trim(); const phone = rawPhone ? normalizePhone(rawPhone) : null; if (!name || !code) throw httpError(400, 'Name and code are required'); if (phone && !isValidPhone(phone)) { throw httpError(400, 'Dealer phone must be a Sri Lankan mobile number'); } const dealer = await prisma.dealer.create({ data: { name, code, district, address, phone }, }); return res.status(201).json({ success: true, data: dealer }); }) ); router.get( '/sales-reps', requireRole('superAdmin'), asyncHandler(async (req, res) => { const reps = await prisma.user.findMany({ where: { role: 'salesRep' }, select: userPublicSelect, orderBy: { name: 'asc' }, }); return res.json({ success: true, data: reps.map((rep) => publicUser(rep)) }); }) ); router.post( '/sales-reps', requireRole('superAdmin'), asyncHandler(async (req, res) => { const name = String(req.body?.name || '').trim(); const phone = normalizePhone(req.body?.phone); const dealerIds = Array.isArray(req.body?.dealerIds) ? req.body.dealerIds : []; if (!name || !isValidPhone(phone)) { throw httpError(400, 'Name and a 947XXXXXXXX phone are required'); } if (!dealerIds.every((id) => typeof id === 'string' && id.trim())) { throw httpError(400, 'dealerIds must be a list of ids'); } const uniqueIds = [...new Set(dealerIds.map((id) => id.trim()))]; if (uniqueIds.length) { const found = await prisma.dealer.findMany({ where: { id: { in: uniqueIds } } }); if (found.length !== uniqueIds.length) throw httpError(404, 'Dealer not found'); } const user = await prisma.user.create({ data: { name, phone, role: 'salesRep', assignments: { create: uniqueIds.map((dealerId) => ({ dealerId })), }, }, select: userPublicSelect, }); return res.status(201).json({ success: true, data: publicUser(user) }); }) ); router.patch( '/assign-dealer', requireRole('superAdmin'), asyncHandler(async (req, res) => { const salesRepId = String(req.body?.salesRepId || '').trim(); const dealerId = String(req.body?.dealerId || '').trim(); const assigned = req.body?.assigned !== false; if (!salesRepId || !dealerId) { throw httpError(400, 'salesRepId and dealerId are required'); } const [rep, dealer] = await Promise.all([ prisma.user.findUnique({ where: { id: salesRepId } }), prisma.dealer.findUnique({ where: { id: dealerId } }), ]); if (!rep || rep.role !== 'salesRep') throw httpError(404, 'Sales rep not found'); if (!dealer) throw httpError(404, 'Dealer not found'); if (assigned) { await prisma.dealerAssignment.upsert({ where: { salesRepId_dealerId: { salesRepId, dealerId } }, update: {}, create: { salesRepId, dealerId }, }); } else { await prisma.dealerAssignment.deleteMany({ where: { salesRepId, dealerId } }); } const updated = await prisma.user.findUnique({ where: { id: salesRepId }, select: userPublicSelect, }); return res.json({ success: true, data: publicUser(updated) }); }) ); router.post( '/dealer-users', requireRole('superAdmin', 'salesRep'), asyncHandler(async (req, res) => { const name = String(req.body?.name || '').trim(); const phone = normalizePhone(req.body?.phone); const dealerId = String(req.body?.dealerId || '').trim(); if (!name || !isValidPhone(phone) || !dealerId) { throw httpError(400, 'Name, phone, and dealerId are required'); } if (!canAccessDealer(req.user, dealerId)) throw httpError(403, 'Forbidden'); const dealer = await prisma.dealer.findUnique({ where: { id: dealerId } }); if (!dealer) throw httpError(404, 'Dealer not found'); const user = await prisma.user.create({ data: { name, phone, role: 'dealer', dealerId }, select: userPublicSelect, }); return res.status(201).json({ success: true, data: publicUser(user) }); }) ); module.exports = router;