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

exports.createRoute = async (req, res, next) => {
	let transaction = await sequelize.transaction();
	try {
		const { from, to, direction } = req.body;
		if (!from || !to || !direction) {
			return errorHandler('From, to, and direction are required', 400);
		}
		const route = await Routes.create({ from, to, direction }, { transaction });
		await transaction.commit();
		return res.status(201).json({ success: true, data: formatCase(route.get({ plain: true })) });
	} catch (err) {
		if (transaction) await transaction.rollback();
		next(err);
	}
};

exports.getRoutes = async (req, res, next) => {
	try {
		const { page = 1, limit = 20 } = req.query;
		const offset = (parseInt(page) - 1) * parseInt(limit);
		const { count, rows } = await Routes.findAndCountAll({
			order: [['createdAt', 'DESC']],
			limit: parseInt(limit),
			offset,
		});
		return res.status(200).json({
			success: true,
			data: formatCase(rows.map((r) => r.get({ plain: true }))),

			pagination: {
				currentPage: parseInt(page),
				totalPages: Math.ceil(count / parseInt(limit)),
				totalItems: count,
				itemsPerPage: parseInt(limit),
			},
		});
	} catch (err) {
		next(err);
	}
};

exports.getRoute = async (req, res, next) => {
	try {
		const route = await Routes.findByPk(req.params.id);
		if (!route) return errorHandler('Route not found', 404);
		return res.status(200).json({ success: true, data: formatCase(route.get({ plain: true })) });
	} catch (err) {
		next(err);
	}
};

exports.updateRoute = async (req, res, next) => {
	let transaction = await sequelize.transaction();
	try {
		const route = await Routes.findByPk(req.params.id);
		if (!route) return errorHandler('Route not found', 404);
		await route.update(req.body, { transaction });
		await transaction.commit();
		return res.status(200).json({ success: true, data: formatCase(route.get({ plain: true })) });
	} catch (err) {
		if (transaction) await transaction.rollback();
		next(err);
	}
};

exports.deleteRoute = async (req, res, next) => {
	let transaction = await sequelize.transaction();
	try {
		const route = await Routes.findByPk(req.params.id);
		if (!route) return errorHandler('Route not found', 404);
		await route.destroy({ transaction });
		await transaction.commit();
		return res.status(200).json({ success: true, message: 'Route deleted' });
	} catch (err) {
		if (transaction) await transaction.rollback();
		next(err);
	}
};

exports.createRouteSchedule = async (req, res, next) => {
	let transaction = await sequelize.transaction();
	try {
		const { route_id, date, start_time, end_time } = req.body;
		if (!route_id || !date) {
			return errorHandler('Route ID and date are required', 400);
		}
		const schedule = await RouteSchedules.create({ route_id, date, start_time, end_time }, { transaction });
		await transaction.commit();
		return res.status(201).json({ success: true, data: formatCase(schedule.get({ plain: true })) });
	} catch (err) {
		if (transaction) await transaction.rollback();
		next(err);
	}
};

exports.getRouteSchedules = async (req, res, next) => {
	try {
		const { page = 1, limit = 20 } = req.query;
		const offset = (parseInt(page) - 1) * parseInt(limit);
		const { count, rows } = await RouteSchedules.findAndCountAll({
			order: [['createdAt', 'DESC']],
			limit: parseInt(limit),
			offset,
		});
		return res.status(200).json({
			success: true,
			data: formatCase(rows.map((r) => r.get({ plain: true }))),

			pagination: {
				currentPage: parseInt(page),
				totalPages: Math.ceil(count / parseInt(limit)),
				totalItems: count,
				itemsPerPage: parseInt(limit),
			},
		});
	} catch (err) {
		next(err);
	}
};

exports.getRouteSchedule = async (req, res, next) => {
	try {
		const schedule = await RouteSchedules.findByPk(req.params.id);
		if (!schedule) return errorHandler('Route schedule not found', 404);
		return res.status(200).json({ success: true, data: formatCase(schedule.get({ plain: true })) });
	} catch (err) {
		next(err);
	}
};

exports.updateRouteSchedule = async (req, res, next) => {
	let transaction = await sequelize.transaction();
	try {
		const schedule = await RouteSchedules.findByPk(req.params.id);
		if (!schedule) return errorHandler('Route schedule not found', 404);
		await schedule.update(req.body, { transaction });
		await transaction.commit();
		return res.status(200).json({ success: true, data: formatCase(schedule.get({ plain: true })) });
	} catch (err) {
		if (transaction) await transaction.rollback();
		next(err);
	}
};

exports.deleteRouteSchedule = async (req, res, next) => {
	let transaction = await sequelize.transaction();
	try {
		const schedule = await RouteSchedules.findByPk(req.params.id);
		if (!schedule) return errorHandler('Route schedule not found', 404);
		await schedule.destroy({ transaction });
		await transaction.commit();
		return res.status(200).json({ success: true, message: 'Route schedule deleted' });
	} catch (err) {
		if (transaction) await transaction.rollback();
		next(err);
	}
};

exports.createDriver = async (req, res, next) => {
	let transaction = await sequelize.transaction();
	try {
		const { email, password } = req.body;

		const driver = await Drivers.create({ email_address: email, password }, { transaction });
		await transaction.commit();
		return res.status(201).json({ success: true, data: formatCase(driver.get({ plain: true })) });
	} catch (err) {
		if (transaction) await transaction.rollback();
		next(err);
	}
};

exports.getDrivers = async (req, res, next) => {
	try {
		const { page = 1, limit = 20 } = req.query;
		const offset = (parseInt(page) - 1) * parseInt(limit);
		const { count, rows } = await Drivers.findAndCountAll({
			order: [['createdAt', 'DESC']],
			limit: parseInt(limit),
			offset,
		});
		return res.status(200).json({
			success: true,
			data: formatCase(rows.map((r) => r.get({ plain: true }))),

			pagination: {
				currentPage: parseInt(page),
				totalPages: Math.ceil(count / parseInt(limit)),
				totalItems: count,
				itemsPerPage: parseInt(limit),
			},
		});
	} catch (err) {
		next(err);
	}
};

exports.getDriver = async (req, res, next) => {
	try {
		const driver = await Drivers.findByPk(req.params.id);
		if (!driver) return errorHandler('Driver not found', 404);
		return res.status(200).json({ success: true, data: formatCase(driver.get({ plain: true })) });
	} catch (err) {
		next(err);
	}
};

exports.updateDriver = async (req, res, next) => {
	let transaction = await sequelize.transaction();
	try {
		const driver = await Drivers.findByPk(req.params.id);
		if (!driver) return errorHandler('Driver not found', 404);
		await driver.update(req.body, { transaction });
		await transaction.commit();
		return res.status(200).json({ success: true, data: formatCase(driver.get({ plain: true })) });
	} catch (err) {
		if (transaction) await transaction.rollback();
		next(err);
	}
};

exports.deleteDriver = async (req, res, next) => {
	let transaction = await sequelize.transaction();
	try {
		const driver = await Drivers.findByPk(req.params.id);
		if (!driver) return errorHandler('Driver not found', 404);
		await driver.destroy({ transaction });
		await transaction.commit();
		return res.status(200).json({ success: true, message: 'Driver deleted' });
	} catch (err) {
		if (transaction) await transaction.rollback();
		next(err);
	}
};
