import LoggingService from '#services/file-system/logService';
import NotificationService from '#services/notification/notificationService';
import sequelize from '#services/database/sequelize/sequelizeService';
import { QueryTypes } from 'sequelize';
import { AppointmentRow } from '../types';

const CLASS_NAME = 'AppointmentJob';

/**
 * Appointment Reminder Job
 *
 * Queries the `appointments` table for confirmed, unreminded appointments
 * within the next `lookAheadMinutes` window, sends a push notification to
 * each user, then marks the appointment `reminder_sent = true`.
 *
 * The job degrades gracefully if the `appointments` table does not yet exist.
 */
export class AppointmentReminderJob {
	private logger: LoggingService;
	private notificationService: NotificationService;

	constructor() {
		this.logger = new LoggingService();
		this.notificationService = NotificationService.getInstance();
	}

	/**
	 * Send reminders for appointments occurring within the next `lookAheadMinutes`.
	 * Default look-ahead is 60 minutes (1 hour before the appointment).
	 */
	async run(lookAheadMinutes = 60): Promise<void> {
		const SOURCE = `${CLASS_NAME}.run`;
		try {
			this.logger.logInfoAsync(SOURCE, `Running appointment reminder (look-ahead: ${lookAheadMinutes}m)`, null);

			const windowEnd = new Date(Date.now() + lookAheadMinutes * 60 * 1000);

			const appointments = await sequelize.query<AppointmentRow>(
				`SELECT id, user_id, scheduled_at, title
				 FROM appointments
				 WHERE scheduled_at BETWEEN NOW() AND :windowEnd
				   AND reminder_sent = false
				   AND status = 'confirmed'`,
				{ replacements: { windowEnd }, type: QueryTypes.SELECT },
			);

			for (const appt of appointments) {
				await this.notificationService.createAndSend({
					userId: appt.user_id,
					body: `Bạn có lịch hẹn lúc ${new Date(appt.scheduled_at).toLocaleString('vi-VN')}${appt.title ? ': ' + appt.title : ''}`,
					type: 'appointment_reminder',
					data: { appointment_id: appt.id },
				} as any);

				await sequelize.query(`UPDATE appointments SET reminder_sent = true WHERE id = :id`, {
					replacements: { id: appt.id },
					type: QueryTypes.UPDATE,
				});
			}

			this.logger.logInfoAsync(
				SOURCE,
				`Appointment reminder job completed — ${appointments.length} reminder(s) sent`,
				null,
			);
		} catch (error: any) {
			// Graceful degradation: if the appointments table doesn't exist yet, skip silently
			if (error?.original?.code === '42P01') {
				this.logger.logInfoAsync(SOURCE, 'appointments table not found — skipping reminder job', null);
				return;
			}
			this.logger.logErrorAsync(SOURCE, error as Error, null);
		}
	}
}

export default AppointmentReminderJob;
