import { FastifyRequest, FastifyReply } from 'fastify'; interface CreateWalkthroughBody { date?: string; } interface AddReservoirCheckBody { tankName: string; tankType: 'VEG' | 'FLOWER'; levelPercent: number; status: 'OK' | 'LOW' | 'CRITICAL'; photoUrl?: string; notes?: string; } interface AddIrrigationCheckBody { zoneName: string; drippersTotal: number; drippersWorking: number; drippersFailed?: string[]; waterFlow: boolean; nutrientsMixed: boolean; scheduleActive: boolean; photoUrl?: string; issues?: string; } interface AddPlantHealthCheckBody { zoneName: string; healthStatus: 'GOOD' | 'FAIR' | 'NEEDS_ATTENTION'; pestsObserved: boolean; pestType?: string; waterAccess: 'OK' | 'ISSUES'; foodAccess: 'OK' | 'ISSUES'; flaggedForAttention?: boolean; issuePhotoUrl?: string; referencePhotoUrl?: string; notes?: string; } /** * Start a new daily walkthrough */ export const createWalkthrough = async (request: FastifyRequest, reply: FastifyReply) => { const { date } = (request.body as CreateWalkthroughBody) || {}; const userId = (request.user as any)?.userId; if (!userId) { return reply.code(401).send({ message: 'Unauthorized' }); } // Verify user exists (handle stale tokens after re-seed) const userExists = await request.server.prisma.user.findUnique({ where: { id: userId } }); if (!userExists) { return reply.code(401).send({ message: 'User not found. Please log in again.' }); } try { const walkthrough = await request.server.prisma.dailyWalkthrough.create({ data: { date: date ? new Date(date) : new Date(), completedBy: userId, status: 'IN_PROGRESS', }, include: { user: { select: { id: true, name: true, email: true, role: true, }, }, reservoirChecks: true, irrigationChecks: true, plantHealthChecks: true, }, }); return reply.code(201).send(walkthrough); } catch (error) { request.log.error(error); return reply.code(500).send({ message: 'Failed to create walkthrough' }); } }; /** * Get all walkthroughs (with optional filters) */ export const getWalkthroughs = async (request: FastifyRequest, reply: FastifyReply) => { const { status, startDate, endDate, userId } = request.query as any; try { const walkthroughs = await request.server.prisma.dailyWalkthrough.findMany({ where: { ...(status && { status }), ...(userId && { completedBy: userId }), ...(startDate && endDate && { date: { gte: new Date(startDate), lte: new Date(endDate), }, }), }, include: { user: { select: { id: true, name: true, email: true, role: true, }, }, reservoirChecks: true, irrigationChecks: true, plantHealthChecks: true, }, orderBy: { date: 'desc', }, }); return walkthroughs; } catch (error) { request.log.error(error); return reply.code(500).send({ message: 'Failed to fetch walkthroughs' }); } }; /** * Get today's walkthrough (if exists) */ export const getTodaysWalkthrough = async (request: FastifyRequest, reply: FastifyReply) => { try { const today = new Date(); today.setHours(0, 0, 0, 0); const tomorrow = new Date(today); tomorrow.setDate(tomorrow.getDate() + 1); const walkthrough = await request.server.prisma.dailyWalkthrough.findFirst({ where: { date: { gte: today, lt: tomorrow, }, }, include: { user: { select: { id: true, name: true, email: true, role: true, }, }, reservoirChecks: true, irrigationChecks: true, plantHealthChecks: true, }, orderBy: { startTime: 'desc', }, }); if (!walkthrough) { return reply.code(404).send({ message: 'No walkthrough found for today' }); } return walkthrough; } catch (error) { request.log.error(error); return reply.code(500).send({ message: 'Failed to fetch today\'s walkthrough' }); } }; /** * Get a single walkthrough by ID */ export const getWalkthrough = async (request: FastifyRequest, reply: FastifyReply) => { const { id } = request.params as { id: string }; try { const walkthrough = await request.server.prisma.dailyWalkthrough.findUnique({ where: { id }, include: { user: { select: { id: true, name: true, email: true, role: true, }, }, reservoirChecks: true, irrigationChecks: true, plantHealthChecks: true, }, }); if (!walkthrough) { return reply.code(404).send({ message: 'Walkthrough not found' }); } return walkthrough; } catch (error) { request.log.error(error); return reply.code(500).send({ message: 'Failed to fetch walkthrough' }); } }; /** * Complete a walkthrough */ export const completeWalkthrough = async (request: FastifyRequest, reply: FastifyReply) => { const { id } = request.params as { id: string }; try { const walkthrough = await request.server.prisma.dailyWalkthrough.update({ where: { id }, data: { status: 'COMPLETED', endTime: new Date(), }, include: { user: { select: { id: true, name: true, email: true, role: true, }, }, reservoirChecks: true, irrigationChecks: true, plantHealthChecks: true, }, }); return walkthrough; } catch (error) { request.log.error(error); return reply.code(500).send({ message: 'Failed to complete walkthrough' }); } }; /** * Add a reservoir check to a walkthrough */ export const addReservoirCheck = async (request: FastifyRequest, reply: FastifyReply) => { const { id } = request.params as { id: string }; const checkData = request.body as AddReservoirCheckBody; try { const check = await request.server.prisma.reservoirCheck.create({ data: { walkthroughId: id, ...checkData, }, }); return reply.code(201).send(check); } catch (error) { request.log.error(error); return reply.code(500).send({ message: 'Failed to add reservoir check' }); } }; /** * Add an irrigation check to a walkthrough */ export const addIrrigationCheck = async (request: FastifyRequest, reply: FastifyReply) => { const { id } = request.params as { id: string }; const checkData = request.body as AddIrrigationCheckBody; try { const check = await request.server.prisma.irrigationCheck.create({ data: { walkthroughId: id, zoneName: checkData.zoneName, drippersTotal: checkData.drippersTotal, drippersWorking: checkData.drippersWorking, drippersFailed: checkData.drippersFailed ? JSON.stringify(checkData.drippersFailed) : null, waterFlow: checkData.waterFlow, nutrientsMixed: checkData.nutrientsMixed, scheduleActive: checkData.scheduleActive, photoUrl: checkData.photoUrl, issues: checkData.issues, }, }); return reply.code(201).send(check); } catch (error) { request.log.error(error); return reply.code(500).send({ message: 'Failed to add irrigation check' }); } }; /** * Add a plant health check to a walkthrough */ export const addPlantHealthCheck = async (request: FastifyRequest, reply: FastifyReply) => { const { id } = request.params as { id: string }; const checkData = request.body as AddPlantHealthCheckBody; try { const check = await request.server.prisma.plantHealthCheck.create({ data: { walkthroughId: id, ...checkData, flaggedForAttention: checkData.flaggedForAttention || false, }, }); return reply.code(201).send(check); } catch (error) { request.log.error(error); return reply.code(500).send({ message: 'Failed to add plant health check' }); } };