<?php
/**
 * Calendar view shortcode.
 *
 * @package EventimUSEventListings
 */

defined( 'ABSPATH' ) || exit;

global $evuselConfig;
add_shortcode( $evuselConfig::SHORTCODE_CALENDAR_VIEW, 'evusel_calendar_view_shortcode' );
/**
 * Render calendar view shortcode.
 *
 * @param string|null $month Month to display.
 * @return string Shortcode output.
 */
function evusel_calendar_view_shortcode( $month = null ) {

	global $evuselConfig;

	$firstDayOfWeek  = $evuselConfig->get( 'shortcodes.calendar_view.first_day_of_week' );
	$showEmptyMonths = $evuselConfig->get( 'shortcodes.calendar_view.show_empty_months' );
	$numberOfMonths  = (int) $evuselConfig->get( 'shortcodes.calendar_view.number_of_months' );
	$hideRepeating   = $evuselConfig->get( 'show_repeating_events' ) === false;

	$dateTimeZone = new DateTimeZone( 'UTC' );
	$startDate    = new DateTime( 'first day of this month', $dateTimeZone );
	$endDate      = new DateTime( 'now', $dateTimeZone );
	$endDate->modify( '+' . ( $numberOfMonths - 1 ) . ' months' )->modify( 'last day of this month' )->setTime( 23, 59, 59 );

	$startDateFormatted   = $startDate->format( 'Ymd' );
	$endDateFormatted     = $endDate->format( 'Ymd' );
	$endDateTimeFormatted = $endDate->format( 'Y-m-d H:i:s' );

	$simple_args = array(
		'posts_per_page' => -1,
		'post_type'      => 'seetickets-event',
		'post_status'    => array( 'publish' ),
		'meta_query'     => array(
			array(
				'key'     => 'sort_date',
				'value'   => $startDateFormatted,
				'compare' => '>=',
				'type'    => 'DATE',
			),
			array(
				'key'     => 'sort_date',
				'value'   => $endDateFormatted,
				'compare' => '<=',
				'type'    => 'DATE',
			),
		),
		'orderby'        => 'meta_value',
		'order'          => 'ASC',
		'meta_key'       => 'sort_date',
		'meta_type'      => 'DATE',
	);

	if ( $hideRepeating ) {
		$simple_args['post_parent'] = 0;
	}

	$query  = new WP_Query();
	$events = $query->query( $simple_args );

	if ( empty( $events ) ) {
		$test_args = array(
			'posts_per_page' => 50,
			'post_type'      => 'seetickets-event',
			'post_status'    => array( 'publish' ),
		);
		if ( $hideRepeating ) {
			$test_args['post_parent'] = 0;
		}
		$test_query  = new WP_Query();
		$test_events = $test_query->query( $test_args );
		if ( ! empty( $test_events ) ) {
			$events = $test_events;
		}
	}

	$calendar = '';

	$calendar .= do_shortcode( '[seelistview type="grid" withcalendar=""]' );

	$eventsOrganised = array();

	foreach ( $events as $event ) {
		// Skip repeating child posts – we only need the parent event once per day
		if ( $event->post_parent != 0 ) {
			continue;
		}

		$displayDateTime = evusel_get_event_display_date_time( $event->ID );

		// Fallback to sort_date if event_time is not available
		if ( empty( $displayDateTime ) ) {
			$sortDate = get_post_meta( $event->ID, 'sort_date', true );
			if ( ! empty( $sortDate ) ) {
				$sortDateFormatted = DateTime::createFromFormat( 'Ymd', $sortDate, $dateTimeZone );
				if ( $sortDateFormatted ) {
					$sortDateFormatted->setTime( 0, 0, 0 );
					$displayTimeZone = get_post_meta( $event->ID, 'ianaTimezone', true );
					if ( ! empty( $displayTimeZone ) && in_array( $displayTimeZone, EVUSEL_TIMEZONE_IDENTIFIERS_LIST ) ) {
						$displayTimeZoneObj = new DateTimeZone( $displayTimeZone );
						$sortDateFormatted->setTimezone( $displayTimeZoneObj );
					}
					$displayDateTime = $sortDateFormatted;
				}
			}
		}

		if ( ! empty( $displayDateTime ) ) {
			$eventYear  = $displayDateTime->format( 'Y' );
			$eventMonth = $displayDateTime->format( 'm' );
			$eventDay   = $displayDateTime->format( 'd' );
			$eventTime  = $displayDateTime->format( 'Gi' );

			$eventsOrganised[ $eventYear ][ $eventMonth ][ $eventDay ][ $eventTime ][] = $event;

			// Add entries for each day of multi-day events only if show_repeating_events is ON
			$isMultiDay         = get_post_meta( $event->ID, 'is_multiday', true );
			$multiDayEventDates = get_post_meta( $event->ID, 'multiDayEventDates', true );

			if ( $isMultiDay && is_array( $multiDayEventDates ) && count( $multiDayEventDates ) > 1 && ! $hideRepeating ) {
				foreach ( $multiDayEventDates as $dateStr ) {
					$dateObj = DateTime::createFromFormat( 'm/d/Y', $dateStr );
					if ( ! empty( $dateObj ) ) {
						$mdYear  = $dateObj->format( 'Y' );
						$mdMonth = $dateObj->format( 'm' );
						$mdDay   = $dateObj->format( 'd' );

						// Skip if this is the same date as the main event date
						if ( $mdYear == $eventYear && $mdMonth == $eventMonth && $mdDay == $eventDay ) {
							continue;
						}

						// Use the same time as the original event
						$eventsOrganised[ $mdYear ][ $mdMonth ][ $mdDay ][ $eventTime ][] = $event;
					}
				}
			}
		}
	}

	if ( empty( $eventsOrganised ) && ! empty( $events ) ) {
		foreach ( $events as $event ) {
			if ( $event->post_parent != 0 ) {
				continue;
			}
			$sortDate = get_post_meta( $event->ID, 'sort_date', true );
			if ( ! empty( $sortDate ) ) {
				$sortDateObj = DateTime::createFromFormat( 'Ymd', $sortDate, $dateTimeZone );
				if ( $sortDateObj ) {
					$eventYear  = $sortDateObj->format( 'Y' );
					$eventMonth = $sortDateObj->format( 'm' );
					$eventDay   = $sortDateObj->format( 'd' );
					if ( ! isset( $eventsOrganised[ $eventYear ][ $eventMonth ][ $eventDay ] ) ) {
						$eventsOrganised[ $eventYear ][ $eventMonth ][ $eventDay ] = array();
					}
					if ( ! isset( $eventsOrganised[ $eventYear ][ $eventMonth ][ $eventDay ][0] ) ) {
						$eventsOrganised[ $eventYear ][ $eventMonth ][ $eventDay ][0] = array();
					}
					$eventsOrganised[ $eventYear ][ $eventMonth ][ $eventDay ][0][] = $event;
				}
			}
		}
	}

	$today = ( new DateTime( 'now', $dateTimeZone ) )->format( 'Y-m-j' );

	// Trim $eventsOrganised to only include months within the configured range.
	$allowedMonths     = array();
	$rangeMonthCursor  = new DateTime( 'first day of this month', $dateTimeZone );
	for ( $m = 0; $m < $numberOfMonths; $m++ ) {
		$allowedMonths[] = $rangeMonthCursor->format( 'Y' ) . '-' . $rangeMonthCursor->format( 'm' );
		$rangeMonthCursor->modify( '+1 month' );
	}
	foreach ( $eventsOrganised as $yr => $months ) {
		foreach ( $months as $mo => $days ) {
			if ( ! in_array( $yr . '-' . $mo, $allowedMonths, true ) ) {
				unset( $eventsOrganised[ $yr ][ $mo ] );
			}
		}
		if ( empty( $eventsOrganised[ $yr ] ) ) {
			unset( $eventsOrganised[ $yr ] );
		}
	}

	/**
	 * Count total months displayed and fill empty months
	 * This logic ignores the date of the last event in the calendar, and continues to fill empty months until the total number of displayed months is met.
	 */
	if ( $showEmptyMonths === 'on' ) {

		$totalMonthsDisplayed = 1;
		$currentMonthNo       = 0;
		$startOfCurrentMonth  = DateTime::createFromFormat( 'Y-m-d', $today )->modify( 'first day of' )->setTime( 0, 0, 0 );
		$year                 = (int) $startOfCurrentMonth->format( 'Y' );

		while ( $numberOfMonths >= $totalMonthsDisplayed ) {

			$monthKey       = str_pad( ++$currentMonthNo, 2, '0', STR_PAD_LEFT );
			$monthToAddDate = DateTime::createFromFormat( 'Ymd', $year . $monthKey . '01' )->setTime( 0, 0, 0 );

			if ( ! isset( $eventsOrganised[ $year ][ $monthKey ] ) && $monthToAddDate >= $startOfCurrentMonth ) {
				$eventsOrganised[ $year ][ $monthKey ] = null;
				++$totalMonthsDisplayed;
			} elseif ( isset( $eventsOrganised[ $year ][ $monthKey ] ) ) {
				++$totalMonthsDisplayed;
			}

			if ( $currentMonthNo === 12 ) {
				$currentMonthNo = 0;
				++$year;
			}
		}
	}

	$calendar .= '<div class="seetickets-calendar-container">';

	foreach ( $eventsOrganised as $year => $monthsOrganised ) {

		/**
		 * Fill in empty months
		 * This part is useful here if there is no need to display empty months AFTER the last event in the calendar.
		 * This was an earlier requirement, it is adwised to keep it here in case requirements change in the future
		 */
		// if($showEmptyMonths === 'on') {
		// for ($month = 1; $month <= 12; $month++) {

		// $lastEvent = end($events);
		// $startOfCurrentMonth = DateTime::createFromFormat('Y-m-d', $today)->modify('first day of')->setTime(0,0,0);
		// $monthToAddDate = DateTime::createFromFormat('Ym', $year . $month)->setTime(0,0,0);
		// $endLastEventMonth = DateTime::createFromFormat('Ymd', get_field('sort_date', $lastEvent->ID))->modify('last day of')->setTime(23,59,59);

		// if ($monthToAddDate > $startOfCurrentMonth && $monthToAddDate < $endLastEventMonth) {
		// $monthKey = str_pad($month, 2, '0', STR_PAD_LEFT);
		// if (!isset($monthsOrganised[$monthKey])) {
		// $monthsOrganised[$monthKey] = null;
		// }
		// }
		// }
		// }

		ksort( $monthsOrganised );

		$calendarYear        = '';
		$hideRepeatingImages = $evuselConfig->get( 'shortcodes.calendar_view.hide_repeating_images' ) === 'on';
		$showVenueNames      = $evuselConfig->get( 'shortcodes.calendar_view.show_venue_name' ) === 'on';

		foreach ( $monthsOrganised as $month => $currentMonth ) {

			$calendarMonth = '';
			$weeks         = array();
			$week          = '';

			$ym = $year . '-' . $month;

			$date = explode( '-', $ym );
			$year = $date[0];

			$ym = $year . '-' . $month;

			$timestamp = strtotime( $ym . '-01' );
			if ( $timestamp === false ) {
				$ym        = gmdate( 'Y-m' );
				$timestamp = strtotime( $ym . '-01' );
			}

			$day_count = gmdate( 't', $timestamp );

			// Determine first day of the month
			$str = gmdate( 'w', mktime( 0, 0, 0, gmdate( 'm', $timestamp ), 1, gmdate( 'Y', $timestamp ) ) );
			if ( $firstDayOfWeek === 'm' ) {
				$str = $str > 0 ? $str - 1 : 6;
			}

			// Add empty cell
			$week .= str_repeat( '<td></td>', $str );

			for ( $day = 1; $day <= $day_count; $day++, $str++ ) {

				$date = $year . '-' . $month . '-' . $day;

				$week .= $today == $date ? '<td class="today">' : '<td>';

				$day   = str_pad( $day, 2, '0', STR_PAD_LEFT );
				$month = str_pad( $month, 2, '0', STR_PAD_LEFT );

				$week .= '<div class="fs-16 date-number">' . esc_html( $day ) . '</div>';

				if ( isset( $eventsOrganised[ $year ][ $month ][ $day ] ) ) {

					$eventsOnDay = $eventsOrganised[ $year ][ $month ][ $day ];
					ksort( $eventsOnDay );

					$displayedDailyTitles = array();

					foreach ( $eventsOnDay as $eventsForGivenTime ) {

						foreach ( $eventsForGivenTime as $event ) {

							// if ($hideRepeating && has_post_parent($event)) {

							// $parent = get_post_parent($event);
							// $repeatingDates = $parent->repeating_dates;
							// $lastRepeatingDate = end($repeatingDates);
							// $sortDateTime = DateTime::createFromFormat('Ymd', $event->sort_date);

							// if ($lastRepeatingDate != $sortDateTime->format('m/d/Y')) {
							// continue; // Skip all repeating event,s except for the last one.
							// }
							// }

							$eventTitle = get_post_meta( $event->ID, 'event_title', true );

							if ( ! in_array( $eventTitle, $displayedDailyTitles ) ) {
								$displayedDailyTitles[] = $eventTitle;
								$shouldDisplayImage     = true;
							} else {
								$shouldDisplayImage = ! $hideRepeatingImages;
							}

							$isMultiDay  = get_post_meta( $event->ID, 'is_multiday', true );
							$eventInfoId = $isMultiDay && has_post_parent( $event->ID ) ? wp_get_post_parent_id( $event->ID ) : $event->ID;

							$eventDate        = evusel_get_event_display_date_time( $event->ID );
							$dispevliIsInPast = evuselIsInPast( $event );
							$btnText          = evusel_get_ticket_status_button_text( $event );
							$ariaLabel        = evusel_get_ticket_button_aria_label( $dispevliIsInPast, $eventTitle, $eventDate );
							$classes          = $dispevliIsInPast ? 'disabled ' : '';
							$classes         .= evusel_get_ticket_status_button_classes( $event );

							$style              = $dispevliIsInPast ? 'style="opacity: 60%;"' : '';
							$multiDayEventDates = get_post_meta( $event->ID, 'multiDayEventDates', true );

							$supportingTalent = get_post_meta( $eventInfoId, 'supporting_talent', true );
							$supportingTalent = ! empty( $supportingTalent ) ? evusel_get_supporting_talent_label() . $supportingTalent : '';

							$showTime      = $isMultiDay ? '' : evusel_get_event_display_date_time( $event->ID )->format( 'g:iA' );
							$showTimeLabel = evusel_get_showtime_label();

							$doorDateTime     = $isMultiDay ? '' : evusel_get_event_display_date_time( $event->ID, 'door' );
							$doorTime         = empty( $doorDateTime ) ? '' : $doorDateTime->format( 'g:iA' );
							$doorTimeLabel    = evusel_get_doortime_labe();
							$ticketButtonLink = evusel_get_ticket_link( $event, true );
							$eventImage       = evusel_get_event_image( $event->ID );

							$cardClasses           = $evuselConfig->get( 'shortcodes.calendar_view.material_list_style' ) === 'outlined' ? 'mdc-card--outlined ' : 'mdc-card--elevated ';
							$openEventPageToNewTab = $evuselConfig->get( 'open_event_page_to_new_tab' );

							$ticketButtonLinkTarget = "<a href='" . esc_url( $ticketButtonLink ) . "' aria-label='" . esc_attr( $ariaLabel ) . "' class='" . esc_attr( $classes ) . "' >" . esc_html( $btnText ) . '</a>';

							if ( $openEventPageToNewTab == 'on' ) {
								$ticketButtonLinkTarget = "<a href='" . esc_url( $ticketButtonLink ) . "' target='_blank' aria-label='" . esc_attr( $ariaLabel ) . "' class='" . esc_attr( $classes ) . "' >" . esc_html( $btnText ) . '</a>';
							}

							$doorState = '<p class="' . esc_attr( $evuselConfig->get( 'event_data_classes.doortime_showtime' ) ) . ' fs-12">' . esc_html( $showTimeLabel ) . esc_html( $showTime ) . '</p>';
							if ( evusel_get_door_time_core( $event->ID ) == '' ) {
								$doorState = '';
							}

							$week .= '<div class="seetickets-calendar-event-container mdc-card ' . esc_attr( $cardClasses ) . '" ' . esc_attr( $style ) . '>';
							$week .= $shouldDisplayImage ?
								evusel_anchorize( '<img class="seetickets-calendar-event-picture" src="' . esc_url( $eventImage ) . '">', $event, 'seetickets-calendar-event-picture' ) :
								'<div class="seetickets-calendar-event-picture-empty"></div>';

							$week .= '<div class="calendar-body">';
							$week .= '<div class="' . esc_attr( $evuselConfig->get( 'event_data_classes.title' ) ) . ' seetickets-calendar-event-title"><p class="fs-12 bold m-0">' . evusel_anchorize( $eventTitle, $event ) . '</p></div>';
							$week .= empty( $supportingTalent ) ? '' : '<div><p class="' . esc_attr( $evuselConfig->get( 'event_data_classes.supporting_talent' ) ) . ' fs-12">' . esc_html( $supportingTalent ) . '</p></div>';
							$week .= empty( $showTime ) && empty( $doorTime ) ? '' : '<div class="seetickets-calendar-event-date">';
							$week .= $doorState;
							$week .= empty( $doorTime ) ? '' : '<p class="' . esc_attr( $evuselConfig->get( 'event_data_classes.doortime' ) ) . ' fs-12">' . esc_html( $doorTimeLabel ) . esc_html( $doorTime ) . '</p>';
							$week .= ! $showVenueNames ? '' : '<p class="' . esc_attr( $evuselConfig->get( 'event_data_classes.venue' ) ) . ' fs-12">' . esc_html( evusel_get_venue_text( $event->ID ) ) . '</p>';
							$week .= empty( $showTime ) && empty( $doorTime ) ? '' : '</div>';
							$week .= '<div class="fs-12 seetickets-buy-btn text-center ' . esc_attr( $classes ) . '">';
							$week .= $ticketButtonLinkTarget;
							$week .= '</div>';
							$week .= '</div>';
							$week .= '</div>';
						}
					}
				}

				$week .= '</td>';

				// End of the week OR End of the month
				if ( $str % 7 == 6 || $day == $day_count ) {
					if ( $day == $day_count ) {
						// Add empty cell
						$week .= str_repeat( '<td></td>', 6 - ( $str % 7 ) );
					}
					$weeks[] = '<tr>' . $week . '</tr>';
					// Prepare for new week
					$week = '';
				}
			}

			$month = DateTime::createFromFormat( '!m', $month );
			$month = $month->format( 'F' );

			$calendarMonth .= "<div class='seetickets-calendar-year-month-container display-flex'><p class=\"fs-24 m-0\"><span class=\"bold\">$month</span> $year</p></div>";
			$calendarMonth .= ' <table class="seetickets-calendar mt-0 mb-50 "><tr>';

			switch ( $firstDayOfWeek ) {
				case ( 's' ):
					$calendarMonth .= '<th>Sun</th><th>Mon</th><th>Tue</th><th>Wed</th><th>Thu</th><th>Fri</th><th>Sat</th>';
					break;
				case ( 'm' ):
					$calendarMonth .= '<th>Mon</th><th>Tue</th><th>Wed</th><th>Thu</th><th>Fri</th><th>Sat</th><th>Sun</th>';
					break;
			}

			$calendarMonth .= '</tr>';

			foreach ( $weeks as $week ) {
				$calendarMonth .= $week;
			}

			$calendarMonth .= '</table>';
			$calendarYear  .= $calendarMonth;
		}

		$calendar .= $calendarYear;
	}

	$calendar .= '</div>';

	return $calendar;
}
