<?php
namespace SabaiApps\Directories\Component\Form\Field;

use SabaiApps\Directories\Component\Form\Form;

/**
 * TimePickerField provides a time picker with optional day selection.
 * Supports all-day, start/end time, and validation for required fields.
 */
class TimePickerField extends AbstractField {

	// Constants for special day selection options
	const WEEKDAYS = 8, WEEKEND = 9, ALL_WEEK = 10, NO_SUNDAY = 11;

	/**
	 * Initializes the TimePicker field with default values and pre-render callback.
	 *
	 * @param string $name
	 * @param array  $data
	 * @param Form   $form
	 */
	public function formFieldInit( $name, array &$data, Form $form ) {
		if ( ! isset( $data['#id'] ) ) {
			$data['#id'] = $form->getFieldId( $name );
		}
		if ( ! isset( $data['#default_value'] ) ) {
			if ( ! empty( $data['#current_time_selected'] ) ) {
				$current_time           = $this->_application->getPlatform()->getSystemToSiteTime( time() );
				$data['#default_value'] = array(
					'start' => $current_time,
					'end'   => null,
					'day'   => date( 'w', $current_time ),
				);
			}
		} else {
			// Normalize default values for day, start, and end
			foreach ( array( 'day', 'start', 'end' ) as $key ) {
				if ( isset( $data['#default_value'][ $key ] )
					&& is_numeric( $data['#default_value'][ $key ] )
				) {
					$data['#default_value'][ $key ] = intval( $data['#default_value'][ $key ] );
				} else {
					$data['#default_value'][ $key ] = null;
				}
			}
		}

		// Register pre-render callback with day requirement flag
		$form->settings['#pre_render'][ __CLASS__ ] = array( array( $this, 'preRenderCallback' ), array( empty( $data['#disable_day'] ) && empty( $data['#allow_empty_day'] ) ) );
	}

	/**
	 * Handles value processing and validation for the TimePicker field on submit.
	 *
	 * @param mixed $value
	 * @param array $data
	 * @param Form  $form
	 */
	public function formFieldSubmit( &$value, array &$data, Form $form ) {
		if ( ! is_array( $value ) ) {
			if ( $form->isFieldRequired( $data ) ) {
				$form->setError( isset( $data['#required_error_message'] ) ? $data['#required_error_message'] : __( 'Please pick a time.', 'directories-pro' ), $data );
			}
			$value = null;
			return;
		}

		// Handle all-day selection
		if ( ( $all_day_options = $this->_getAllDayOptions( $data ) )
			&& ! empty( $value['all_day'] )
			&& in_array( $value['all_day'], array_keys( $all_day_options ) )
		) {
			if ( empty( $data['#disable_day'] ) ) {
				if ( empty( $data['#allow_empty_day'] )
					&& empty( $value['day'] )
				) {
					$form->setError( __( 'Please select a day of week.', 'directories-pro' ), $data );
					return;
				}
			}
			$value['start'] = 0;
			$value['end']   = $value['all_day'] == 1 ? 86400 : 0;
			return;
		}
		$value['all_day'] = '';

		// Validate start time
		if ( ! isset( $value['start'] )
			|| ! strlen( $value['start'] = trim( $value['start'] ) )
		) {
			if ( $form->isFieldRequired( $data )
				|| ( empty( $data['#disable_end'] ) && isset( $value['end'] ) && strlen( $value['end'] ) )  // end time selected
			) {
				$form->setError( isset( $data['#required_error_message'] ) ? $data['#required_error_message'] : __( 'Please pick a time.', 'directories-pro' ), $data );
				return;
			}
			// no start/end value
			if ( empty( $data['#disable_day'] )
				&& ! empty( $value['day'] )
			) { // day selected
				if ( empty( $data['#allow_day_only'] ) ) {
					$form->setError( isset( $data['#required_error_message'] ) ? $data['#required_error_message'] : __( 'Please pick a time.', 'directories-pro' ), $data );
				}
				return;
			}
			// no start/end/day value
			$value = null;
		} else {
			// Validate day selection if required
			if ( empty( $data['#disable_day'] ) ) {
				if ( empty( $data['#allow_empty_day'] )
					&& empty( $value['day'] )
				) {
					$form->setError( __( 'Please select a day of week.', 'directories-pro' ), $data );
					return;
				}
			}
			// Validate end time if required
			if ( empty( $data['#disable_end'] )
				&& ( ! isset( $value['end'] ) || ! strlen( $value['end'] = trim( $value['end'] ) ) )
			) {
				$form->setError( __( 'Please select an end time.', 'directories-pro' ), $data );
			}
		}
	}

	/**
	 * Renders the TimePicker field as a group of select elements for day, start, end, and all-day.
	 *
	 * @param array $data
	 * @param Form  $form
	 */
	public function formFieldRender( array &$data, Form $form ) {
		$gutter      = isset( $data['#gutter_size'] ) ? ' drts-gutter-' . $data['#gutter_size'] : '';
		$html        = array( '<div class="drts-row' . $gutter . '">' );
		$placeholder = isset( $data['#attributes']['placeholder'] ) ? $data['#attributes']['placeholder'] : ( isset( $data['#placeholder'] ) ? $data['#placeholder'] : null );
		if ( empty( $data['#disable_day'] ) ) {
			if ( empty( $data['#disable_end'] ) ) {
				if ( $all_day_field = $this->_getAllDayField( $data ) ) {
					$html[] = sprintf(
						'<div class="drts-form-timepicker-day drts-col-sm-6 drts-col-md-3 drts-sm-mb">%s</div>'
						. '<div class="drts-form-timepicker-all_day drts-col-sm-6 drts-col-md-3 drts-sm-mb">%s</div>'
						. '<div class="drts-form-timepicker-start drts-col-sm-6 drts-col-md-3">%s</div>'
						. '<div class="drts-form-timepicker-end drts-col-sm-6 drts-col-md-3">%s</div>',
						$this->_getDays( $data ),
						$all_day_field,
						$this->_getTimeField( $data, 'start', $placeholder ),
						$this->_getTimeField( $data, 'end', isset( $data['#placeholder_end'] ) ? $data['#placeholder_end'] : $placeholder )
					);
				} else {
					$html[] = sprintf(
						'<div class="drts-form-timepicker-day drts-col-md-6 drts-sm-mb">%s</div>'
						. '<div class="drts-form-timepicker-start drts-col-sm-6 drts-col-md-3">%s</div>'
						. '<div class="drts-form-timepicker-end drts-col-sm-6 drts-col-md-3">%s</div>',
						$this->_getDays( $data ),
						$this->_getTimeField( $data, 'start', $placeholder ),
						$this->_getTimeField( $data, 'end', isset( $data['#placeholder_end'] ) ? $data['#placeholder_end'] : $placeholder )
					);
				}
			} elseif ( $all_day_field = $this->_getAllDayField( $data ) ) {
					$html[] = sprintf(
						'<div class="drts-form-timepicker-day drts-col-sm-6 drts-col-md-3 drts-sm-mb">%s</div>'
						. '<div class="drts-form-timepicker-all_day drts-col-sm-6 drts-col-md-3 drts-sm-mb">%s</div>'
						. '<div class="drts-form-timepicker-start drts-col-sm-6">%s</div>',
						$this->_getDays( $data ),
						$all_day_field,
						$this->_getTimeField( $data, 'start', $placeholder )
					);
			} else {
				$html[] = sprintf(
					'<div class="drts-form-timepicker-day drts-col-sm-6">%s</div>'
					. '<div class="drts-form-timepicker-start drts-col-sm-6">%s</div>',
					$this->_getDays( $data ),
					$this->_getTimeField( $data, 'start', $placeholder )
				);
			}
		} elseif ( empty( $data['#disable_end'] ) ) {
			if ( ! empty( $data['#allow_empty_day'] )
					&& ( $all_day_field = $this->_getAllDayField( $data ) )
				) {
				$html[] = sprintf(
					'<div class="drts-form-timepicker-all_day drts-col-md-6 drts-sm-mb">%s</div>'
					. '<div class="drts-form-timepicker-start drts-col-sm-6 drts-col-md-3">%s</div>'
					. '<div class="drts-form-timepicker-end drts-col-sm-6 drts-col-md-3">%s</div>',
					$all_day_field,
					$this->_getTimeField( $data, 'start', $placeholder ),
					$this->_getTimeField( $data, 'end', isset( $data['#placeholder_end'] ) ? $data['#placeholder_end'] : $placeholder )
				);
			} else {
				$html[] = sprintf(
					'<div class="drts-form-timepicker-start drts-col-sm-6">%s</div>'
					. '<div class="drts-form-timepicker-end drts-col-sm-6">%s</div>',
					$this->_getTimeField( $data, 'start', $placeholder ),
					$this->_getTimeField( $data, 'end', isset( $data['#placeholder_end'] ) ? $data['#placeholder_end'] : $placeholder )
				);
			}
		} elseif ( ! empty( $data['#allow_empty_day'] )
					&& ( $all_day_field = $this->_getAllDayField( $data ) )
				) {

				$html[] = sprintf(
					'<div class="drts-form-timepicker-all_day drts-col-md-6">%s</div>'
						. '<div class="drts-form-timepicker-start drts-col-md-6">%s</div>',
					$all_day_field,
					$this->_getTimeField( $data, 'start', $placeholder )
				);
		} else {
			$html[] = sprintf(
				'<div class="drts-form-timepicker-start drts-col-md-6">%s</div>',
				$this->_getTimeField( $data, 'start', $placeholder )
			);
		}
		$html[] = '</div>';
		$this->_render( implode( PHP_EOL, $html ), $data, $form );
	}

	/**
	 * Returns the available options for the all-day dropdown.
	 *
	 * @param array $data
	 * @return array|null
	 */
	protected function _getAllDayOptions( array $data ) {
		if ( empty( $data['#all_day_options'] ) ) {
			return;
		}

		$options = array(
			'' => __( 'Enter hours', 'directories-pro' ),
			1  => __( 'All day', 'directories-pro' ),
		);
		if ( is_array( $data['#all_day_options'] ) ) {
			foreach ( $data['#all_day_options'] as $value => $label ) {
				$options[ $value ] = $label;
			}
		}
		return $options;
	}

	/**
	 * Returns the HTML for the all-day select field.
	 *
	 * @param array $data
	 * @return string|null
	 */
	protected function _getAllDayField( array $data ) {
		if ( ! $options = $this->_getAllDayOptions( $data ) ) {
			return;
		}

		$ret = array(
			sprintf(
				'<select class="%sform-select" name="%s[all_day]"%s>',
				DRTS_BS_PREFIX,
				$data['#name'],
				$data['#disabled'] ? ' disabled="disabled"' : ''
			),
		);
		foreach ( $options as $key => $label ) {
			$ret[] = sprintf(
				'<option value="%s"%s>%s</option>',
				$key,
				isset( $data['#default_value']['all_day'] ) && $data['#default_value']['all_day'] == $key ? ' selected="selected"' : '',
				$this->_application->H( $label )
			);
		}
		$ret[] = '</select>';

		return implode( PHP_EOL, $ret );
	}

	/**
	 * Returns the HTML for the day select field.
	 *
	 * @param array $data
	 * @return string
	 */
	protected function _getDays( array $data ) {
		$ret     = array(
			sprintf(
				'<select class="%sform-select" name="%s[day]"%s%s>',
				DRTS_BS_PREFIX,
				$data['#name'],
				$data['#disabled'] ? ' disabled="disabled"' : '',
				empty( $data['#allow_empty_day'] ) ? '' : ' data-allow-empty="1"'
			),
		);
		$options = array( '' => __( '— Select —', 'directories-pro' ) ) + $this->_application->System_Days();
		if ( ! empty( $data['#enable_day_bulk'] ) ) {
			$options += array(
				self::WEEKDAYS  => $options[1] . ' - ' . $options[5],
				self::NO_SUNDAY => $options[1] . ' - ' . $options[6],
				self::WEEKEND   => $options[6] . ' - ' . $options[7],
				self::ALL_WEEK  => $this->_application->System_Days_allWeekStr(),
			);
		}
		foreach ( $options as $key => $day ) {
			$ret[] = sprintf(
				'<option value="%s"%s>%s</option>',
				$key,
				isset( $data['#default_value']['day'] ) && $data['#default_value']['day'] === $key ? ' selected="selected"' : '',
				$this->_application->H( $day )
			);
		}
		$ret[] = '</select>';

		return implode( PHP_EOL, $ret );
	}

	/**
	 * Returns the HTML for the time select field (start or end).
	 *
	 * @param array       $data
	 * @param string      $name
	 * @param string|null $placeholder
	 * @return string
	 */
	protected function _getTimeField( array $data, $name, $placeholder = null ) {
		$time_step      = isset( $data['#time_step'] ) ? (int) $data['#time_step'] : 15;
		$time_range_min = $time_range_max = null;
		if ( isset( $data['#time_range_min'] )
			&& is_int( $data['#time_range_min'] )
			&& $data['#time_range_min'] < 86400
		) {
			$time_range_min = $data['#time_range_min'];
			$time_range_max = isset( $data['#time_range_max'] ) && is_int( $data['#time_range_max'] ) && $data['#time_range_max'] <= 86400 ? $data['#time_range_max'] : 86400;
			if ( $time_range_min % $time_step === 0 ) {
				--$time_range_min;
			}
			if ( $time_range_max % $time_step === 0 ) {
				++$time_range_max;
			}
		}
		$options = $this->_application->System_Util_timeOptions(
			isset( $data['#default_value'][ $name ] ) ? $data['#default_value'][ $name ] : null,
			array(
				'format'      => isset( $data['#time_format'] ) ? $data['#time_format'] : null,
				'step'        => $time_step,
				'html'        => true,
				'placeholder' => isset( $placeholder ) ? $placeholder : '--',
				'skip'        => array( $time_range_min, $time_range_max ),
			)
		);
		return sprintf(
			'<select class="%1$sform-select" name="%2$s[%3$s]"%4$s>%5$s</select>',
			DRTS_BS_PREFIX,
			$this->_application->H( $data['#name'] ),
			$name,
			$data['#disabled'] ? ' disabled="disabled"' : '',
			implode( PHP_EOL, $options )
		);
	}

	/**
	 * Pre-render callback to load scripts and initialize the time picker.
	 *
	 * @param Form $form
	 * @param bool $requireDay
	 */
	public function preRenderCallback( Form $form, $requireDay ) {
		$this->_application->Form_Scripts_time();

		$form->settings['#js_ready'][] = sprintf(
			'(function() {
    $("#%s").find(".drts-form-type-timepicker").each(function(){
        DRTS.Form.field.timepicker($(this), {requireDay: %s}); 
    });
})();',
			$form->settings['#id'],
			empty( $requireDay ) ? 'false' : 'true'
		);
	}
}
