<?php

namespace SugarCalendarBookings\Availability;

use DateTimeZone;
use DateTimeImmutable;
use SugarCalendarBookings\Plugin;
use SugarCalendarBookings\Options;
use SugarCalendarBookings\Support\Helpers\Date;

/**
 * Advance window validator.
 *
 * Validate if the working time slot is within the allowed appointment advance window.
 *
 * @since 1.0.0
 */
class AdvanceWindowValidator {

	/**
	 * The current date and time.
	 *
	 * @since 1.0.0
	 *
	 * @var DateTimeImmutable
	 */
	private $now;

	/**
	 * The current date.
	 *
	 * @since 1.0.0
	 *
	 * @var DateTimeImmutable
	 */
	private $now_date;

	/**
	 * Whether the minimum advance booking is enabled.
	 *
	 * @since 1.0.0
	 *
	 * @var bool
	 */
	private $min_advance_enabled;

	/**
	 * The minimum advance days.
	 *
	 * @since 1.0.0
	 *
	 * @var int
	 */
	private $min_advance_days;

	/**
	 * Whether the maximum advance booking is enabled.
	 *
	 * @since 1.0.0
	 *
	 * @var bool
	 */
	private $max_advance_enabled;

	/**
	 * The maximum advance days.
	 *
	 * @since 1.0.0
	 *
	 * @var int
	 */
	private $max_advance_days;

	/**
	 * Business timezone.
	 *
	 * @since 1.0.0
	 *
	 * @var DateTimeZone
	 */
	private $timezone;

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

		$options  = Plugin::get( Options::class );
		$timezone = Date::get_default_timezone();

		$this->now                 = new DateTimeImmutable( 'now', $timezone );
		$this->now_date            = $this->now->setTime( 0, 0 );
		$this->min_advance_enabled = $options->get( 'appointments.advance_minimum' );
		$this->min_advance_days    = $options->get( 'appointments.advance_minimum_days' );
		$this->max_advance_enabled = $options->get( 'appointments.advance_maximum' );
		$this->max_advance_days    = $options->get( 'appointments.advance_maximum_days' );
		$this->timezone            = $timezone;
	}

	/**
	 * Check if the slot is outside the allowed appointment advance window.
	 *
	 * @since 1.0.0
	 *
	 * @param WorkingTimeSlot $slot The working time slot.
	 *
	 * @return bool True if the slot is outside the allowed appointment advance window, false otherwise.
	 */
	public function is_slot_outside_advance_window( $slot ) {

		$slot_start = $slot->start()->setTimezone( $this->timezone );

		if ( $slot_start < $this->now ) {
			return true;
		}

		if ( ! $this->max_advance_enabled && ! $this->min_advance_enabled ) {
			return false;
		}

		$start_date = $slot_start->setTime( 0, 0 );
		$days_diff  = (int) $this->now_date->diff( $start_date )->format( '%a' );

		if ( $this->min_advance_enabled && $days_diff < $this->min_advance_days ) {
			return true;
		}

		if ( $this->max_advance_enabled && $days_diff > $this->max_advance_days ) {
			return true;
		}

		return false;
	}
}
