const { Op } = require('sequelize');
const { BusSchedules, Routes, RouteSchedules } = require('../../models');
const { formatCase } = require('../../util/formatter');

exports.schedules = async (req, res, next) => {
	try {
		const { driverId } = req;
		const { type } = req.query;

		const today = new Date();
		const dateFilter = type === 'all' ? {} : { date: today.toISOString().slice(0, 10) };

		let schedules = await BusSchedules.findAll({
			where: { driver_id: driverId, ...dateFilter },
			attributes: ['id', 'date', 'start_time', 'start_status', 'finish_time', 'finish_status'],
			include: [
				{
					model: RouteSchedules,
					as: 'schedule',
					attributes: ['start_time', 'end_time'],
					include: [
						{
							model: Routes,
							as: 'route',
							attributes: ['from', 'to', 'direction'],
						},
					],
				},
			],
			order: [['start_time', 'ASC']],
		});
		schedules =
			schedules?.length > 0
				? schedules.map((item) => {
						let schedule = item.get({ plain: true });

						schedule.driver_start_time = schedule.start_time;
						schedule.driver_finish_time = schedule.finish_time;
						schedule.start_time = schedule.schedule?.start_time ?? null;
						schedule.end_time = schedule.schedule?.end_time ?? null;
						schedule.from = schedule.schedule?.route?.from ?? null;
						schedule.to = schedule.schedule?.route?.to ?? null;
						schedule.direction = schedule.schedule?.route?.direction ?? null;

						delete schedule.schedule;
						return schedule;
					})
				: [];

		return res.status(200).json({
			success: true,
			data: formatCase(schedules),
		});
	} catch (error) {
		next(error);
	}
};

exports.update = async (req, res, next) => {
	try {
		const { driverId } = req;
		const { scheduleId, action } = req.body;

		let driverRoute = await BusSchedules.findOne({
			where: { id: scheduleId, driver_id: driverId },
		});

		if (!driverRoute) {
			return res.status(404).json({ success: false, message: 'Driver route not found.' });
		}

		if (action === 'start' && driverRoute.start_time) {
			return res.status(400).json({ success: false, message: 'Already started.' });
		}

		if (action === 'finish' && driverRoute.finish_time) {
			return res.status(400).json({ success: false, message: 'Already finished.' });
		}

		if (action === 'start') {
			const unfinished = await BusSchedules.findOne({
				where: {
					driver_id: driverId,
					start_time: { [Op.ne]: null },
					finish_time: null,
					id: { [Op.ne]: scheduleId },
				},
			});
			if (unfinished) {
				return res
					.status(400)
					.json({ success: false, message: 'Cannot start a new schedule while another is still in progress.' });
			}
		}

		const now = new Date();
		const nowTime = now.toTimeString().slice(0, 8);

		const schedule = await RouteSchedules.findOne({
			where: { id: driverRoute.route_schedule_id },
			attributes: ['start_time', 'end_time'],
		});

		function timeToDate(baseDate, timeStr) {
			const [h, m, s] = timeStr.split(':');
			const d = new Date(baseDate);
			d.setHours(Number(h), Number(m), Number(s), 0);
			return d;
		}

		if (action === 'start') {
			if (schedule && schedule.start_time) {
				const scheduledStart = timeToDate(now, schedule.start_time);
				const diffMs = now.getTime() - scheduledStart.getTime();
				const diffMin = diffMs / 60000;

				if (diffMin < -10) {
					return res
						.status(400)
						.json({ success: false, message: 'Cannot start more than 10 minutes before scheduled start time.' });
				}

				if (Math.abs(diffMin) <= 3) {
					driverRoute.start_status = 'On Time';
				} else if (diffMin > 3) {
					driverRoute.start_status = 'Late';
				} else {
					driverRoute.start_status = 'Early';
				}
			}
			driverRoute.start_time = nowTime;
		} else if (action === 'finish') {
			if (!driverRoute.start_time) {
				return res.status(400).json({ success: false, message: 'Cannot finish. Start time is missing.' });
			}
			driverRoute.finish_time = nowTime;

			if (schedule && schedule.end_time) {
				const scheduledEnd = timeToDate(now, schedule.end_time);
				const diffMs = now.getTime() - scheduledEnd.getTime();
				const diffMin = diffMs / 60000;

				if (Math.abs(diffMin) <= 3) {
					driverRoute.finish_status = 'On Time';
				} else if (diffMin > 3) {
					driverRoute.finish_status = 'Late';
				} else {
					driverRoute.finish_status = 'Early';
				}
			}
		}

		await driverRoute.save();

		return res.status(200).json({
			success: true,
			data: driverRoute,
		});
	} catch (error) {
		next(error);
	}
};
