import { Router } from 'express';
import { authenticate } from '../../middleware/auth';
import { requireRoles } from '../../middleware/rbac';
import { Role, ErrorCode, TripStatus, TRIP_STATUS_TRANSITIONS } from '@saferoute/constants';
import { prisma } from '../../config/database';
import { sendSuccess, sendError } from '../../utils/response';
import { createAuditLog } from '../../utils/audit-logger';

export const tripRoutes = Router();

tripRoutes.post('/start', authenticate, requireRoles(Role.DRIVER, Role.AUTO_DRIVER), async (req, res) => {
  try {
    const { routeId, vehicleId, type } = req.body;

    const route = await prisma.route.findUnique({ where: { id: routeId }, include: { school: true } });
    if (!route) { sendError(res, ErrorCode.RESOURCE_NOT_FOUND, 'Route not found.'); return; }

    const vehicle = await prisma.vehicle.findUnique({ where: { id: vehicleId }, include: { gpsDevice: true } });
    if (!vehicle) { sendError(res, ErrorCode.RESOURCE_NOT_FOUND, 'Vehicle not found.'); return; }

    const driver = await prisma.driver.findFirst({ where: { userId: req.user!.userId } });
    if (!driver) { sendError(res, ErrorCode.ACCESS_DENIED, 'You are not registered as a driver.'); return; }

    const trip = await prisma.trip.create({
      data: {
        schoolId: route.schoolId, routeId, vehicleId, driverId: driver.id,
        tripDate: new Date(), type: type || 'MORNING', status: TripStatus.TRIP_STARTED, startedAt: new Date(),
      },
    });

    await prisma.tripEvent.create({
      data: { tripId: trip.id, eventType: 'TRIP_STARTED', createdBy: req.user!.userId },
    });

    sendSuccess(res, { id: trip.id, status: trip.status, startedAt: trip.startedAt?.toISOString() }, 'Trip started', 201);
  } catch (error) {
    sendError(res, ErrorCode.SERVER_ERROR, 'Failed to start trip.');
  }
});

tripRoutes.post('/:tripId/end', authenticate, requireRoles(Role.DRIVER, Role.AUTO_DRIVER), async (req, res) => {
  try {
    const trip = await prisma.trip.findUnique({ where: { id: req.params.tripId } });
    if (!trip) { sendError(res, ErrorCode.RESOURCE_NOT_FOUND, 'Trip not found.'); return; }
    if (trip.status === TripStatus.TRIP_COMPLETED || trip.status === TripStatus.CANCELLED) {
      sendError(res, ErrorCode.TRIP_NOT_ACTIVE, 'Trip is already completed/cancelled.'); return;
    }

    await prisma.trip.update({
      where: { id: req.params.tripId },
      data: { status: TripStatus.TRIP_COMPLETED, endedAt: new Date() },
    });
    await prisma.tripEvent.create({
      data: { tripId: req.params.tripId, eventType: 'TRIP_COMPLETED', createdBy: req.user!.userId },
    });
    sendSuccess(res, { id: req.params.tripId, status: TripStatus.TRIP_COMPLETED }, 'Trip ended');
  } catch (error) {
    sendError(res, ErrorCode.SERVER_ERROR, 'Failed to end trip.');
  }
});

tripRoutes.get('/:tripId', authenticate, async (req, res) => {
  try {
    const trip = await prisma.trip.findUnique({
      where: { id: req.params.tripId },
      include: {
        route: { include: { stops: { orderBy: { sequenceOrder: 'asc' } } } },
        vehicle: { select: { id: true, vehicleNumber: true, vehicleType: true } },
        driver: { include: { user: { select: { fullName: true, phone: true } } } },
        attendant: { include: { user: { select: { fullName: true } } } },
        events: { orderBy: { createdAt: 'desc' }, take: 50 },
        rfidScans: { orderBy: { scannedAt: 'desc' }, include: { student: { select: { id: true, fullName: true } } } },
      },
    });
    if (!trip) { sendError(res, ErrorCode.RESOURCE_NOT_FOUND, 'Trip not found.'); return; }
    sendSuccess(res, trip);
  } catch (error) {
    sendError(res, ErrorCode.SERVER_ERROR, 'Failed to get trip.');
  }
});

tripRoutes.get('/vehicle/:vehicleId/current', authenticate, async (req, res) => {
  try {
    const trip = await prisma.trip.findFirst({
      where: {
        vehicleId: req.params.vehicleId,
        status: { notIn: [TripStatus.TRIP_COMPLETED, TripStatus.CANCELLED] },
      },
      include: {
        route: { select: { id: true, name: true } },
        driver: { include: { user: { select: { fullName: true } } } },
      },
      orderBy: { createdAt: 'desc' },
    });
    sendSuccess(res, trip);
  } catch (error) {
    sendError(res, ErrorCode.SERVER_ERROR, 'Failed to get current trip.');
  }
});

tripRoutes.patch('/:tripId/status', authenticate, async (req, res) => {
  try {
    const { status } = req.body;
    const trip = await prisma.trip.findUnique({ where: { id: req.params.tripId } });
    if (!trip) { sendError(res, ErrorCode.RESOURCE_NOT_FOUND, 'Trip not found.'); return; }

    const currentStatus = trip.status as TripStatus;
    const allowedTransitions = TRIP_STATUS_TRANSITIONS[currentStatus] || [];
    if (!allowedTransitions.includes(status as TripStatus)) {
      sendError(res, ErrorCode.VALIDATION_ERROR, `Cannot transition from ${currentStatus} to ${status}.`, {
        currentStatus, requestedStatus: status, allowedTransitions,
      });
      return;
    }

    await prisma.trip.update({ where: { id: req.params.tripId }, data: { status } });
    await prisma.tripEvent.create({
      data: { tripId: req.params.tripId, eventType: `STATUS_CHANGED_TO_${status}`, createdBy: req.user?.userId },
    });

    sendSuccess(res, { id: req.params.tripId, status }, 'Trip status updated');
  } catch (error) {
    sendError(res, ErrorCode.SERVER_ERROR, 'Failed to update trip status.');
  }
});

tripRoutes.post('/:tripId/events', authenticate, async (req, res) => {
  try {
    const { eventType, description, latitude, longitude } = req.body;
    const event = await prisma.tripEvent.create({
      data: { tripId: req.params.tripId, eventType, description, latitude, longitude, createdBy: req.user?.userId },
    });
    sendSuccess(res, { id: event.id, eventType: event.eventType }, 'Event logged', 201);
  } catch (error) {
    sendError(res, ErrorCode.SERVER_ERROR, 'Failed to log event.');
  }
});

tripRoutes.get('/student/:studentId/history', authenticate, async (req, res) => {
  try {
    const page = parseInt(req.query.page as string) || 1;
    const limit = parseInt(req.query.limit as string) || 20;
    const skip = (page - 1) * limit;

    const routeStudents = await prisma.routeStudent.findMany({ where: { studentId: req.params.studentId } });
    const routeIds = routeStudents.map((rs) => rs.routeId);

    const [trips, total] = await Promise.all([
      prisma.trip.findMany({
        where: { routeId: { in: routeIds } },
        skip, take: limit, orderBy: { tripDate: 'desc' },
        select: { id: true, tripDate: true, type: true, status: true, startedAt: true, endedAt: true },
      }),
      prisma.trip.count({ where: { routeId: { in: routeIds } } }),
    ]);

    sendSuccess(res, { items: trips, page, limit, total, totalPages: Math.ceil(total / limit) });
  } catch (error) {
    sendError(res, ErrorCode.SERVER_ERROR, 'Failed to get trip history.');
  }
});
