import express, { Request, Response } from 'express';
import { authenticate } from '../middleware/auth';
import { requireTripAccess } from '../middleware/tripAccess';
import { broadcast } from '../websocket';
import { checkPermission } from '../services/permissions';
import {
  getAssignmentWithPlace,
  listDayAssignments,
  dayExists,
  placeExists,
  createAssignment,
  assignmentExistsInDay,
  deleteAssignment,
  reorderAssignments,
  getAssignmentForTrip,
  moveAssignment,
  getParticipants,
  updateTime,
  setParticipants,
} from '../services/assignmentService';
import { onPlaceCreated } from '../services/journeyService';
import { AuthRequest } from '../types';

const router = express.Router({ mergeParams: true });

router.get('/trips/:tripId/days/:dayId/assignments', authenticate, requireTripAccess, (req: Request, res: Response) => {
  const { tripId, dayId } = req.params;

  if (!dayExists(dayId, tripId)) return res.status(404).json({ error: 'Day not found' });

  const result = listDayAssignments(dayId);
  res.json({ assignments: result });
});

router.post('/trips/:tripId/days/:dayId/assignments', authenticate, requireTripAccess, (req: Request, res: Response) => {
  const authReq = req as AuthRequest;
  if (!checkPermission('day_edit', authReq.user.role, authReq.trip!.user_id, authReq.user.id, authReq.trip!.user_id !== authReq.user.id))
    return res.status(403).json({ error: 'No permission' });

  const { tripId, dayId } = req.params;
  const { place_id, notes } = req.body;

  if (!dayExists(dayId, tripId)) return res.status(404).json({ error: 'Day not found' });
  if (!placeExists(place_id, tripId)) return res.status(404).json({ error: 'Place not found' });

  const assignment = createAssignment(dayId, place_id, notes);
  res.status(201).json({ assignment });
  broadcast(tripId, 'assignment:created', { assignment }, req.headers['x-socket-id'] as string);
  try { onPlaceCreated(Number(tripId), Number(place_id)); } catch {}
});

router.delete('/trips/:tripId/days/:dayId/assignments/:id', authenticate, requireTripAccess, (req: Request, res: Response) => {
  const authReq = req as AuthRequest;
  if (!checkPermission('day_edit', authReq.user.role, authReq.trip!.user_id, authReq.user.id, authReq.trip!.user_id !== authReq.user.id))
    return res.status(403).json({ error: 'No permission' });

  const { tripId, dayId, id } = req.params;

  if (!assignmentExistsInDay(id, dayId, tripId)) return res.status(404).json({ error: 'Assignment not found' });

  deleteAssignment(id);
  res.json({ success: true });
  broadcast(tripId, 'assignment:deleted', { assignmentId: Number(id), dayId: Number(dayId) }, req.headers['x-socket-id'] as string);
});

router.put('/trips/:tripId/days/:dayId/assignments/reorder', authenticate, requireTripAccess, (req: Request, res: Response) => {
  const authReq = req as AuthRequest;
  if (!checkPermission('day_edit', authReq.user.role, authReq.trip!.user_id, authReq.user.id, authReq.trip!.user_id !== authReq.user.id))
    return res.status(403).json({ error: 'No permission' });

  const { tripId, dayId } = req.params;
  const { orderedIds } = req.body;

  if (!dayExists(dayId, tripId)) return res.status(404).json({ error: 'Day not found' });

  reorderAssignments(dayId, orderedIds);
  res.json({ success: true });
  broadcast(tripId, 'assignment:reordered', { dayId: Number(dayId), orderedIds }, req.headers['x-socket-id'] as string);
});

router.put('/trips/:tripId/assignments/:id/move', authenticate, requireTripAccess, (req: Request, res: Response) => {
  const authReq = req as AuthRequest;
  if (!checkPermission('day_edit', authReq.user.role, authReq.trip!.user_id, authReq.user.id, authReq.trip!.user_id !== authReq.user.id))
    return res.status(403).json({ error: 'No permission' });

  const { tripId, id } = req.params;
  const { new_day_id, order_index } = req.body;

  const existing = getAssignmentForTrip(id, tripId);
  if (!existing) return res.status(404).json({ error: 'Assignment not found' });

  if (!dayExists(new_day_id, tripId)) return res.status(404).json({ error: 'Target day not found' });

  const oldDayId = existing.day_id;
  const { assignment: updated } = moveAssignment(id, new_day_id, order_index, oldDayId);
  res.json({ assignment: updated });
  broadcast(tripId, 'assignment:moved', { assignment: updated, oldDayId: Number(oldDayId), newDayId: Number(new_day_id) }, req.headers['x-socket-id'] as string);
});

router.get('/trips/:tripId/assignments/:id/participants', authenticate, requireTripAccess, (req: Request, res: Response) => {
  const { id } = req.params;

  const participants = getParticipants(id);
  res.json({ participants });
});

router.put('/trips/:tripId/assignments/:id/time', authenticate, requireTripAccess, (req: Request, res: Response) => {
  const authReq = req as AuthRequest;
  if (!checkPermission('day_edit', authReq.user.role, authReq.trip!.user_id, authReq.user.id, authReq.trip!.user_id !== authReq.user.id))
    return res.status(403).json({ error: 'No permission' });

  const { tripId, id } = req.params;

  const existing = getAssignmentForTrip(id, tripId);
  if (!existing) return res.status(404).json({ error: 'Assignment not found' });

  const { place_time, end_time } = req.body;
  const updated = updateTime(id, place_time, end_time);
  res.json({ assignment: updated });
  broadcast(Number(tripId), 'assignment:updated', { assignment: updated }, req.headers['x-socket-id'] as string);
});

router.put('/trips/:tripId/assignments/:id/participants', authenticate, requireTripAccess, (req: Request, res: Response) => {
  const authReq = req as AuthRequest;
  if (!checkPermission('day_edit', authReq.user.role, authReq.trip!.user_id, authReq.user.id, authReq.trip!.user_id !== authReq.user.id))
    return res.status(403).json({ error: 'No permission' });

  const { tripId, id } = req.params;
  const { user_ids } = req.body;
  if (!Array.isArray(user_ids)) return res.status(400).json({ error: 'user_ids must be an array' });

  const participants = setParticipants(id, user_ids);
  res.json({ participants });
  broadcast(Number(tripId), 'assignment:participants', { assignmentId: Number(id), participants }, req.headers['x-socket-id'] as string);
});

export default router;
