<?php
namespace SabaiApps\Directories\Component\Calendar\FormField;

use SabaiApps\Directories\Component\Form\Field\FieldsetField;
use SabaiApps\Directories\Component\Form\Form;
use RRule\RRule;

class SlotFormField extends FieldsetField {

	public function formFieldInit( $name, array &$data, Form $form ) {
		$data = array(
			'#tree'     => true,
			'#group'    => true,
			'#row'      => true,
			'#children' => array(
				0 => array(),
			),
		) + $data;
		if ( ! empty( $data['#enable_title'] ) ) {
			$data['#children'][0]['title'] = array(
				'#type'          => 'textfield',
				'#title'         => __( 'Title', 'directories-pro' ) . ' ' . __( '(optional)', 'directories-pro' ),
				'#horizontal'    => true,
				'#default_value' => $data['#default_value']['title'] ?? null,
				'#weight'        => 1,
			);
		}
		$data['#children'][0] += array(
			'repeat' => array(
				'#type'          => 'select',
				'#title'         => __( 'Repeat', 'directories-pro' ),
				'#options'       => array(
					''        => __( 'None', 'directories-pro' ),
					'daily'   => __( 'Daily', 'directories-pro' ),
					'weekly'  => __( 'Weekly', 'directories-pro' ),
					'monthly' => __( 'Monthly', 'directories-pro' ),
					'yearly'  => __( 'Yearly', 'directories-pro' ),
				),
				'#horizontal'    => true,
				'#default_value' => $data['#default_value']['repeat'] ?? '',
				'#class'         => 'drts-calendar-slot-repeat',
				'#weight'        => 3,
			),
			'start'  => array(
				'#title'      => __( 'Date', 'directories-pro' ),
				'#horizontal' => true,
				'#type'       => 'fieldset',
				'#group'      => true,
				'#row'        => true,
				'#tree'       => true,
				'#weight'     => 5,
				'#children'   => array(
					0 => array(
						'date'    => array(
							'#type'          => 'datepicker',
							'#default_value' => $value['start']['date'] ?? null,
							'#col'           => 6,
							'#disable_time'  => true,
						),
						'all_day' => array(
							'#type'          => 'checkbox',
							'#title'         => __( 'All day', 'directories-pro' ),
							'#default_value' => ! empty( $data['#default_value']['start']['all_day'] ),
							'#col'           => 6,
							'#switch'        => false,
							'#class'         => DRTS_BS_PREFIX . 'mb-0 ' . DRTS_BS_PREFIX . 'mt-2 drts-calendar-slot-start-all-day',
						),
					),
				),
			),
			'time'   => array(
				'#title'            => __( 'Time', 'directories-pro' ),
				'#horizontal'       => true,
				'#type'             => 'fieldset',
				'#group'            => true,
				'#row'              => true,
				'#tree'             => true,
				'#weight'           => 7,
				'#element_validate' => array(
					function ( Form $form, &$value, $element ) {
						if ( ! empty( $value['start_time'] )
						&& ! empty( $value['end_time'] )
						&& $value['end_time'] <= $value['start_time']
						) {
									$form->setError( __( 'The end time must be later than the start time.', 'directories-pro' ), $element );
						}
					},
				),
				'#states_selector'  => '.drts-calendar-slot-time',
				'#class'            => 'drts-calendar-slot-time',
				'#states'           => array(
					'visible' => array(
						'.drts-calendar-slot-start-all-day input[type="checkbox"]' => array(
							'type'      => 'checked',
							'value'     => false,
							'container' => '.drts-form-type-calendar-slot',
						),
					),
				),
				'#children'         => array(
					0 => array(
						'start_time' => array(
							'#type'          => 'select',
							'#options'       => array( '' => __( 'Select start time', 'directories-pro' ) ) + $this->_getTimeOptions(),
							'#default_value' => $value['time']['start'] ?? null,
							'#col'           => 6,
						),
						'end_time'   => array(
							'#type'          => 'select',
							'#options'       => array( '' => __( 'Select end time', 'directories-pro' ) ) + $this->_getTimeOptions(),
							'#default_value' => $value['time']['end'] ?? null,
							'#col'           => 6,
						),
					),
				),
			),
		);
		if ( empty( $data['#enable_recurring'] ) ) {
			$data['#children'][0]['repeat']['#value'] = '';
			$data['#children'][0]['repeat']['#type']  = 'hidden';
		} else {
			$data['#children'][0] += array(
				'weekly'        => array(
					'#type'            => 'fieldset',
					'#group'           => true,
					'#states'          => array(
						'visible' => array(
							'.drts-calendar-slot-repeat select' => array(
								'value'     => 'weekly',
								'container' => '.drts-form-type-calendar-slot',
							),
						),
					),
					'#weight'          => 10,
					'#states_selector' => '.drts-calendar-slot-weekly-days',
					'#class'           => 'drts-calendar-slot-weekly-days',
					'#children'        => array(
						0 => array(
							'days' => array(
								'#type'          => 'checkboxes',
								'#title'         => __( 'Days of week', 'directories-pro' ),
								'#options'       => $this->_application->System_Days(),
								'#horizontal'    => true,
								'#default_value' => $data['#default_value']['weekly']['days'] ?? null,
								'#inline'        => true,
							),
						),
					),
				),
				'monthly'       => array(
					'#type'            => 'fieldset',
					'#group'           => true,
					'#states'          => array(
						'visible' => array(
							'.drts-calendar-slot-repeat select' => array(
								'value'     => 'monthly',
								'container' => '.drts-form-type-calendar-slot',
							),
						),
					),
					'#states_selector' => '.drts-calendar-slot-monthly',
					'#class'           => 'drts-calendar-slot-monthly',
					'#weight'          => 12,
					'#children'        => array(
						0 => array(
							'pattern'    => array(
								'#type'          => 'select',
								'#title'         => __( 'Repeat pattern', 'directories-pro' ),
								'#options'       => array(
									'bymonthday' => __( 'By date', 'directories-pro' ),
									'byday'      => __( 'By weekday', 'directories-pro' ),
								),
								'#horizontal'    => true,
								'#default_value' => $data['#default_value']['monthly']['pattern'] ?? 'bymonthday',
								'#class'         => 'drts-calendar-slot-monthly-pattern',
							),
							'bymonthday' => array(
								'#type'            => 'select',
								'#field_prefix'    => __( 'Day of month', 'directories-pro' ),
								'#options'         => array_combine( range( 1, 31 ), range( 1, 31 ) ) + array( -1 => __( 'Last day', 'directories-pro' ) ),
								'#horizontal'      => true,
								'#default_value'   => $data['#default_value']['monthly']['bymonthday'] ?? null,
								'#states'          => array(
									'visible' => array(
										'.drts-calendar-slot-monthly-pattern select' => array(
											'value'     => 'bymonthday',
											'container' => '.drts-form-type-calendar-slot',
										),
									),
								),
								'#class'           => 'drts-calendar-slot-monthly-bymonthday',
								'#states_selector' => '.drts-calendar-slot-monthly-bymonthday',
							),
							'byday'      => array(
								'#type'            => 'fieldset',
								'#states'          => array(
									'visible' => array(
										'.drts-calendar-slot-monthly-pattern select' => array(
											'value'     => 'byday',
											'container' => '.drts-form-type-calendar-slot',
										),
									),
								),
								'#class'           => 'drts-calendar-slot-monthly-byday',
								'#states_selector' => '.drts-calendar-slot-monthly-byday',
								'#group'           => true,
								'#row'             => true,
								'#horizontal'      => true,
								'#title'           => ' ',
								'#children'        => array(
									0 => array(
										'week' => array(
											'#type'     => 'fieldset',
											'#row'      => true,
											'#children' => array(
												0 => array(
													'day_pos' => array(
														'#type' => 'select',
														'#options' => array(
															1 => __( 'First', 'directories-pro' ),
															2 => __( 'Second', 'directories-pro' ),
															3 => __( 'Third', 'directories-pro' ),
															4 => __( 'Fourth', 'directories-pro' ),
															-1 => __( 'Last', 'directories-pro' ),
														),
														'#default_value' => $data['#default_value']['monthly']['byday']['day_pos'] ?? null,
														'#col' => 4,
													),
													'day' => array(
														'#type' => 'select',
														'#options' => $this->_application->System_Days(),
														'#default_value' => $data['#default_value']['monthly']['byday']['day'] ?? null,
														'#col' => 8,
													),
												),
											),
										),
									),
								),
							),
						),
					),
				),
				'end_repeat'    => array(
					'#type'            => 'fieldset',
					'#group'           => true,
					'#states'          => array(
						'invisible' => array(
							'.drts-calendar-slot-repeat select' => array(
								'value'     => '',
								'container' => '.drts-form-type-calendar-slot',
							),
						),
					),
					'#class'           => 'drts-calendar-slot-end-repeat',
					'#states_selector' => '.drts-calendar-slot-end-repeat',
					'#weight'          => 14,
					'#children'        => array(
						0 => array(
							'type'  => array(
								'#type'          => 'select',
								'#title'         => __( 'Repeat ends', 'directories-pro' ),
								'#options'       => array(
									'after' => __( 'After number of occurrences', 'directories-pro' ),
									'on'    => __( 'On date', 'directories-pro' ),
								),
								'#horizontal'    => true,
								'#default_value' => $data['#default_value']['end_repeat']['type'] ?? null,
								'#class'         => 'drts-calendar-slot-end-repeat-type',
							),
							'after' => array(
								'#type'            => 'slider',
								'#field_suffix'    => _x( 'occurrences', 'X occurrences', 'directories-pro' ),
								'#min_value'       => 1,
								'#max_value'       => 100,
								'#horizontal'      => true,
								'#default_value'   => $data['#default_value']['end_repeat']['after'] ?? 10,
								'#states'          => array(
									'visible' => array(
										'.drts-calendar-slot-end-repeat-type select' => array(
											'value'     => 'after',
											'container' => '.drts-form-type-calendar-slot',
										),
									),
								),
								'#class'           => 'drts-calendar-slot-end-repeat-after',
								'#states_selector' => '.drts-calendar-slot-end-repeat-after',
							),
							'on'    => array(
								'#type'            => 'datepicker',
								'#disable_time'    => true,
								'#horizontal'      => true,
								'#default_value'   => $data['#default_value']['end_repeat']['on'] ?? null,
								'#states'          => array(
									'visible' => array(
										'.drts-calendar-slot-end-repeat-type select' => array(
											'value'     => 'on',
											'container' => '.drts-form-type-calendar-slot',
										),
									),
								),
								'#class'           => 'drts-calendar-slot-end-repeat-on',
								'#states_selector' => '.drts-calendar-slot-end-repeat-on',
								'#empty_value'     => '',
							),
						),
					),
				),
				'exclude_dates' => array(
					'#type'            => 'datepicker',
					'#disable_time'    => true,
					'#horizontal'      => true,
					'#default_value'   => $data['#default_value']['exclude_dates'] ?? null,
					'#title'           => __( 'Exclude dates', 'directories-pro' ),
					'#multiple'        => true,
					'#class'           => 'drts-calendar-slot-exclude-dates',
					'#states_selector' => '.drts-calendar-slot-exclude-dates',
					'#states'          => array(
						'invisible' => array(
							'.drts-calendar-slot-repeat select' => array(
								'value'     => '',
								'container' => '.drts-form-type-calendar-slot',
							),
						),
					),
					'#empty_value'     => '',
					'#weight'          => 16,
				),
			);
		}
		if ( ! empty( $data['#default_value']['slot_id'] ) ) {
			$data['#children'][0]['slot_id'] = array(
				'#type'          => 'hidden',
				'#default_value' => $data['#default_value']['slot_id'],
			);
		}

		$data['#children'][0]['data'] = array(
			'#type'             => 'fieldset',
			'#children'         => array( 0 => array() ),
			'#weight'           => 50,
			'#element_validate' => array(
				function ( Form $form, &$value, $element ) {
					if ( ! empty( $value['booking_allow'] )
					&& empty( $value['booking_max_spaces'] )
						) {
						$form->setError( __( 'Please specify maximum spaces for booking.', 'directories-pro' ), $element['#name'] . '[booking_max_spaces]' );
					}
				},
			),
		);
		if ( ! empty( $data['#enable_booking'] ) ) {
			$data['#children'][0]['data']['#children'][0]['booking_allow']      = array(
				'#type'          => 'checkbox',
				'#title'         => __( 'Allow booking', 'directories-pro' ),
				'#default_value' => $data['#default_value']['data']['booking_allow'] ?? true,
				'#horizontal'    => true,
				'#weight'        => 50,
				'#class'         => 'drts-calendar-slot-booking-allow',
			);
			$data['#children'][0]['data']['#children'][0]['booking_max_spaces'] = array(
				'#type'            => 'number',
				'#min_value'       => 1,
				'#max_value'       => isset( $data['#booking_allow_max'] ) ? ( empty( $data['#booking_allow_max'] ) ? null : $data['#booking_allow_max'] ) : 100,
				'#field_prefix'    => __( 'Maximum spaces', 'directories-pro' ),
				'#default_value'   => isset( $data['#default_value']['data']['booking_max_spaces'] ) && is_numeric( $data['#default_value']['data']['booking_max_spaces'] ) ? $data['#default_value']['data']['booking_max_spaces'] : 10,
				'#horizontal'      => true,
				'#weight'          => 51,
				'#states'          => array(
					'visible' => array(
						'.drts-calendar-slot-booking-allow input[type="checkbox"]' => array(
							'type'      => 'checked',
							'value'     => true,
							'container' => '.drts-form-type-calendar-slot',
						),
					),
				),
				'#integer'         => true,
				'#class'           => 'drts-form-type-calendar-slot-booking-max-spaces',
				'#states_selector' => '.drts-form-type-calendar-slot-booking-max-spaces',
			);
		}

		$form->settings['#pre_render'][ __CLASS__ ] = array( $this, 'preRenderCallback' );

		parent::formFieldInit( $name, $data, $form );
	}

	protected function _getTimeOptions( $intervalMin = 15 ) {
		$options  = array();
		$interval = $intervalMin * 60;
		for ( $seconds = 0; $seconds < 24 * 60 * 60; $seconds += $interval ) {
			$hours               = floor( $seconds / 3600 );
			$minutes             = floor( ( $seconds % 3600 ) / 60 );
			$options[ $seconds ] = sprintf( '%02d:%02d', $hours, $minutes );
		}
		return $options;
	}

	public function formFieldSubmit( &$value, array &$data, Form $form ) {
		parent::formFieldSubmit( $value, $data, $form );

		if ( empty( $value['start']['date'] ) ) {
			if ( ! empty( $data['#enable_title'] )
				&& isset( $value['title'] )
				&& strlen( $value['title'] )
			) {
				// Show error only if title is specified
				$form->setError( 'Start date is required.', $data['#name'] . '[start][date]' );
			}
			return;
		}
		if ( $all_day = ! empty( $value['start']['all_day'] ) ) {
			$value['time']['start_time'] = 0;
		} elseif ( ! isset( $value['time']['start_time'] )
			|| ! is_numeric( $value['time']['start_time'] )
		) {
			$form->setError( 'Start time is required.', $data['#name'] . '[time][start_time]' );
			return;
		}

		$start_date = $value['start']['date'];
		$start_time = $value['time']['start_time'] % 86400;

		$repeat = empty( $data['#enable_recurring'] ) ? '' : ( $value['repeat'] ?? '' );
		if ( $repeat !== '' ) {
			// Get dates excluded from repeat
			if ( empty( $value['exclude_dates'] )
				|| ! is_array( $value['exclude_dates'] )
				|| ( ! $exclude_dates = array_filter( array_map( 'intval', $value['exclude_dates'] ) ) )
			) {
				$exclude_dates = null;
			}
			// Get repeat end date
			$repeat_end_date = $repeat_end_after = null;
			$end_repeat_type = $value['end_repeat']['type'] ?? null;
			switch ( $end_repeat_type ) {
				case 'on':
					if ( empty( $value['end_repeat']['on'] ) ) {
						$form->setError( 'Please specify a valid date for repeat end.', $data['#name'] . '[end_repeat][on]' );
						return;
					}
					$repeat_end_date = $value['end_repeat']['on'];
					if ( $repeat_end_date < $start_date ) {
						$form->setError( 'Repeat end date cannot be earlier than start date.', $data['#name'] . '[end_repeat][on]' );
						return;
					}
					break;
				case 'after':
				default:
					if ( empty( $value['end_repeat']['after'] ) || ! is_numeric( $value['end_repeat']['after'] ) || $value['end_repeat']['after'] < 1 ) {
						$form->setError( 'Please specify a valid number of occurrences for repeat end.', $data['#name'] . '[end_repeat][after]' );
						return;
					}
					$repeat_end_after = (int) $value['end_repeat']['after'];
					break;
			}
			switch ( $repeat ) {
				case 'daily':
					break;
				case 'weekly':
					if ( empty( $value['weekly']['days'] )
						|| ! is_array( $value['weekly']['days'] )
						|| ( ! $value['weekly']['days'] = array_filter( array_map( 'intval', $value['weekly']['days'] ) ) )
					) {
						$form->setError( 'Please select at least one day of the week for weekly repeats.', $data['#name'] . '[weekly][days]' );
						return;
					}
					break;
				case 'monthly':
					if ( empty( $value['monthly']['pattern'] ) ) {
						$form->setError( 'Please select a repeat pattern for monthly repeats.', $data['#name'] . '[monthly][pattern]' );
						return;
					}
					if ( $value['monthly']['pattern'] === 'bymonthday' ) {
						if ( empty( $value['monthly']['bymonthday'] )
							|| ! is_numeric( $value['monthly']['bymonthday'] )
							|| ( ! $value['monthly']['bymonthday'] = intval( $value['monthly']['bymonthday'] ) )
							|| $value['monthly']['bymonthday'] < -1
							|| $value['monthly']['bymonthday'] === 0
							|| $value['monthly']['bymonthday'] > 31
						) {
							$form->setError( 'Please select a valid day of the month for monthly repeats.', $data['#name'] . '[monthly][bymonthday]' );
							return;
						}
					} elseif ( $value['monthly']['pattern'] === 'byday' ) {
						if ( empty( $value['monthly']['byday']['week']['day_pos'] )
							|| empty( $value['monthly']['byday']['week']['day'] )
							|| ! is_numeric( $value['monthly']['byday']['week']['day_pos'] )
							|| ! is_numeric( $value['monthly']['byday']['week']['day'] )
							|| ! in_array( $value['monthly']['byday']['week']['day_pos'] = intval( $value['monthly']['byday']['week']['day_pos'] ), array( 1, 2, 3, 4, -1 ), true )
							|| ! in_array( $value['monthly']['byday']['week']['day'] = intval( $value['monthly']['byday']['week']['day'] ), array( 1, 2, 3, 4, 5, 6, 7 ), true )
						) {
							$form->setError( 'Please select a valid week and weekday for monthly repeats.', $data['#name'] . '[monthly][byday]' );
							return;
						}
					} else {
						$form->setError( 'Please select a valid repeat pattern for monthly repeats.', $data['#name'] . '[monthly][pattern]' );
						return;
					}
					break;
				case 'yearly':
					break;
				default:
					$form->setError( 'Invalid repeat type.', $data['#name'] . '[repeat]' );
					return;
			}
		}

		if ( ! empty( $value['start']['all_day'] ) ) {
			$end_time = 86399; // 23:59:59
		} elseif ( ! isset( $value['time']['end_time'] )
			|| ! is_numeric( $value['time']['end_time'] )
		) {
			if ( ! empty( $data['#require_end_time'] ) ) {
				$form->setError( 'End time is required.', $data['#name'] . '[time][end_time]' );
				return;
			}
			$end_time = 86399; // 23:59:59
		} else {
			$end_time = $value['time']['end_time'] % 86400; // seconds since midnight
		}

		$title   = empty( $data['#enable_title'] ) ? '' : ( $value['title'] ?? '' );
		$slot_id = $value['slot_id'] ?? null;

		$data = $value['data'] ?? array();

		if ( $repeat === '' ) {
			$value = array(
				'title'      => $title,
				'start_date' => $start_date,
				'start_time' => $start_time,
				'end_time'   => $end_time,
				'repeat'     => false,
				'slot_id'    => $slot_id,
				'data'       => $data,
				'all_day'    => $all_day,
			);
			return;
		}

		switch ( $repeat ) {
			case 'weekly':
				$value = array(
					'days' => $value['weekly']['days'],
				);
				break;
			case 'monthly':
				$value = array(
					'monthday' => $value['monthly']['pattern'] === 'bymonthday' ? $value['monthly']['bymonthday'] : null,
					'day_pos'  => $value['monthly']['pattern'] === 'byday' ? $value['monthly']['byday']['number'] : null,
					'day'      => $value['monthly']['pattern'] === 'byday' ? $value['monthly']['byday']['day'] : null,
				);
				break;
			default:
				$value = array();
				break;
		}
		$value += array(
			'title'            => $title,
			'start_date'       => $start_date,
			'start_time'       => $start_time,
			'end_time'         => $end_time,
			'repeat'           => $repeat,
			'repeat_end_date'  => $repeat_end_date ?? null,
			'repeat_end_after' => $repeat_end_after ?? null,
			'exclude_dates'    => $exclude_dates,
			'slot_id'          => $slot_id,
			'data'             => $data,
			'all_day'          => $all_day,
		);
	}

	public function preRenderCallback( Form $form ) {
		$this->_application->getPlatform()
			->addJsFile( 'calendar-slot-field.min.js', 'drts-calendar-slot-field', 'drts', 'directories-pro' );
	}
}
