<?php

namespace SugarCalendarBookings\Calendar\Admin;

use DateTimeImmutable;
use SugarCalendarBookings\Appointments\AppointmentModel;
use SugarCalendarBookings\Calendar\CalendarHelpers;
use SugarCalendarBookings\Options;
use SugarCalendarBookings\Plugin;
use SugarCalendarBookings\Support\Helpers\Helpers;
use SugarCalendarBookings\Support\Helpers\Date;
use SugarCalendarBookings\Support\Helpers\UI;

/**
 * Calendar agenda view.
 *
 * @since 1.3.0
 */
class CalendarAgendaView extends AbstractCalendarView {

	/**
	 * View mode.
	 *
	 * @since 1.3.0
	 *
	 * @var string
	 */
	const MODE = 'agenda';

	/**
	 * Default service color when appointment has no service or service has no color.
	 *
	 * @since 1.3.0
	 *
	 * @var string
	 */
	const DEFAULT_SERVICE_COLOR = '#cccccc';

	/**
	 * Get appointments relationships.
	 *
	 * @since 1.3.0
	 *
	 * @return array
	 */
	public function get_appointments_relationships() {

		$relationships = parent::get_appointments_relationships();

		$relationships['customer'] = fn( $q ) => $q->select( [ 'id', 'name' ] );
		$relationships['location'] = fn( $q ) => $q->select( [ 'id', 'name' ] );
		$relationships['meta']     = null;

		return $relationships;
	}

	/**
	 * Get default columns.
	 *
	 * @since 1.3.0
	 *
	 * @return array
	 */
	protected function get_default_columns() {

		return [
			'time'    => esc_html__( 'Time', 'sugar-calendar-bookings-scheduling-appointments-lite' ),
			'service' => esc_html__( 'Service', 'sugar-calendar-bookings-scheduling-appointments-lite' ),
		];
	}

	/**
	 * Get column options.
	 *
	 * @since 1.3.0
	 *
	 * @return array
	 */
	public function get_column_options() {

		return [
			'customer' => esc_html__( 'Customer', 'sugar-calendar-bookings-scheduling-appointments-lite' ),
			'location' => esc_html__( 'Location', 'sugar-calendar-bookings-scheduling-appointments-lite' ),
			'status'   => esc_html__( 'Status', 'sugar-calendar-bookings-scheduling-appointments-lite' ),
		];
	}

	/**
	 * Get all columns.
	 *
	 * @since 1.3.0
	 *
	 * @return array
	 */
	private function get_all_columns() {

		return array_merge( $this->get_default_columns(), $this->get_column_options() );
	}

	/**
	 * Get column keys that are grouped on the right side of the appointment row.
	 *
	 * @since 1.3.0
	 *
	 * @return array
	 */
	protected function get_appointment_right_columns() {

		return [ 'status' ];
	}

	/**
	 * Get the service color for an appointment.
	 *
	 * @since 1.3.0
	 *
	 * @param AppointmentModel $appointment Appointment model.
	 *
	 * @return string Hex color.
	 */
	protected function get_appointment_service_color( $appointment ) {

		return $appointment->service ? $appointment->service->color : self::DEFAULT_SERVICE_COLOR;
	}

	/**
	 * Get header slots.
	 *
	 * @since 1.3.0
	 *
	 * @return array<BaseCalendarSlot>
	 */
	protected function get_header_slots() {

		// Agenda view doesn't use traditional header slots.
		return [];
	}

	/**
	 * Get body slots.
	 *
	 * @since 1.3.0
	 *
	 * @return array<BaseCalendarSlot>
	 */
	protected function get_body_slots() {

		// Use local agenda-specific date calculations.
		return $this->get_slots(
			$this->get_agenda_start_date(),
			$this->get_agenda_end_date()
		);
	}

	/**
	 * Get body cell class.
	 *
	 * @since 1.3.0
	 *
	 * @param BaseCalendarSlot $slot Calendar slot.
	 *
	 * @return array
	 */
	protected function get_body_cell_class( $slot ) {

		$class = parent::get_body_cell_class( $slot );

		$class[] = 'sugar-calendar-bookings-calendar__cell--agenda-day';

		if ( $slot->is_same_day( $this->query->get_today() ) ) {
			$class[] = 'sugar-calendar-bookings-calendar__cell--today';
		}

		return $class;
	}

	/**
	 * Display body cell.
	 *
	 * @since 1.3.0
	 *
	 * @param BaseCalendarSlot        $slot         Calendar slot.
	 * @param array<AppointmentModel> $appointments Appointments.
	 *
	 * @return void
	 */
	protected function display_body_cell( $slot, $appointments ) {

		// Sort appointments by start time, end time, then ID.
		usort(
			$appointments,
			function ( $a, $b ) {

				$start_compare = $a->start_at <=> $b->start_at;

				if ( $start_compare !== 0 ) {
					return $start_compare;
				}

				$end_compare = $a->end_at <=> $b->end_at;

				if ( $end_compare !== 0 ) {
					return $end_compare;
				}

				return $a->id <=> $b->id;
			}
		);

		?>
		<div class="sugar-calendar-bookings-calendar__date-group">
			<?php
			$this->display_date_sidebar( $slot );
			$this->display_appointments_list( $appointments, $slot );
			?>
		</div>
		<?php
	}

	/**
	 * Display the calendar.
	 *
	 * @since 1.3.0
	 *
	 * @return void
	 */
	public function display() {

		$this->output_styles();

		if ( $this->should_display_notice() ) {
			$this->display_search_notice();
		}
		?>

		<div class="sugar-calendar-bookings-calendar-view" data-mode="<?php echo esc_attr( static::MODE ); ?>">

			<?php $this->display_filters(); ?>

			<div class="sugar-calendar-bookings-calendar sugar-calendar-bookings-calendar--<?php echo esc_attr( static::MODE ); ?>">

				<div class="sugar-calendar-bookings-calendar__header">

					<?php
					foreach ( $this->get_header_slots() as $slot ) :
						$class = UI::sanitize_class( $this->get_header_cell_class( $slot ) );
						?>

						<div class="<?php echo esc_attr( $class ); ?>"><?php $this->display_header_cell( $slot ); ?></div>

					<?php endforeach; ?>

				</div>
				<div class="sugar-calendar-bookings-calendar__content">

					<div class="sugar-calendar-bookings-calendar__dates-wrapper">
						<?php foreach ( $this->get_body_slots() as $slot ) : ?>

							<?php
							$entries = $this->get_entries( $slot );
							$class   = UI::sanitize_class( $this->get_body_cell_class( $slot ) );
							?>

							<div class="<?php echo esc_attr( $class ); ?>">
								<?php $this->display_body_cell( $slot, $entries ); ?>
							</div>

						<?php endforeach; ?>
					</div>

					<?php $this->display_body_after(); ?>

				</div>
				<div class="sugar-calendar-bookings-calendar__footer">

					<?php
					foreach ( $this->get_footer_slots() as $slot ) :
						$class = UI::sanitize_class( $this->get_footer_cell_class( $slot ) );
						?>

						<div class="<?php echo esc_attr( $class ); ?>"><?php $this->display_footer_cell( $slot ); ?></div>

					<?php endforeach; ?>

				</div>
			</div>
		</div>
		<?php
	}

	/**
	 * Display body after content.
	 *
	 * @since 1.3.0
	 *
	 * @return void
	 */
	protected function display_body_after() {

		$this->display_mini_calendar();
	}

	/**
	 * Display mini calendar container.
	 *
	 * @since 1.3.0
	 *
	 * @return void
	 */
	private function display_mini_calendar() {

		$mini_calendar_data = $this->get_mini_calendar_data();
		$current_date       = $this->query->get_date();
		$month_year         = wp_date( 'M, Y', $current_date->getTimestamp(), Date::get_default_timezone() );
		?>
		<div class="sugar-calendar-bookings-calendar__mini-calendar-wrapper">
			<div class="sugar-calendar-bookings-calendar__mini-calendar-header">
				<?php
				echo esc_html(
					sprintf(
					/* translators: %1$s - month and year. */
						__( 'Overview of %1$s', 'sugar-calendar-bookings-scheduling-appointments-lite' ),
						$month_year
					)
				);
				?>
			</div>
			<div
				id="sugar-calendar-bookings-calendar-mini-calendar"
				class="sugar-calendar-bookings-calendar__mini-calendar"
				data-mini-calendar-data="<?php echo esc_attr( wp_json_encode( $mini_calendar_data ) ); ?>">
			</div>
		</div>
		<?php
	}

	/**
	 * Get mini calendar data.
	 *
	 * @since 1.3.0
	 *
	 * @return array
	 */
	private function get_mini_calendar_data() {

		$current_date = $this->query->get_date();

		return [
			'currentMonth'    => $current_date->format( 'Y-m-d' ),
			'selectedDate'    => $current_date->format( 'Y-m-d' ),
			'baseUrl'         => $this->query->get_base_url(),
			'filters'         => $this->query->get_applied_filters(),
			'appointments'    => $this->get_appointments_for_mini_calendar(),
			'displayTimeZone' => Date::get_default_timezone_string(),
			'startOfWeek'     => Plugin::get( Options::class )->get( 'display.start_of_week' ),
		];
	}

	/**
	 * Get appointments data for mini calendar.
	 *
	 * @since 1.3.0
	 *
	 * @return array
	 */
	private function get_appointments_for_mini_calendar() {

		// Get appointments for first week until the last week of the month.
		$appointments = $this->get_appointments_for_full_calendar_range();

		// Group appointments by date and service color.
		$appointments_by_date = [];

		foreach ( $appointments as $appointment ) {
			$date = Date::format_display_date( $appointment->start_at, 'Y-m-d' );

			if ( ! isset( $appointments_by_date[ $date ] ) ) {
				$appointments_by_date[ $date ] = [];
			}

			$appointments_by_date[ $date ][] = [
				'id'    => $appointment->id,
				'color' => $this->get_appointment_service_color( $appointment ),
			];
		}

		// Limit to 5 appointments per day for display.
		foreach ( $appointments_by_date as $date => $day_appointments ) {
			if ( count( $day_appointments ) > 5 ) {
				$appointments_by_date[ $date ]                  = array_slice( $day_appointments, 0, 5 );
				$appointments_by_date[ $date ][4]['isOverflow'] = true;
			}
		}

		return $appointments_by_date;
	}

	/**
	 * Get appointments for full calendar range.
	 *
	 * @since 1.3.0
	 *
	 * @return array
	 */
	private function get_appointments_for_full_calendar_range() {

		// Get the current month's start and end dates.
		$current_date = $this->query->get_date();
		$month_start  = $current_date->modify( 'first day of this month' )->setTime( 0, 0, 0 );

		// Calculate the full 6-week calendar range to include outside days.
		// This ensures appointments on previous/next month's days are included.
		$start_of_week = Plugin::get( Options::class )->get( 'display.start_of_week' );

		// Find the first day of the calendar grid (may be in previous month).
		$calendar_start = clone $month_start;
		$day_of_week    = (int) $calendar_start->format( 'w' ); // 0 (Sunday) to 6 (Saturday).

		// Calculate days to subtract to reach the start of week.
		$days_to_subtract = ( $day_of_week - $start_of_week + 7 ) % 7;

		if ( $days_to_subtract > 0 ) {
			$calendar_start = $calendar_start->modify( "-{$days_to_subtract} days" );
		}

		// Find the last day of the calendar grid (may be in next month).
		// A calendar grid is typically 6 weeks (42 days) to accommodate all scenarios.
		$calendar_end = $calendar_start->modify( '+41 days' )->setTime( 23, 59, 59 );

		return $this->query_appointments_for_range( $calendar_start, $calendar_end );
	}

	/**
	 * Query appointments for a specific date range.
	 *
	 * @since 1.3.0
	 *
	 * @param DateTimeImmutable $start_date Start date.
	 * @param DateTimeImmutable $end_date   End date.
	 *
	 * @return array<AppointmentModel>
	 */
	private function query_appointments_for_range( $start_date, $end_date ) {

		$start_date_utc = Date::to_utc( $start_date )->format( Date::DB_DATETIME_FORMAT );
		$end_date_utc   = Date::to_utc( $end_date )->format( Date::DB_DATETIME_FORMAT );

		$query = AppointmentModel::query()
			->with( [ 'service' => fn( $q ) => $q->select( [ 'id', 'name', 'color' ] ) ] )
			->where(
				function ( $q ) use ( $start_date_utc, $end_date_utc ) {
					$q->where( 'appointments.start_at', '>=', $start_date_utc, '%s' )
						->where( 'appointments.start_at', '<=', $end_date_utc, '%s' );
				}
			)
			->or_where(
				function ( $q ) use ( $start_date_utc, $end_date_utc ) {
					$q->where( 'appointments.end_at', '>=', $start_date_utc, '%s' )
						->where( 'appointments.end_at', '<=', $end_date_utc, '%s' );
				}
			);

		// Apply the same filters as the main query (status, service, search).
		$filters = $this->query->get_applied_filters();

		if ( ! empty( $filters['status'] ) ) {
			$query = $query->where( 'appointments.status', '=', $filters['status'], '%s' );
		}

		if ( isset( $filters['service_id'] ) && $filters['service_id'] !== '' ) {
			$query = $query->where( 'appointments.service_id', '=', $filters['service_id'], '%s' );
		}

		return $query->order_by( 'start_at' )->get();
	}

	/**
	 * Display date sidebar for agenda.
	 *
	 * @since 1.3.0
	 *
	 * @param BaseCalendarSlot $slot Calendar slot.
	 *
	 * @return void
	 */
	private function display_date_sidebar( $slot ) {

		$timestamp = $slot->get_start()->getTimestamp();

		// Set default time to middle of the day (12:00 PM).
		$start_datetime = $slot->get_start()->setTime( 12, 0, 0 );
		$end_datetime   = $slot->get_start()->setTime( 13, 0, 0 );

		?>
		<div class="sugar-calendar-bookings-calendar__date-sidebar">
			<div class="sugar-calendar-bookings-calendar__date-number">
				<?php echo esc_html( wp_date( 'd', $timestamp, Date::get_default_timezone() ) ); ?>
			</div>
			<div class="sugar-calendar-bookings-calendar__date-label">
				<?php echo esc_html( wp_date( 'M, D', $timestamp, Date::get_default_timezone() ) ); ?>
				<?php CalendarHelpers::add_appointment_button( $start_datetime, $end_datetime ); ?>
			</div>
		</div>
		<?php
	}

	/**
	 * Display appointments list for a day.
	 *
	 * @since 1.3.0
	 *
	 * @param array<AppointmentModel> $appointments Appointments.
	 * @param BaseCalendarSlot        $slot         Calendar slot.
	 *
	 * @return void
	 */
	private function display_appointments_list( $appointments, $slot ) {

		?>
		<div class="sugar-calendar-bookings-calendar__appointments-container" data-date="<?php echo esc_attr( $slot->get_start()->format( 'Y-m-d' ) ); ?>">
			<?php if ( $this->is_today( $slot ) ) : ?>
				<?php $this->display_current_time_marker( 'opacity: 0;' ); ?>
			<?php endif; ?>

			<?php foreach ( $appointments as $appointment ) : ?>
				<?php $this->display_appointment_row( $appointment ); ?>
			<?php endforeach; ?>
		</div>
		<?php
	}

	/**
	 * Display a single appointment row.
	 *
	 * @since 1.3.0
	 *
	 * @param AppointmentModel $appointment Appointment model.
	 *
	 * @return void
	 */
	protected function display_appointment_row( $appointment ) {

		$status    = 'appointment-' . $appointment->status;
		$row_class = [
			'sugar-calendar-bookings-calendar__appointment',
			$status,
		];
		?>
		<div
			class="<?php echo esc_attr( UI::sanitize_class( $row_class ) ); ?>"
			data-preview
			data-appointment-id="<?php echo esc_attr( $appointment->id ); ?>"
			data-start-time="<?php echo esc_attr( $appointment->start_at->format( 'c' ) ); ?>"
			data-end-time="<?php echo esc_attr( $appointment->end_at->format( 'c' ) ); ?>"
			data-popover-placement="left"
			data-popover-style="<?php echo esc_attr( self::MODE ); ?>"
		>

			<?php $this->display_appointment_columns( $appointment ); ?>

		</div>
		<?php
	}

	/**
	 * Display appointment column.
	 *
	 * @since 1.3.0
	 *
	 * @param AppointmentModel $appointment Appointment model.
	 *
	 * @return void
	 */
	protected function display_appointment_columns( $appointment ) {

		$columns       = $this->get_all_columns();
		$right_columns = $this->get_appointment_right_columns();
		$column_keys   = array_keys( $columns );
		$right_keys    = array_intersect( $column_keys, $right_columns );
		$left_keys     = array_diff( $column_keys, $right_columns );

		foreach ( $left_keys as $key ) {
			$column_renderer = 'display_appointment_' . $key;

			if ( method_exists( $this, $column_renderer ) ) {
				$this->$column_renderer( $appointment );
			}
		}

		if ( ! empty( $right_keys ) ) {
			echo '<div class="sugar-calendar-bookings-calendar__appointment-right-group">';

			foreach ( $right_keys as $key ) {
				$column_renderer = 'display_appointment_' . $key;

				if ( method_exists( $this, $column_renderer ) ) {
					$this->$column_renderer( $appointment );
				}
			}

			echo '</div>';
		}
	}

	/**
	 * Display appointment time.
	 *
	 * @since 1.3.0
	 *
	 * @param AppointmentModel $appointment Appointment model.
	 *
	 * @return void
	 */
	protected function display_appointment_time( $appointment ) {

		$service_color = $this->get_appointment_service_color( $appointment );
		?>
		<span class="sugar-calendar-bookings-calendar__appointment-time"
			style="--service-color: <?php echo esc_attr( $service_color ); ?>;">
			<?php
			echo esc_html(
				sprintf(
				/* translators: %1$s - appointment start time; %2$s - appointment end time. */
					__( '%1$s - %2$s', 'sugar-calendar-bookings-scheduling-appointments-lite' ),
					Date::format_display_date( $appointment->start_at, 'g:i A' ),
					Date::format_display_date( $appointment->end_at, 'g:i A' )
				)
			);
			?>
		</span>
		<?php
	}

	/**
	 * Display appointment service.
	 *
	 * @since 1.3.0
	 *
	 * @param AppointmentModel $appointment Appointment model.
	 *
	 * @return void
	 */
	protected function display_appointment_service( $appointment ) {

		$service_name = $appointment->service ? $appointment->service->name : '';
		?>
		<span class="sugar-calendar-bookings-calendar__appointment-service">
			<?php echo esc_html( $service_name ); ?>
		</span>
		<?php
	}

	/**
	 * Display appointment customer.
	 *
	 * @since 1.3.0
	 *
	 * @param AppointmentModel $appointment Appointment model.
	 *
	 * @return void
	 */
	protected function display_appointment_customer( $appointment ) {

		$customer_name = $appointment->customer ? $appointment->customer->name : '';
		?>
		<span class="sugar-calendar-bookings-calendar__appointment-customer">
			<?php
			echo esc_html(
				__( 'for', 'sugar-calendar-bookings-scheduling-appointments-lite' )
			);
			?>
			<span class="sugar-calendar-bookings-calendar__appointment-customer-name">
				<?php echo esc_html( $customer_name ); ?>
			</span>
		</span>
		<?php
	}

	/**
	 * Display appointment location.
	 *
	 * @since 1.3.0
	 * @since 1.4.0 Resolve Zoom join URL from appointment data.
	 *
	 * @param AppointmentModel $appointment Appointment model.
	 *
	 * @return void
	 */
	protected function display_appointment_location( $appointment ) {

		$location = $appointment->get_location();

		if ( ! $location ) {
			return;
		}

		?>
		<span
			class="sugar-calendar-bookings-calendar__appointment-location"
			<?php UI::maybe_render_title_attribute( $location->get_display_name() ); ?>
		>
			<?php UI::render_appointment_location_for_display( $location, $appointment ); ?>
		</span>
		<?php
	}

	/**
	 * Display appointment status.
	 *
	 * @since 1.3.0
	 *
	 * @param AppointmentModel $appointment Appointment model.
	 *
	 * @return void
	 */
	protected function display_appointment_status( $appointment ) {
		?>
		<span class="sugar-calendar-bookings-calendar__appointment-status">
			<span class="status-badge <?php echo esc_attr( $appointment->status ); ?>">
				<?php echo esc_html( $appointment->get_status_label() ); ?>
			</span>
		</span>
		<?php
	}

	/**
	 * Output dynamic styles.
	 *
	 * @since 1.3.0
	 *
	 * @return void
	 */
	public function output_styles() {

		$hidden_columns = Plugin::get( CalendarScreenOptions::class )->get( 'hidden_columns' );
		$hidden_columns = $hidden_columns[ static::MODE ] ?? [];

		Helpers::template(
			'calendar/agenda-view-styles.php',
			[
				'hidden_columns' => $hidden_columns,
			]
		);
	}

	/**
	 * Get pagination first link URL.
	 *
	 * @since 1.3.0
	 *
	 * @return string
	 */
	protected function pagination_get_first_link_url() {

		return $this->query->get_url_with_date( $this->query->get_previous_month() );
	}

	/**
	 * Get pagination previous link URL.
	 *
	 * @since 1.3.0
	 *
	 * @return string
	 */
	protected function pagination_get_previous_link_url() {

		return $this->query->get_url_with_date( $this->get_previous_agenda_window() );
	}

	/**
	 * Get pagination next link URL.
	 *
	 * @since 1.3.0
	 *
	 * @return string
	 */
	protected function pagination_get_next_link_url() {

		return $this->query->get_url_with_date( $this->get_next_agenda_window() );
	}

	/**
	 * Get pagination last link URL.
	 *
	 * @since 1.3.0
	 *
	 * @return string
	 */
	protected function pagination_get_last_link_url() {

		return $this->query->get_url_with_date( $this->query->get_next_month() );
	}

	/**
	 * Get pagination first link text.
	 *
	 * @since 1.3.0
	 *
	 * @return string
	 */
	protected function pagination_get_first_link_text() {

		return esc_html__( 'Previous Month', 'sugar-calendar-bookings-scheduling-appointments-lite' );
	}

	/**
	 * Get pagination previous link text.
	 *
	 * @since 1.3.0
	 *
	 * @return string
	 */
	protected function pagination_get_previous_link_text() {

		$count = $this->get_agenda_window_count();
		$type  = $this->get_agenda_window_type();

		return sprintf(
			/* translators: %1$d - number; %2$s - unit type (days, weeks, months, etc.). */
			esc_html__( 'Previous %1$d %2$s', 'sugar-calendar-bookings-scheduling-appointments-lite' ),
			$count,
			esc_html( $type )
		);
	}

	/**
	 * Get pagination next link text.
	 *
	 * @since 1.3.0
	 *
	 * @return string
	 */
	protected function pagination_get_next_link_text() {

		$count = $this->get_agenda_window_count();
		$type  = $this->get_agenda_window_type();

		return sprintf(
			/* translators: %1$d - number; %2$s - unit type (days, weeks, months, etc.). */
			esc_html__( 'Next %1$d %2$s', 'sugar-calendar-bookings-scheduling-appointments-lite' ),
			$count,
			esc_html( $type )
		);
	}

	/**
	 * Get pagination last link text.
	 *
	 * @since 1.3.0
	 *
	 * @return string
	 */
	protected function pagination_get_last_link_text() {

		return esc_html__( 'Next Month', 'sugar-calendar-bookings-scheduling-appointments-lite' );
	}

	/**
	 * Get agenda window type.
	 *
	 * @since 1.3.0
	 *
	 * @return string
	 */
	protected function get_agenda_window_type() {

		return 'days';
	}

	/**
	 * Get agenda window count.
	 *
	 * @since 1.3.0
	 *
	 * @return int
	 */
	protected function get_agenda_window_count() {

		return 5;
	}

	/**
	 * Get agenda start date.
	 *
	 * @since 1.3.0
	 *
	 * @return DateTimeImmutable
	 */
	protected function get_agenda_start_date() {

		return $this->query->get_date()->setTime( 0, 0 );
	}

	/**
	 * Get agenda end date.
	 *
	 * @since 1.3.0
	 *
	 * @return DateTimeImmutable
	 */
	protected function get_agenda_end_date() {

		$window_count = $this->get_agenda_window_count();
		$agenda_count = $window_count - 1;
		$type         = $this->get_agenda_window_type();

		return $this->query->get_date()
			->modify( "+{$agenda_count} {$type}" )
			->setTime( 23, 59, 59 );
	}

	/**
	 * Get previous agenda window's date.
	 *
	 * @since 1.3.0
	 *
	 * @return DateTimeImmutable
	 */
	protected function get_previous_agenda_window() {

		static $previous = null;

		if ( is_null( $previous ) ) {
			$count    = $this->get_agenda_window_count();
			$type     = $this->get_agenda_window_type();
			$previous = $this->query->get_date()->modify( "-{$count} {$type}" );
		}

		return $previous;
	}

	/**
	 * Get next agenda window's date.
	 *
	 * @since 1.3.0
	 *
	 * @return DateTimeImmutable
	 */
	protected function get_next_agenda_window() {

		static $next = null;

		if ( is_null( $next ) ) {
			$count = $this->get_agenda_window_count();
			$type  = $this->get_agenda_window_type();
			$next  = $this->query->get_date()->modify( "+{$count} {$type}" );
		}

		return $next;
	}
}
