<?php
/**
 * Elementor Upcoming Appointments Widget.
 *
 * Elementor widget that inserts a coverflow-style carousel into the page.
 *
 * @since 1.0.0
 */

class SSA_Elementor_Booking_Widget extends \Elementor\Widget_Base {

	/**
	 * Get widget name.
	 *
	 * Retrieve coverflow carousel widget name.
	 *
	 * @since 1.0.0
	 * @access public
	 *
	 * @return string Widget name.
	 */
	public function get_name() {
		return 'ssa-booking';
	}

	/**
	 * Get widget title.
	 *
	 * Retrieve Upcoming Appointments widget title.
	 *
	 * @since 1.0.0
	 * @access public
	 *
	 * @return string Widget title.
	 */
	public function get_title() {
		return __( 'Schedule an Appointment', 'simply-schedule-appointments' );
	}

	/**
	 * Get widget icon.
	 *
	 * Retrieve Upcoming Appointments widget icon.
	 *
	 * @since 1.0.0
	 * @access public
	 *
	 * @return string Widget icon.
	 */
	public function get_icon() {
		return 'eicon-calendar';
	}

	/**
	 * Get widget keywords.
	 *
	 * Retrieve the list of keywords the widget belongs to.
	 *
	 * @since 2.1.0
	 * @access public
	 *
	 * @return array Widget keywords.
	 */
	public function get_keywords() {
		return [ 'ssa', 'schedule', 'calendar', 'appointments', 'simply', 'booking' ];
	}

	/**
	 * Get widget categories.
	 *
	 * Retrieve the list of categories the Upcoming Appointments widget belongs to.
	 *
	 * @since 1.0.0
	 * @access public
	 *
	 * @return array Widget categories.
	 */
	public function get_categories() {
		return [ 'general' ];
	}

	/**
	 * Retrieve the list of scripts the Upcoming Appointments widget depended on.
	 *
	 * Used to set scripts dependencies required to run the widget.
	 *
	 * @since 1.3.0
	 * @access public
	 *
	 * @return array Widget scripts dependencies.
	 */
	public function get_script_depends() {
		return [];
	}

	/**
	 * Retrieve the list of styles the Upcoming Appointments widget depended on.
	 *
	 * Used to set style dependencies required to run the widget.
	 *
	 * @since 1.3.0
	 * @access public
	 *
	 * @return array Widget styles dependencies.
	 */
	public function get_style_depends() {
		return [];
	}

	/**
	 * Register Upcoming Appointments widget controls.
	 *
	 * Adds different input fields to allow the user to change and customize the widget settings.
	 *
	 * @since 1.0.0
	 * @access protected
	 */
	protected function register_controls() {
		$this->start_controls_section(
			'block_section',
			[
				'label' => __( 'Block Description', 'simply-schedule-appointments' ),
				'tab'   => \Elementor\Controls_Manager::TAB_CONTENT,
			]
		);

		$icon_url = $this->get_icon();

		$this->add_control(
			'title',
			[
				'raw' => '<div><i class="' . esc_attr($icon_url) . '"></i><span> Appointment Booking Form</span></div>',
				'type' => \Elementor\Controls_Manager::RAW_HTML,
			]
		);

		$this->add_control(
			'description',
			[
				'raw' => '<p>' .esc_html__('Displays an Appointment Booking Form. You can customize the appointment type and styles.', 'simply-schedule-appointments') . '</p>',
				'type' => \Elementor\Controls_Manager::RAW_HTML,
			]
		);

		$this->end_controls_section();

		$this->start_controls_section(
			'section_ssa_booking',
			[
				'label' => __( 'Select Appointment Types', 'simply-schedule-appointments' ),
			]
		);

		$appointment_type_labels = ssa()->appointment_type_label_model->query();
		$ssa_appointment_label_key_values = wp_list_pluck( $appointment_type_labels, 'name', 'id' );
		$ssa_appointment_label_key_values[''] = 'All';
		$ssa_appointment_label_key_values = array_reverse( $ssa_appointment_label_key_values, true );

		$appointment_types = ssa()->appointment_type_model->query( array(
			'number' => -1,
			'status' => 'publish',
		) );

		$filter_options = [
			'types' => __( 'Appointment types', 'simply-schedule-appointments' ),
			'label' => __( 'Label', 'simply-schedule-appointments' ),
		];

		$default_filter = key($filter_options);
		$map_appointment_type_ids_to_labels = wp_list_pluck( $appointment_types, 'title', 'slug' );
		$map_appointment_type_ids_to_labels = array_reverse( $map_appointment_type_ids_to_labels, true );
		$map_appointment_type_ids_to_labels[''] = 'All';
		$map_appointment_type_ids_to_labels = array_reverse( $map_appointment_type_ids_to_labels, true );

		$this->add_control(
			'appointment_types_filter',
			[
				'label' => __( 'FILTER BY', 'simply-schedule-appointments' ),
				'type' => \Elementor\Controls_Manager::SELECT,
				'default' => $default_filter,
				'options' => $filter_options,
				'classes' => 'ssa-booking-block',
			]
		);

		$this->add_control(
			'label',
			[
				'label' => __( 'Labels', 'simply-schedule-appointments' ),
				'type' => \Elementor\Controls_Manager::SELECT,
				'default' => '',
				'options' => $ssa_appointment_label_key_values,
				'condition' => [
					'appointment_types_filter' => 'label',
				],
			]
		);

		$this->add_control(
			'header',
			[
				'raw' => '<h4>Select Appointment Types:</h4>',
				'type' => \Elementor\Controls_Manager::RAW_HTML,
				'separator' => 'after',
				'condition' => [
					'appointment_types' => 'types',
				],
			]
		);

		$this->add_control(
			'appointment_type',
			[
				'label' => esc_html__('Appointment Types', 'simply-schedule-appointments'),
				'type' => \Elementor\Controls_Manager::SELECT2,
				'options' => $map_appointment_type_ids_to_labels,
				'label_block' => true,
				'multiple' => true,
				'frontend_available' => true,
				'condition' => [
					'appointment_types_filter' => 'types',
				],
			]
		);

		$this->end_controls_section();

		/* Appointment type view */
		$this->start_controls_section(
			'section_ssa_booking_type_view',
			[
				'label' => __( 'Appointment Types View', 'simply-schedule-appointments' ),
			]
		);

		$filter_types_options = [
			'cardList' => __('List', 'simply-schedule-appointments'),
			'cardGrid' => __('Grid', 'simply-schedule-appointments'),
			'cardColumns' => __('Two Columns', 'simply-schedule-appointments'),
		];

		$default_filter_type = key($filter_types_options);

		$this->add_control(
			'appointment_types_view',
			[
				'label' => __( 'Appointments types view', 'simply-schedule-appointments' ),
				'type' => \Elementor\Controls_Manager::SELECT,
				'default' => $default_filter_type,
				'options' => $filter_types_options,
				'label_block' => true,
				'classes' => 'ssa-booking-block',
			]
		);
		
		$this->end_controls_section();

		/* Booking Flow UI*/	
		if ( ssa_should_render_booking_flow()) {
			$this->start_controls_section(
				'section_ssa_booking_flow',
				[
					'label' => __( 'Booking Flow', 'simply-schedule-appointments' ),
				]
			);

			$filter_flow_options = [
				'appt_type_settings' => __('Use default settings from appointment type', 'simply-schedule-appointments'),
				'expanded' => __('Expanded', 'simply-schedule-appointments'),
				'express' => __('Express', 'simply-schedule-appointments'),
				'first_available' => __('First available', 'simply-schedule-appointments'),
			];

			$default_flow_filter = key($filter_flow_options);

			$this->add_control(
				'booking_layout',
				[
					'label' => esc_html__( 'Main Booking Layout', 'simply-schedule-appointments' ),
					'label_block' => true,
					'frontend_available' => true,
					'type' => \Elementor\Controls_Manager::SELECT,
					'default' => $default_flow_filter,
					'options' => $filter_flow_options,
				]
			);

			$this->add_control(
				'appt_duration',
				[
					'label' => esc_html__( 'Duration', 'simply-schedule-appointments' ),
					'label_block' => false,
					'type' => \Elementor\Controls_Manager::NUMBER,
					'min' => 1,
					'default' => 1,
					'condition' => [
						'booking_layout' => 'first_available',
					]
				]
			);

			$filter_duration_units = [
				'minutes' => __('Minutes', 'simply-schedule-appointments'),
				'hours' => __('Hours', 'simply-schedule-appointments'),
				'days' => __('Days', 'simply-schedule-appointments'),
				'weeks' => __('Weeks', 'simply-schedule-appointments'),
			];

			$default_duration_unit = key($filter_duration_units);

			$this->add_control(
				'duration_unit',
				[
					'label' => esc_html__( 'Duration Unit', 'simply-schedule-appointments' ),
					'label_block' => true,
					'type' => \Elementor\Controls_Manager::SELECT,
					'default' => $default_duration_unit,
					'options' => $filter_duration_units,
					'condition' => [
						'booking_layout' => 'first_available',
					],
				]
			);	

			$filter_fallback_options = [
				'expanded' => __('Expanded', 'simply-schedule-appointments'),
				'express' => __('Express', 'simply-schedule-appointments'),
			];

			$default_fallback_filter = key($filter_fallback_options);

			$this->add_control(
				'fallback_options',
				[
					'label' => esc_html__( 'Fallback Flow', 'simply-schedule-appointments' ),
					'label_block' => true,
					'type' => \Elementor\Controls_Manager::SELECT,
					'default' => $default_fallback_filter,
					'options' => $filter_fallback_options,
					'condition' => [
						'booking_layout' => 'first_available',
					],
				]
			);

			$this->add_control(
				'view_type',
				[
					'label' => esc_html__( 'View Type', 'simply-schedule-appointments' ),
					'type' => \Elementor\Controls_Manager::CHOOSE,
					'frontend_available' => true,
					'options' => [
						'left' => [
							'title' => esc_html__( 'Date View', 'simply-schedule-appointments' ),
							'icon' => 'eicon-calendar',
						],
						'right' => [
							'title' => esc_html__( 'Time View', 'simply-schedule-appointments' ),
							'icon' => 'eicon-clock-o',
						],
					],
					'default' => 'left',
					'toggle' => true,
					'selectors_dictionary' => [
						'left' => is_rtl() ? 'end' : 'start',
						'right' => is_rtl() ? 'start' : 'end',
					],
					'conditions' => [
						'relation' => 'and',
						'terms' => [
							[
								'name' => 'booking_layout',
								'operator' => '!==',
								'value' => 'express',
							],
							[
								'name' => 'booking_layout',
								'operator' => '!==',
								'value' => 'appt_type_settings',
							],	
						]
					],
				]
			);
					
			$filter_date_options = [
				'week' => __('Weekly', 'simply-schedule-appointments'),
				'month' => __('Monthly', 'simply-schedule-appointments'),
				'only_available' =>__('Only available dates', 'simply-schedule-appointments'),
			];

			$default_date_filter = key($filter_date_options);

			$this->add_control(
				'date_view_options',
				[
					'label' => esc_html__( 'Date View', 'simply-schedule-appointments' ),
					'label_block' => true,
					'type' => \Elementor\Controls_Manager::SELECT,
					'default' => $default_date_filter,
					'options' => $filter_date_options,
					'conditions' => [
						'relation' => 'and',
						'terms' => [
							[
								'name' => 'view_type',
								'operator' => '===',
								'value' => 'left',
							],
							[
								'relation' => 'and',
								'terms' => [
									[
										'name' => 'booking_layout',
										'operator' => '!==',
										'value' => 'express',
									],
									[
										'name' => 'booking_layout',
										'operator' => '!==',
										'value' => 'appt_type_settings',
									],
								],
							],
						],
					],
				]
			);

			$filter_time_options = [
				'time_of_day_columns' => __('Time of day columns', 'simply-schedule-appointments'),
				'single_column' => __('Single column', 'simply-schedule-appointments'),
			];

			$default_time_filter = key($filter_time_options);

			$this->add_control(
				'time_view_options',
				[
					'label' => esc_html__( 'Time View', 'simply-schedule-appointments' ),
					'label_block' => true,
					'type' => \Elementor\Controls_Manager::SELECT,
					'default' => $default_time_filter,
					'options' => $filter_time_options,
					'conditions' => [
						'relation' => 'or',
						'terms' => [
							[
								'name' => 'booking_layout',
								'operator' => '===',
								'value' => 'express',
							],
							[
								'relation' => 'and',
								'terms' => [
									[
										'name' => 'view_type',
										'operator' => '===',
										'value' => 'right',
									],
									[
										'name' => 'booking_layout',
										'operator' => '!==',
										'value' => 'appt_type_settings',
									],
								],
							]
						]
					],
				]
			);

			$this->end_controls_section();
		}

		$this->start_controls_section(
			'section_performance',
			[
				'label' => __( 'Performance', 'simply-schedule-appointments' ),
			]
		);

		$this->add_control(
			'defer',
			[
				'label' => __( 'Defer loading', 'simply-schedule-appointments' ),
				'description' => __( 'Improves page load performance by deferring initialization until visible.', 'simply-schedule-appointments' ),
				'type' => \Elementor\Controls_Manager::SWITCHER,
				'label_on' => __( 'Yes', 'simply-schedule-appointments' ),
				'label_off' => __( 'No', 'simply-schedule-appointments' ),
				'return_value' => 'yes',
				'default' => '',
			]
		);

		$this->end_controls_section();

		$this->start_controls_section(
			'section_style',
			[
				'label' => __( 'Styles', 'elementor' ),
				'tab' => \Elementor\Controls_Manager::TAB_STYLE,
			]
		);

		$this->add_control(
			'accent_color',
			[
				'label'   => __( 'Accent Color', 'simply-schedule-appointments' ),
				'type'    => \Elementor\Controls_Manager::COLOR,
				'alpha'   => false,
			]
		);		

		$this->add_control(
			'background_color',
			[
				'label'   => __( 'Background Color', 'simply-schedule-appointments' ),
				'type'    => \Elementor\Controls_Manager::COLOR,
				'alpha'   => false,
			]
		);		

		$this->add_control(
			'font_family',
			[
				'label'   => __( 'Font Family', 'simply-schedule-appointments' ),
				'type' => \Elementor\Controls_Manager::FONT,
			]
		);		

		$this->add_control(
			'padding',
			[
				'label'   => __( 'Padding', 'simply-schedule-appointments' ),
				'type' => \Elementor\Controls_Manager::SLIDER,
				'size_units' => [ 'px', 'em', 'rem', 'vw', '%' ],	
				'range' => [
					'px' => [
						'min' => 0,
						'max' => 100,
						'step' => 1
					],
					'em' => [
						'min' => 0,
						'max' => 100,
						'step' => 1
					],
					'rem' => [
						'min' => 0,
						'max' => 100,
						'step' => 1
					],
					'vw' => [
						'min' => 0,
						'max' => 100,
						'step' => 1
					],
					'%' => [
						'min' => 0,
						'max' => 100,
						'step' => 1
					],
				],							
			]
		);		

		$this->end_controls_section();
	}

	public function get_global_color($global_colors, $new_color){
		$new_color_id = substr($new_color, strpos($new_color, 'colors?id=')+10);

		foreach($global_colors as $global_color){
			if($global_color['_id']!= $new_color_id){
				continue;
			}

			$new_color = ltrim($global_color['color'], '#');
		}

		return $new_color;
	}

	/**
	 * Converts time units to minutes
	 *
	 * This function converts time units to minutes based on the duration and unit type passed to the function, returning their equivalent.
	 *
	 * @param int $duration - The amount of time that needs conversion.
	 * @param string $unit  - The time format (minutes, hours, days, weeks).
	 *
	 * @return int|null The amount after conversion, or null if the input is invalid.
	 */
	function convertDurationToMinutes($duration, $unit) {
		// Validate if the duration is an integer
		$duration = filter_var($duration, FILTER_VALIDATE_INT);

		// If duration is not a valid integer, null, zero, or a negative integer return an error or null
		if ($duration === false || $duration <= 0) {
			return null;
		}

		switch ($unit) {
			case 'minutes':
				return $duration;
			case 'hours':
				return $duration * 60;
			case 'days':
				return $duration * 60 * 24;
			case 'weeks':
				return $duration * 60 * 24 * 7;
			default:
				return null;
		}
	}

	/**
	 * Render Upcoming Appointments widget output on the frontend.
	 *
	 * Written in PHP and used to generate the final HTML.
	 *
	 * @since 1.0.0
	 * @access protected
	 */
	protected function render() {
		$settings = $this->get_settings_for_display();
		if ( $settings['appointment_type'] === 'none' || $settings['appointment_type'] === 'all' ) {
			$settings['appointment_type'] = '';			
		}

		$attrs = array();

		$kit = Elementor\Plugin::$instance->kits_manager->get_active_kit_for_frontend();
		$system_colors = $kit->get_settings_for_display( 'system_colors' );
		$custom_colors = $kit->get_settings_for_display( 'custom_colors' );
		$global_colors = array_merge( $system_colors, $custom_colors );

		if( $settings['appointment_type'] && $settings['appointment_type'] !== '') {
			if( is_array($settings['appointment_type'])){
				$attrs['types'] = implode(',', $settings['appointment_type']);
			}else {
				$attrs['types'] = $settings['appointment_type'];
				$settings['appointment_type'] = '';
			}
		}

		if( $settings['label'] && $settings['label'] !== '') {
			$attrs['label'] = $settings['label'];
		}

		if ( $settings['appointment_types_view'] && $settings['appointment_types_view'] !== '' ) {

			$attrs['appointment_types_view'] = $settings['appointment_types_view'];
		}

		if ( ssa_should_render_booking_flow() ) {

			if ( $settings['booking_layout'] !== 'appt_type_settings' && !empty( $settings['booking_layout'] ) ) {
		
				if ( $settings['booking_layout'] === 'expanded' ) {
					$attrs['flow']      = $settings['booking_layout'];
					$attrs['date_view'] = $settings['date_view_options'];
					$attrs['time_view'] = $settings['time_view_options'];
				}
	
				else if ( $settings['booking_layout'] === 'express' ) {
					$attrs['flow']      = $settings['booking_layout'];
					$attrs['time_view'] = $settings['time_view_options'];
				}
	
				else if ( $settings['booking_layout'] === 'first_available' ) {
					$attrs['flow'] = $settings['booking_layout'];
					$attrs['suggest_first_available'] = true;
	
					// Only available within
					$attrs['suggest_first_available_within_minutes'] = $this->convertDurationToMinutes(  $settings['appt_duration'],  $settings['duration_unit'] );
	
					// Fallback flow
					if ( $settings['fallback_options'] === 'expanded' ) {
						$attrs['fallback_flow'] = $settings['fallback_options'];
						$attrs['date_view']     = $settings['date_view_options'];
						$attrs['time_view']     = $settings['time_view_options'];
					}
		
					else if ( $settings['fallback_options'] === 'express' ) {
						$attrs['fallback_flow'] = $settings['fallback_options'];
						$attrs['time_view']     = $settings['time_view_options'];
					}
	
				}
			}
		}

		if( $settings['accent_color'] && $settings['accent_color'] !== '' ) {
			$attrs['accent_color'] = ltrim( $settings['accent_color'], '#');
		} else if ( ! empty( $settings['__globals__']['accent_color'] ) ) {
			$attrs['accent_color'] = $this->get_global_color($global_colors, $settings['__globals__']['accent_color']);
		}
		if( $settings['background_color'] && $settings['background_color'] !== '' ) {
			$attrs['background'] = ltrim( $settings['background_color'], '#' );
		} else if (!empty($settings['__globals__']['background_color'])) {
			$attrs['background'] = $this->get_global_color($global_colors, $settings['__globals__']['background_color']);
		}
		if( $settings['font_family'] && $settings['font_family'] !== '' ) {
			$attrs['font'] = $settings['font_family'];
		}
		if( $settings['padding'] && $settings['padding'] !== '' ) {
			$attrs['padding'] = $settings['padding']['size'] . $settings['padding']['unit'];
		}

		if ( ! empty( $settings['defer'] ) && $settings['defer'] === 'yes' ) {
			$attrs['defer'] = 1;
		}
		?>
		<div class="elementor-ssa-booking-wrapper">
			<div <?php echo $this->get_render_attribute_string( 'booking' ); ?>>
				<div class="ssa-booking">
					<?php echo ssa()->shortcodes->ssa_booking( $attrs ); ?>
				</div>
			</div>
		</div>
		<?php
	}

}
