import { Response } from 'express'; import { AuthRequest } from '../middleware/auth'; import { eventService } from '../services/eventService'; import prisma from '../config/database'; import { clerkClient } from '@clerk/clerk-sdk-node'; // Helper to find or create user from Clerk ID async function findOrCreateUser(clerkId: string): Promise { // Check if user exists let user = await prisma.user.findUnique({ where: { clerkId }, select: { id: true }, }); if (user) { return user.id; } // User doesn't exist, fetch from Clerk and create try { const clerkUser = await clerkClient.users.getUser(clerkId); user = await prisma.user.create({ data: { clerkId, email: clerkUser.emailAddresses[0]?.emailAddress || `${clerkId}@temp.com`, username: clerkUser.username || `user_${clerkId.substring(0, 8)}`, firstName: clerkUser.firstName, lastName: clerkUser.lastName, avatarUrl: clerkUser.imageUrl, }, select: { id: true }, }); return user.id; } catch (error) { console.error('Error creating user from Clerk:', error); throw new Error('Failed to create user'); } } export const eventController = { // Get all events with optional filters async getEvents(req: AuthRequest, res: Response) { try { const { status, startDate, endDate, latitude, longitude, radius } = req.query; const filters: any = {}; if (status) filters.status = status as string; if (startDate) filters.startDate = new Date(startDate as string); if (endDate) filters.endDate = new Date(endDate as string); if (latitude && longitude) { filters.latitude = parseFloat(latitude as string); filters.longitude = parseFloat(longitude as string); if (radius) filters.radius = parseFloat(radius as string); } const events = await eventService.getEvents(filters); res.json(events); } catch (error: any) { console.error('Error fetching events:', error); res.status(500).json({ code: 'FETCH_EVENTS_ERROR', message: 'Failed to fetch events', details: error.message, timestamp: new Date().toISOString(), }); } }, // Get single event by ID async getEvent(req: AuthRequest, res: Response) { try { const { id } = req.params; const event = await eventService.getEventById(id); if (!event) { return res.status(404).json({ code: 'EVENT_NOT_FOUND', message: 'Event not found', timestamp: new Date().toISOString(), }); } res.json(event); } catch (error: any) { console.error('Error fetching event:', error); res.status(500).json({ code: 'FETCH_EVENT_ERROR', message: 'Failed to fetch event', details: error.message, timestamp: new Date().toISOString(), }); } }, // Create new event async createEvent(req: AuthRequest, res: Response) { try { const clerkId = req.userId; if (!clerkId) { return res.status(401).json({ code: 'UNAUTHORIZED', message: 'User not authenticated', timestamp: new Date().toISOString(), }); } // Find or create user in database const userId = await findOrCreateUser(clerkId); const { title, description, latitude, longitude, locationName, scheduledDate, duration } = req.body; // Validation if (!title || !description || !latitude || !longitude || !locationName || !scheduledDate || !duration) { return res.status(400).json({ code: 'VALIDATION_ERROR', message: 'Missing required fields', timestamp: new Date().toISOString(), }); } const eventData = { organizerId: userId, title, description, latitude: parseFloat(latitude), longitude: parseFloat(longitude), locationName, scheduledDate: new Date(scheduledDate), duration: parseInt(duration), }; const event = await eventService.createEvent(eventData); res.status(201).json(event); } catch (error: any) { console.error('Error creating event:', error); res.status(500).json({ code: 'CREATE_EVENT_ERROR', message: 'Failed to create event', details: error.message, timestamp: new Date().toISOString(), }); } }, // Update event async updateEvent(req: AuthRequest, res: Response) { try { const clerkId = req.userId; if (!clerkId) { return res.status(401).json({ code: 'UNAUTHORIZED', message: 'User not authenticated', timestamp: new Date().toISOString(), }); } const userId = await findOrCreateUser(clerkId); const { id } = req.params; const event = await eventService.getEventById(id); if (!event) { return res.status(404).json({ code: 'EVENT_NOT_FOUND', message: 'Event not found', timestamp: new Date().toISOString(), }); } // Check if user is the organizer if (event.organizerId !== userId) { return res.status(403).json({ code: 'FORBIDDEN', message: 'Only the event organizer can update this event', timestamp: new Date().toISOString(), }); } const updatedEvent = await eventService.updateEvent(id, req.body); res.json(updatedEvent); } catch (error: any) { console.error('Error updating event:', error); res.status(500).json({ code: 'UPDATE_EVENT_ERROR', message: 'Failed to update event', details: error.message, timestamp: new Date().toISOString(), }); } }, // Delete event async deleteEvent(req: AuthRequest, res: Response) { try { const clerkId = req.userId; if (!clerkId) { return res.status(401).json({ code: 'UNAUTHORIZED', message: 'User not authenticated', timestamp: new Date().toISOString(), }); } const userId = await findOrCreateUser(clerkId); const { id } = req.params; const event = await eventService.getEventById(id); if (!event) { return res.status(404).json({ code: 'EVENT_NOT_FOUND', message: 'Event not found', timestamp: new Date().toISOString(), }); } // Check if user is the organizer if (event.organizerId !== userId) { return res.status(403).json({ code: 'FORBIDDEN', message: 'Only the event organizer can delete this event', timestamp: new Date().toISOString(), }); } await eventService.deleteEvent(id); res.status(204).send(); } catch (error: any) { console.error('Error deleting event:', error); res.status(500).json({ code: 'DELETE_EVENT_ERROR', message: 'Failed to delete event', details: error.message, timestamp: new Date().toISOString(), }); } }, // Register for event async registerForEvent(req: AuthRequest, res: Response) { try { const clerkId = req.userId; if (!clerkId) { return res.status(401).json({ code: 'UNAUTHORIZED', message: 'User not authenticated', timestamp: new Date().toISOString(), }); } const userId = await findOrCreateUser(clerkId); const { id } = req.params; const registration = await eventService.registerForEvent(id, userId); res.status(201).json(registration); } catch (error: any) { console.error('Error registering for event:', error); if (error.message.includes('already registered')) { return res.status(409).json({ code: 'ALREADY_REGISTERED', message: error.message, timestamp: new Date().toISOString(), }); } res.status(500).json({ code: 'REGISTER_EVENT_ERROR', message: 'Failed to register for event', details: error.message, timestamp: new Date().toISOString(), }); } }, // Unregister from event async unregisterFromEvent(req: AuthRequest, res: Response) { try { const clerkId = req.userId; if (!clerkId) { return res.status(401).json({ code: 'UNAUTHORIZED', message: 'User not authenticated', timestamp: new Date().toISOString(), }); } const userId = await findOrCreateUser(clerkId); const { id } = req.params; await eventService.unregisterFromEvent(id, userId); res.status(204).send(); } catch (error: any) { console.error('Error unregistering from event:', error); res.status(500).json({ code: 'UNREGISTER_EVENT_ERROR', message: 'Failed to unregister from event', details: error.message, timestamp: new Date().toISOString(), }); } }, // Get event registrations async getEventRegistrations(req: AuthRequest, res: Response) { try { const { id } = req.params; const registrations = await eventService.getEventRegistrations(id); res.json(registrations); } catch (error: any) { console.error('Error fetching event registrations:', error); res.status(500).json({ code: 'FETCH_REGISTRATIONS_ERROR', message: 'Failed to fetch event registrations', details: error.message, timestamp: new Date().toISOString(), }); } }, // Check registration status async getRegistrationStatus(req: AuthRequest, res: Response) { try { const clerkId = req.userId; if (!clerkId) { return res.json({ registered: false }); } const userId = await findOrCreateUser(clerkId); const { id } = req.params; const isRegistered = await eventService.isUserRegistered(id, userId); res.json({ registered: isRegistered }); } catch (error: any) { console.error('Error checking registration status:', error); res.status(500).json({ code: 'CHECK_REGISTRATION_ERROR', message: 'Failed to check registration status', details: error.message, timestamp: new Date().toISOString(), }); } }, };