<?php

namespace SugarCalendarBookings\Notifications\Emails;

use SugarCalendarBookings\Plugin;
use SugarCalendarBookings\Appointments\AppointmentModel;
use SugarCalendarBookings\Support\Bootable;
use DateTimeImmutable;
use DateTimeZone;

if ( ! defined( 'ABSPATH' ) ) {
	exit;
}

/**
 * Service for handling appointment reminder emails.
 *
 * @since 1.0.0
 */
class ReminderProvider implements Bootable {

	/**
	 * Email service instance.
	 *
	 * @since 1.0.0
	 *
	 * @var EmailService
	 */
	private $email_service;

	/**
	 * Constructor.
	 *
	 * @since 1.0.0
	 */
	public function __construct() {

		$this->email_service = Plugin::get( EmailService::class );
	}

	/**
	 * Initialize the reminder service.
	 *
	 * @since 1.0.0
	 */
	public function init() {

		if ( ! wp_next_scheduled( 'sugar_calendar_bookings_hourly_reminder_check' ) ) {
			wp_schedule_event( time(), 'hourly', 'sugar_calendar_bookings_hourly_reminder_check' );
		}
	}

	/**
	 * Register WordPress hooks.
	 *
	 * @since 1.0.0
	 */
	public function hooks() {

		// Hook into the scheduled event.
		add_action( 'sugar_calendar_bookings_hourly_reminder_check', [ $this, 'send_hourly_reminders' ] );

		// Hook into plugin deactivation.
		add_action( 'deactivate_sugar-calendar-bookings-scheduling-appointments/sugar-calendar-bookings-scheduling-appointments.php', [ $this, 'cleanup' ] );
		add_action( 'deactivate_sugar-calendar-bookings-scheduling-appointments-lite/sugar-calendar-bookings-scheduling-appointments-lite.php', [ $this, 'cleanup' ] );
	}

	/**
	 * Send reminder emails for appointments that start in the next 24 hours.
	 *
	 * @since 1.0.0
	 */
	public function send_hourly_reminders() {

		// Get current time in UTC.
		$now = new DateTimeImmutable( 'now', new DateTimeZone( 'UTC' ) );

		// Find appointments that start in the next 24 hours that haven't been reminded yet.
		$reminder_time_end = $now->modify( '+24 hours' );

		// TODO: filter appointments with join meta table without PHP.

		// Get appointments that need reminders right now.
		$appointments = AppointmentModel::query()
			->with(
				[
					'customer',
					'employee',
					'service.meta',
					'location',
					'payments',
					'meta' => fn( $q ) => $q->where( 'meta_key', '=', 'reminder_sent', '%s' ),
				]
			)
			->where( 'start_at', '<=', $reminder_time_end->format( 'Y-m-d H:i:s' ), '%s' )
			->where( 'start_at', '>=', $now->format( 'Y-m-d H:i:s' ), '%s' )
			->where( 'status', 'NOT IN', [ 'cancelled', 'done' ], '%s' )
			->get();

		// Filter out appointments that have already been reminded.
		$appointments = array_filter(
			$appointments,
			function ( $appointment ) {
				return $appointment->reminder_sent !== true;
			}
		);

		if ( empty( $appointments ) ) {
			return;
		}

		foreach ( $appointments as $appointment ) {
			$sent = $this->send_reminder_emails( $appointment );

			if ( $sent ) {
				$appointment->reminder_sent = '1';

				$appointment->save();
			}
		}
	}

	/**
	 * Send reminder emails for a specific appointment.
	 *
	 * @since 1.0.0
	 *
	 * @param AppointmentModel $appointment Appointment to send reminders for.
	 *
	 * @return bool True if at least one reminder was sent, false otherwise.
	 */
	public function send_reminder_emails( $appointment ) {

		// Send reminder to attendee.
		$attendee_sent = $this->email_service->send_email( 'appointment_reminder_attendee', $appointment );

		// Send reminder to employee.
		$employee_sent = $this->email_service->send_email( 'appointment_reminder_employee', $appointment );

		return $attendee_sent || $employee_sent;
	}

	/**
	 * Clean up scheduled events on deactivation.
	 *
	 * @since 1.0.0
	 */
	public function cleanup() {

		// Clean up hourly reminder cron.
		$timestamp = wp_next_scheduled( 'sugar_calendar_bookings_hourly_reminder_check' );

		if ( $timestamp ) {
			wp_unschedule_event( $timestamp, 'sugar_calendar_bookings_hourly_reminder_check' );
		}
	}
}
