<?php
/**
 * GFB Appointment Class
 *
 * @package GFB.
 */

if ( ! defined( 'ABSPATH' ) ) {
	exit; // Exit if accessed directly.
}

if ( ! class_exists( 'APBGF_Appointment' ) ) {
	
	class APBGF_Appointment {
		/**
		 * Instance
		 *
		 * @var $instance
		 */
		private static $instance = null;

		private static $checkPostType = null;

		/**
		 * Init the Dependencies.
		 */
		private function __construct() {
			add_action('init', array( $this, 'register_appointment_posttype' ));
			add_filter( 'manage_apbgf-appointment_posts_columns', array( $this, 'apbgf_modify_column_names' ) );
			add_action( 'manage_apbgf-appointment_posts_custom_column', array( $this, 'apbgf_add_custom_column' ), 9, 2 );
			add_filter( 'gform_custom_merge_tags', array( $this, 'apbgf_merge_tags' ), 10, 4 );
			add_filter( 'gform_replace_merge_tags', array( $this, 'apbgf_replace_merge_tags' ), 10, 7 );
			// phpcs:ignore
			self::$checkPostType = isset( $_REQUEST['post_type'] ) && ! empty( sanitize_text_field( wp_unslash( $_REQUEST['post_type']) ) ) ? sanitize_text_field($_REQUEST['post_type']) : '';

			if ( 'apbgf-appointment' === self::$checkPostType ) {     

				add_action( 'admin_footer', array( $this, 'apbgf_appointment_modal' ) );

				add_filter('post_row_actions', '__return_empty_array');             

				add_filter('months_dropdown_results', '__return_empty_array');

				add_filter( 'bulk_actions-edit-apbgf-appointment', '__return_empty_array' );

				// HTML of the filter
				add_action( 'restrict_manage_posts', array( $this, 'apbgf_add_filters' ) );

				// the function that filters posts
				add_action( 'pre_get_posts', array( $this, 'apbgf_filter_query' ) );

				add_action( 'views_edit-apbgf-appointment', function ( $views ) {

					//add 4 block on top of the page.
					require_once APBGF_ADMIN_VIEW_PATH . 'block_data_reports.php';

					unset($views['all']);
					unset($views['publish']);
					unset($views['trash']);
					unset($views['draft']);

					return $views;
				});

			}

			// continue from here 27 June 2023, For adding multiple days appointment.
			add_action( 'gform_after_submission', array( $this, 'create_appointment' ), 90, 2 );

			add_filter( 'gform_confirmation', array( $this, 'apbgf_add_to_calendar_button' ), 11, 3 );

			add_filter('gform_product_info', array( $this, 'apbgf_add_appointment_fee' ), 4, 3);

			add_filter( 'gform_pre_render', array( $this, 'add_default_value_to_fields' ), 99, 3 );

			//paypal specific to update status
			add_action( 'gform_post_payment_status', array( $this, 'apbgf_paypal_payment_status' ), 99, 8 );

			add_action( 'wp_ajax_apbgf_delete_appointment', array( $this, 'apbgf_delete_appointment' ) );
			add_action( 'wp_ajax_apbgf_change_appointment_status', array( $this, 'apbgf_change_appointment_status' ) );

			add_action('wp_ajax_apbgf_show_appointment_data', array( $this, 'apbgf_show_appointment_data' ));

			add_action( 'wp_ajax_apbgf_create_booking_admin', array( $this, 'apbgf_create_booking_admin' ) );
			
			add_filter( 'template_redirect', array( $this, 'apbgf_mollie_payment_status' ), 999 );
		}
		
		public function apbgf_create_booking_admin() {
			check_ajax_referer( 'appointment-and-booking-for-gravity-forms', 'nonce' );

			// Sanitize all expected inputs from $_REQUEST
			$_POSTED = wp_unslash( $_REQUEST ); // Unslash data before sanitizing

			$result = array(
				'status'  => 'error',
				'message' => __( 'Appointment not created.', 'appointment-and-booking-for-gravity-forms' )
			);

			// Required fields - sanitize and validate
			$location_id = isset( $_POSTED['location_id'] ) ? absint( $_POSTED['location_id'] ) : 0;
			$service_id  = isset( $_POSTED['service_id'] ) ? absint( $_POSTED['service_id'] ) : 0;
			$staff_id    = isset( $_POSTED['staff_id'] ) ? absint( $_POSTED['staff_id'] ) : 0;
			$date        = isset( $_POSTED['date'] ) ? sanitize_text_field( $_POSTED['date'] ) : '';
			$time        = isset( $_POSTED['time'] ) ? sanitize_text_field( $_POSTED['time'] ) : '';
			$slot        = isset( $_POSTED['slot'] ) ? absint( $_POSTED['slot'] ) : 1;

			if ( ! $location_id || ! $service_id || ! $staff_id || empty( $date ) || empty( $time ) ) {
				wp_send_json( $result );
			}
			
			// Customer handling
			$wp_user = 0;
			$apbgf_customer = 0;
			
			if ( ! empty( $_POSTED['apbgf_customer'] ) ) {
				$apbgf_customer = absint( $_POSTED['apbgf_customer'] );
				$wp_user      = absint( get_post_meta( $apbgf_customer, 'wp_user', true ) );

				$userdata = get_userdata( $wp_user );
				if ( ! $userdata ) {
					wp_send_json( $result );
				}
			} elseif ( ! empty( $_POSTED['fname'] ) && ! empty( $_POSTED['email'] ) && is_email( $_POSTED['email'] ) ) {
				$data = array(
					'fname' => sanitize_text_field( $_POSTED['fname'] ),
					'lname' => isset( $_POSTED['lname'] ) ? sanitize_text_field( $_POSTED['lname'] ) : '',
					'email' => sanitize_email( $_POSTED['email'] ),
					'phone' => isset( $_POSTED['phone'] ) ? sanitize_text_field( $_POSTED['phone'] ) : ''
				);
				
				$wp_user = APBGF_Customer::apbgf_create_customer( $data );
				
				$apbgf_customer = absint( get_user_meta( $wp_user, 'apbgf_user', true ) );
			} else {
				$result['message'] = __( 'Missing or invalid customer info.', 'appointment-and-booking-for-gravity-forms' );
				wp_send_json( $result );
			}

			// Cost
			if ( isset( $_POSTED['cost'] ) && $_POSTED['cost'] !== '' ) {
				$raw_cost = floatval( $_POSTED['cost'] );
				$cost     = GFCommon::to_number( $raw_cost * $slot );
			} else {
				$cost = GFCommon::to_number( 0 );
			}

			// Prepare post args
			$args = apply_filters( 'apbgf_add_admin_appointment_args', array(
				'post_title'  => sanitize_text_field( $date . ' ' . $time ),
				'post_type'   => 'apbgf-appointment',
				'post_status' => 'draft',
				'wp_error'    => true,
				'meta_input'  => array(
					'form_id'         => '',
					'entry_id'        => '',
					'wp_user'         => $wp_user,
					'apbgf_user'        => $apbgf_customer,
					'location_id'     => $location_id,
					'location_name'   => sanitize_text_field( get_the_title( $location_id ) ),
					'service_id'      => $service_id,
					'service_name'    => sanitize_text_field( get_the_title( $service_id ) ),
					'staff_id'        => $staff_id,
					'staff_name'      => sanitize_text_field( get_the_title( $staff_id ) ),
					'date'            => $date,
					'time'            => $time,
					'slot'            => $slot,
					'cost'            => $cost,
					'status'          => 'pending'
				)
			) );

			$appointment_id = wp_insert_post( $args );

			if ( $appointment_id && ! is_wp_error( $appointment_id ) ) {
				$result['message'] = sprintf(
					// translators: %s is the appointment ID
					esc_html__( 'Appointment # %s has been created successfully', 'appointment-and-booking-for-gravity-forms' ),
					esc_html( $appointment_id )
				);
				$result['status']  = 'success';
			}

			wp_send_json( $result );
		}


		public function apbgf_mollie_payment_status() {
			// phpcs:ignore
			if ( isset($_GET['gf_mollie_result']) && ! empty($_GET['gf_mollie_result']) ) {
				// phpcs:ignore
				$arr = base64_decode( sanitize_text_field(wp_unslash( $_GET['gf_mollie_result'] )) );
				parse_str( $arr, $query );          
				list( $form_id, $feed_id, $entry_id ) = explode( '|', $query['ids'] );
				$entry = GFAPI::get_entry( $entry_id );             
				$payment_status = $entry['payment_status'];
				$appointment_id = gform_get_meta( $entry_id, 'apbgf_appointment' );

				if ( ! empty( $payment_status ) && ( 'Paid' == $payment_status || 'COMPLETED' == $payment_status ) ) {
					update_post_meta($appointment_id, 'status', 'confirmed');
					APBGF_Email::send_notification( $appointment_id, 'template_1', 'customer' ); # template_1
				}
				
			}
		}


		public function apbgf_add_to_calendar_button( $confirmation, $form, $entry ) {

			global $wp;     

			$apbgf_settings = APBGF_Setting::get_settings();

			$redirect_url = home_url($wp->request);
			$state =    $entry['id'];
			return $confirmation;
		}

		public static function apbgf_appointments_by_services( $service_id = '' ) {           
			
			if ( empty( $service_id ) ) {
				return false;
			}

			$args = array(
				'fields' => 'ids',
				'post_type' => 'apbgf-appointment',
				'numberposts' => -1,
				'post_status' => 'draft',
				'meta_query' => array(
					'relation' => 'AND',                
					array(
						'key' => 'service_id',
						'value' => trim($service_id),
						'compare' => '='
					)
				)
			);

			return get_posts( $args );
		}

		public static function apbgf_appointments_by_staff( $staff_id = '' ) {            
			
			if ( empty( $staff_id ) ) {
				return false;
			}

			$args = array(
				'fields' => 'ids',
				'post_type' => 'apbgf-appointment',
				'numberposts' => -1,
				'post_status' => 'draft',
				'meta_query' => array(
					'relation' => 'AND',                
					array(
						'key' => 'staff_id',
						'value' => trim($staff_id),
						'compare' => '='
					)
				)
			);

			return get_posts( $args );
		}

		public static function apbgf_appointments_by_status( $status = 'pending' ) {
			$args = array(
				'fields' => 'ids',
				'post_type' => 'apbgf-appointment',
				'numberposts' => -1,
				'post_status' => 'draft',
				'meta_query' => array(
					'relation' => 'AND',                
					array(
						'key' => 'status',
						'value' => trim($status),
						'compare' => '='
					)
				)
			);

			return get_posts( $args );
		}

		public static function apbgf_appointments_by_date( $date = '1970-01-01' ) {

			$args = array(
				'fields' => 'ids',
				'post_type' => 'apbgf-appointment',
				'numberposts' => -1,
				'post_status' => 'draft',
				'meta_query' => array(
					'relation' => 'AND',                
					array(
						'key' => 'date',
						'value' => trim($date),
						'compare' => 'LIKE'
					)
				)
			);

			return get_posts( $args );
		}

		public function apbgf_show_appointment_data() {
			check_ajax_referer( 'appointment-and-booking-for-gravity-forms', 'nonce' );

			$response = array(          
				'status'  => 'error'
			);

			$post_id = isset( $_POST['post_id'] ) ? absint( $_POST['post_id'] ) : 0;

			if ( $post_id ) {

				$post = get_post( $post_id );               
				if ( $post && 'apbgf-appointment' == $post->post_type ) {
					$appointment_id = $post->ID;
					$location_id = get_post_meta($appointment_id, 'location_id', true);
					if ( $location_id > 1 ) {
						$location = ! empty( get_the_title( $location_id ) ) ? get_the_title( $location_id ) : get_post_meta($appointment_id, 'location_name', true);
					} else {
						$location = 'All';
					}
					$service_id = get_post_meta($appointment_id, 'service_id', true);
					$service = ! empty( get_the_title( $service_id ) ) ? get_the_title( $service_id ) : get_post_meta($appointment_id, 'service_name', true);
					if ( 'other' === trim(strtolower($service)) ) {
						$service_other = get_post_meta( $appointment_id, 'service_other', true );
						if ( ! empty(trim($service_other)) ) {
							$service = $service . ' - ' . $service_other;
						}
					}
					$staff_id = get_post_meta($appointment_id, 'staff_id', true);
					$staffData = APBGF_Staff::get_staff_by_id( $staff_id );
					$staff = ! empty( get_the_title( $staff_id ) ) ? get_the_title( $staff_id ) : get_post_meta($appointment_id, 'staff_name', true);
					$user_id = get_post_meta($appointment_id, 'wp_user', true);
					$userdata = get_userdata( $user_id );
					if ( $userdata ) {
						$customer = $userdata->first_name . ' ' . $userdata->last_name;
					} else {
						$customer = '';
					}
					$form_id = get_post_meta($appointment_id, 'form_id', true);
					$entry_id = get_post_meta($appointment_id, 'entry_id', true);
					$formatted_dateTime = '';
					$time = get_post_meta($appointment_id, 'time', true);
					$time = apply_filters('apbgf_staff_time_slot', $time, $staffData );
					$date = get_post_meta($appointment_id, 'date', true);
					if ( is_array($date) && count($date) > 0 ) {
						foreach ( $date as $i => $date ) {
							if ( $i > 0 ) {
								$formatted_dateTime .= '<br/>';
							}
							$formatted_dateTime .= apply_filters('apbgf_staff_date_slot', $date) . ' ' . $time;

						}
					} else {
						$formatted_dateTime = apply_filters('apbgf_staff_date_slot', $date) . ' ' . $time;    
					}
					
					$slot = get_post_meta($appointment_id, 'slot', true);
					$cost = get_post_meta($appointment_id, 'cost', true);
					$cost = apbgf_price_format($cost);
					$status = get_post_meta($appointment_id, 'status', true);
					$booking_type = ! empty(get_post_meta($appointment_id, 'booking_type', true)) ? get_post_meta($appointment_id, 'booking_type', true) : 'custom';

					$response['apbgf-appointment_id'] = $appointment_id;
					$response['apbgf-location_name'] = $location;
					$response['apbgf-service_name'] = $service;
					$response['apbgf-staff_name'] = $staff;
					$response['apbgf-customer_name'] = $customer;
					$response['apbgf-schedule'] = $formatted_dateTime;
					$response['apbgf-slot'] = $slot;
					$response['apbgf-cost'] = $cost;
					$response['apbgf-status'] = $status;
					$response['apbgf-booking_type'] = $booking_type;
					$response['apbgf-form_id'] = $form_id;
					$response['apbgf-entry_id'] = $entry_id;
					$response['status'] = 'success';
				}
			}

			echo wp_json_encode( $response );
			wp_die();
		}

		public function apbgf_appointment_modal() {
			//adding customer modal view file
			require_once APBGF_ADMIN_VIEW_PATH . 'modal/appointment-modal.php';

			$popup_img = defined( 'APBGF_IMAGE_URL' ) ? APBGF_IMAGE_URL . 'ProPopup.svg' : '';
			$popup_url = 'https://gravitybooking.com/pricing/?utm_source=plugin&utm_medium=appointment';
			if ( $popup_img ) {
				?>
				<div id="apbgf-appointment-pro-modal" class="modal" role="dialog" aria-modal="true" aria-label="<?php esc_attr_e( 'Export', 'appointment-and-booking-for-gravity-forms' ); ?>" style="position:fixed;inset:0;align-items:center;justify-content:center;">
					<div class="apbgf-appointment-pro-modal__inner" style="position:relative;max-width:640px;width:100%;margin:auto;">
						<div class="apbgf-appointment-pro-modal__content" style="position:relative;border-radius:8px;overflow:hidden;">
							<img src="<?php echo esc_url( $popup_img ); ?>" alt="<?php esc_attr_e( 'Upgrade to Pro', 'appointment-and-booking-for-gravity-forms' ); ?>" style="display:block;width:100%;height:auto;" />
							<a href="<?php echo esc_url( $popup_url ); ?>" target="_blank" rel="noopener noreferrer"
							   aria-label="<?php esc_attr_e( 'Buy Gravity Bookings', 'appointment-and-booking-for-gravity-forms' ); ?>"
							   style="position:absolute;left:31%;top:69%;width:38%;height:15%;background:transparent;border:none;outline:none;box-shadow:none;cursor:pointer;text-indent:-9999px;overflow:hidden;">
								<?php esc_html_e( 'Buy Gravity Bookings', 'appointment-and-booking-for-gravity-forms' ); ?>
							</a>
							<button type="button" class="modal__close" aria-label="<?php esc_attr_e( 'Close', 'appointment-and-booking-for-gravity-forms' ); ?>" style="position:absolute;top:0;right:0;width:15%;height:12%;background:transparent;border:none;outline:none;box-shadow:none;cursor:pointer;z-index:2;"></button>
						</div>
					</div>
				</div>
				<?php
			}
		}

		public static function apbgf_show_appointments_on_calendar( $data ) {

			$appointmentData = array();

			if ( isset($data['staff_id']) && ! empty($data['staff_id']) ) {

				$staff_meta = array();
				if ( isset($data['staff_id']) && 'all' != $data['staff_id'] ) {
					$staff_meta = array(
						'key' => 'staff_id',
						'value' => trim( $data['staff_id'] ),
						'compare' => '='
					);
				}

				$location_meta = array();
				if ( isset($data['location_id']) && 'all' != $data['location_id'] ) {
					$location_meta = array(
						'key' => 'location_id',
						'value' => trim( $data['location_id'] ),
						'compare' => '='
					);
				}

				$service_meta = array();
				if ( isset($data['service_id']) && 'all' != $data['service_id'] ) {
					$service_meta = array(
						'key' => 'service_id',
						'value' => trim( $data['service_id'] ),
						'compare' => '='
					);
				}

				$args = array(
					'fields' => 'ids',
					'post_type' => 'apbgf-appointment',
					'numberposts' => -1,
					'post_status' => 'draft',
					'meta_query' => array(
						'relation' => 'AND',                
						// array(
						//  'key' => 'staff_id',
						//  'value' => trim( $data['staff_id'] ),
						//  'compare' => '='
						// ),
						$staff_meta,
						$location_meta,
						$service_meta

					)
				);

				$appointmentData = get_posts( $args );              
			}

			return $appointmentData;    
		}

		public static function apbgf_total_collection() {
			$total_collection = 0;

			$args = array(
				'post_type' => 'apbgf-appointment',
				'numberposts' => -1,
				'post_status' => 'draft',
				'meta_query' => array(
					'relation' => 'AND',                
					array(
						'key' => 'status',
						'value' => array( 'visited', 'confirmed' ),
						'compare' => 'IN'
					)
				)
			);

			$appointmentData = get_posts( $args );

			if ( is_array( $appointmentData ) && count( $appointmentData ) > 0 ) {
				foreach ($appointmentData as  $appointment) {
					$cost = get_post_meta( $appointment->ID, 'cost', true );
					$cost = isset($cost) ? (float) $cost : 0;
					$total_collection += $cost;
				}               
			}

			return $total_collection;
		}   

		public function apbgf_filter_query( $admin_query ) {

			if ( ! is_admin() || ! $admin_query->is_main_query() ) {
				return $admin_query;
			}

			$post_type = $admin_query->get( 'post_type' );
			if ( ! $post_type && isset( $_GET['post_type'] ) ) {
				$post_type = sanitize_key( wp_unslash( $_GET['post_type'] ) );
			}
			if ( 'apbgf-appointment' !== $post_type ) {
				return $admin_query;
			}

			$cond_arr = array();

			if ( is_user_logged_in() && current_user_can( 'apbgf-staff' ) && ! current_user_can( 'manage_options' ) ) {
				$current_user_id = get_current_user_id();
				$staff_id        = get_user_meta( $current_user_id, 'apbgf_user', true );
				if ( $staff_id ) {
					$cond_arr[] = array(
						'key'     => 'staff_id',
						'value'   => $staff_id,
						'compare' => '=',
					);
				}
			}

			$date_from_raw = isset( $_GET['date_from'] ) ? sanitize_text_field( wp_unslash( $_GET['date_from'] ) ) : '';
			$date_to_raw   = isset( $_GET['date_to'] ) ? sanitize_text_field( wp_unslash( $_GET['date_to'] ) ) : '';

			if ( $date_from_raw && $date_to_raw ) {
				$filter_nonce = '';
				if ( isset( $_GET['apbgf-appointment-filter-nonce'] ) ) {
					$filter_nonce = sanitize_text_field( wp_unslash( $_GET['apbgf-appointment-filter-nonce'] ) );
				} elseif ( isset( $_POST['apbgf-appointment-filter-nonce'] ) ) {
					$filter_nonce = sanitize_text_field( wp_unslash( $_POST['apbgf-appointment-filter-nonce'] ) );
				}

				if ( wp_verify_nonce( $filter_nonce, 'apbgf-appointment-filter-nonce-action' ) ) {
					$date_from_obj = DateTime::createFromFormat( 'Y-m-d', $date_from_raw );
					$date_to_obj   = DateTime::createFromFormat( 'Y-m-d', $date_to_raw );

					if ( $date_from_obj && $date_to_obj ) {
						if ( $date_from_obj > $date_to_obj ) {
							$swap          = $date_from_obj;
							$date_from_obj = $date_to_obj;
							$date_to_obj   = $swap;
						}

						// Dates may be stored as a string or serialized array; LIKE matches both.
						if ( $date_from_obj->format( 'Y-m-d' ) === $date_to_obj->format( 'Y-m-d' ) ) {
							$cond_arr[] = array(
								'key'     => 'date',
								'value'   => $date_from_obj->format( 'Y-m-d' ),
								'compare' => 'LIKE',
							);
						} else {
							$date_clauses = array( 'relation' => 'OR' );
							$period       = new DatePeriod(
								$date_from_obj,
								new DateInterval( 'P1D' ),
								( clone $date_to_obj )->modify( '+1 day' )
							);
							foreach ( $period as $date_day ) {
								$date_clauses[] = array(
									'key'     => 'date',
									'value'   => $date_day->format( 'Y-m-d' ),
									'compare' => 'LIKE',
								);
							}
							if ( count( $date_clauses ) > 1 ) {
								$cond_arr[] = $date_clauses;
							}
						}
					}
				}
			}

			$search_term = isset( $admin_query->query_vars['s'] ) ? trim( $admin_query->query_vars['s'] ) : '';

			if ( $search_term !== '' && is_numeric( $search_term ) && absint( $search_term ) ) {
				$admin_query->set( 'p', absint( $search_term ) );
				$admin_query->set( 's', '' );
			} elseif ( $search_term !== '' ) {
				$search_clauses = array( 'relation' => 'OR' );

				$user_query = new WP_User_Query(
					array(
						'search'         => '*' . $search_term . '*',
						'search_columns' => array( 'display_name', 'user_email', 'user_login', 'user_nicename' ),
						'fields'         => 'ID',
						'number'         => -1,
					)
				);
				$matching_user_ids = array_filter( array_map( 'absint', (array) $user_query->get_results() ) );

				$name_user_query = new WP_User_Query(
					array(
						'fields'     => 'ID',
						'number'     => -1,
						'meta_query' => array(
							'relation' => 'OR',
							array(
								'key'     => 'first_name',
								'value'   => $search_term,
								'compare' => 'LIKE',
							),
							array(
								'key'     => 'last_name',
								'value'   => $search_term,
								'compare' => 'LIKE',
							),
						),
					)
				);
				$matching_user_ids = array_unique(
					array_merge( $matching_user_ids, array_filter( array_map( 'absint', (array) $name_user_query->get_results() ) ) )
				);

				foreach ( $matching_user_ids as $user_id ) {
					$search_clauses[] = array(
						'key'     => 'wp_user',
						'value'   => $user_id,
						'compare' => '=',
					);
				}

				$search_clauses[] = array(
					'key'     => 'staff_name',
					'value'   => $search_term,
					'compare' => 'LIKE',
				);
				$search_clauses[] = array(
					'key'     => 'service_name',
					'value'   => $search_term,
					'compare' => 'LIKE',
				);
				$search_clauses[] = array(
					'key'     => 'location_name',
					'value'   => $search_term,
					'compare' => 'LIKE',
				);
				$search_clauses[] = array(
					'key'     => 'service_other',
					'value'   => $search_term,
					'compare' => 'LIKE',
				);

				if ( count( $search_clauses ) > 1 ) {
					$cond_arr[] = $search_clauses;
				} else {
					$admin_query->set( 'post__in', array( 0 ) );
				}

				$admin_query->set( 's', '' );
			}

			if ( ! empty( $cond_arr ) ) {
				if ( count( $cond_arr ) > 1 && ! isset( $cond_arr['relation'] ) ) {
					$cond_arr = array_merge( array( 'relation' => 'AND' ), $cond_arr );
				}
				$admin_query->set( 'meta_query', $cond_arr );
			}

			return $admin_query;
		}

		public function apbgf_add_filters( $post_type ) {
			require_once APBGF_ADMIN_VIEW_PATH . 'appointment-filters.php';
		}       

		public function apbgf_change_appointment_status() {
			
			check_ajax_referer( 'appointment-and-booking-for-gravity-forms', 'nonce' );

			$response = array(
				'message' => esc_html__( 'Appointment status has not been changed.', 'appointment-and-booking-for-gravity-forms' ),
				'status'  => 'error'
			);

			// Only process the specific expected inputs
			$post_id = isset( $_POST['post_id'] ) ? absint( $_POST['post_id'] ) : 0;
			$status  = isset( $_POST['status'] ) ? sanitize_text_field( wp_unslash( $_POST['status'] ) ) : '';
			$allowed_statuses = array( 'pending', 'confirmed', 'visited', 'cancelled' );

			if ( $post_id && in_array( $status, $allowed_statuses, true ) ) {
				update_post_meta( $post_id, 'status', $status );
				
				if ( 'confirmed' === $status ) {
					APBGF_Email::send_notification( $post_id, 'template_1', 'customer' ); # template_1
				}

				if ( 'visited' === $status ) {
					APBGF_Email::send_notification( $post_id, 'template_2', 'customer' ); # template_2
					APBGF_Email::send_notification( $post_id, 'template_4', 'admin' ); # template_4
				}

				if ( 'cancelled' === $status ) {
					APBGF_Email::send_notification( $post_id, 'template_3', 'customer' ); # template_3
					APBGF_Email::send_notification( $post_id, 'template_6', 'admin' ); # template_6
					APBGF_Email::send_notification( $post_id, 'template_7', 'staff' ); # template_7
				}

				$response['message'] = esc_html__( 'Appointment status has been changed successfully.', 'appointment-and-booking-for-gravity-forms' );
				$response['status'] = 'success';
			} else {
				$response['message'] = esc_html__( 'Invalid request. Status not changed.', 'appointment-and-booking-for-gravity-forms' );
			}

			echo wp_json_encode( $response );
			wp_die();
		}

		public function apbgf_delete_appointment() {

			check_ajax_referer( 'appointment-and-booking-for-gravity-forms', 'nonce' );

			$response = array(
				'message' => esc_html__( 'appointment not deleted.', 'appointment-and-booking-for-gravity-forms' ),
				'status'  => 'error'
			);

			$post_id = isset( $_POST['post_id'] ) ? absint( $_POST['post_id'] ) : 0;

			if ( $post_id ) {
				$post = get_post( $post_id );               
				if ( $post && 'apbgf-appointment' == $post->post_type ) {
					$entry_id = get_post_meta( $post->ID, 'entry_id', true );
					if ( ! empty($entry_id) ) {
						\GFAPI::delete_entry( $entry_id );
					}
					wp_delete_post( $post->ID, true );
					$response['message'] = esc_html__( 'Appointment deleted successfully.', 'appointment-and-booking-for-gravity-forms' );
					$response['status'] = 'success';
				}
			}

			echo wp_json_encode( $response );
			wp_die();
		}

		public function apbgf_add_custom_column( $column, $postId ) {         

			$formatted_dateTime = '';
			$time = get_post_meta( $postId, 'time', true );
			$time = apply_filters('apbgf_appointment_time_format', $time);
			$booking_type = get_post_meta( $postId, 'booking_type', true );
			if ( 'fullday' == $booking_type ) {
				$time = esc_html__('Full Day', 'appointment-and-booking-for-gravity-forms');
			}
			$date = get_post_meta( $postId, 'date', true );
			if ( is_array($date) && count($date) > 0 ) {
				foreach ( $date as $k => $date ) {
					if ( $k > 0 ) {
						$formatted_dateTime .= '<br/>'; 
					}
					$formatted_dateTime .= apply_filters('apbgf_appointment_date_format', $date);
				}

				$formatted_dateTime .= '<br/>' . $time;
			} else {                
				$formatted_dateTime = apply_filters('apbgf_appointment_date_format', $date) . '<br/>' . $time;
			}
			
			$user_id = get_post_meta( $postId, 'wp_user', true );
			$userdata = get_user_by('id', $user_id);
			$customer = '';
			if ( $userdata ) {
				$customer = $userdata->display_name;
			}
			$location = get_post_meta( $postId, 'location_id', true );
			$location = ! empty( get_the_title( $location ) ) ? get_the_title( $location ) : get_post_meta($postId, 'location_name', true);
			$service = get_post_meta( $postId, 'service_id', true );            
			$service = ! empty( get_the_title( $service ) ) ? get_the_title( $service ) : get_post_meta($postId, 'service_name', true);
			$staff = get_post_meta( $postId, 'staff_id', true );            
			$staff = ! empty( get_the_title( $staff ) ) ? get_the_title( $staff ) : get_post_meta($postId, 'staff_name', true);
			$capacity = get_post_meta( $postId, 'slot', true );
			$cost = get_post_meta( $postId, 'cost', true );
			$cost = apbgf_price_format($cost);
			$status = get_post_meta( $postId, 'status', true );
			$cancel_reason = get_post_meta( $postId, 'cancel_reason', true );
			
			switch ($column) {              

				case 'id':
				echo '&nbsp;&nbsp;' . esc_attr($postId);
					break;

				case 'app_date_time':
				echo wp_kses_post($formatted_dateTime);
					break;

				case 'customer':
				echo esc_attr($customer);
					break;

				case 'staff':
				echo esc_attr($staff);
					break;
				
				case 'service':
					if ( 'other' === trim(strtolower($service)) ) {
						$service_other = get_post_meta( $postId, 'service_other', true );
						if ( ! empty(trim($service_other)) ) {
							echo esc_attr($service) . ' - ' . esc_attr($service_other);
						} else {
							echo esc_attr($service);
						}
					} else {
						echo esc_attr($service);
					}
					break;

				case 'payment':
				echo esc_attr($cost);
					break;

				case 'status':
					if ( current_user_can( 'apbgf-staff' ) && ! current_user_can( 'manage_options' ) ) {
						$apbgf_settings = APBGF_Setting::get_settings();
						if ( ( isset($apbgf_settings['apbgf_appointment_policy']) && 'staff' == $apbgf_settings['apbgf_appointment_policy'] ) && 'cancelled' !== $status && 'visited' !== $status ) {
							echo '<select data-post_id="' . esc_attr($postId) . '" class="apbgf-appointment-status">
						<option value="pending" ' . selected($status, 'pending', false) . '>' . esc_html__('Pending', 'appointment-and-booking-for-gravity-forms') . '</option>
						<option value="confirmed" ' . selected($status, 'confirmed', false) . '>' . esc_html__('Confirmed', 'appointment-and-booking-for-gravity-forms') . '</option>
						<option value="visited" ' . selected($status, 'visited', false) . '>' . esc_html__('Visited', 'appointment-and-booking-for-gravity-forms') . '</option>
						<option value="cancelled" ' . selected($status, 'cancelled', false) . '>' . esc_html__('Cancelled', 'appointment-and-booking-for-gravity-forms') . '</option>
						</select>';
						} else {
							echo esc_attr( strtoupper($status) );
							if ( ! empty(trim($cancel_reason)) ) {
								echo '<br/> <a href="#" class="apbgf_show_reason" data-reason="' . esc_html($cancel_reason) . '">' . esc_html__('Reason', 'appointment-and-booking-for-gravity-forms') . '</a>';
							}                           
						}
					} else {

						echo '<select data-post_id="' . esc_attr($postId) . '" class="apbgf-appointment-status">
					<option value="pending" ' . selected($status, 'pending', false) . '>' . esc_html__('Pending', 'appointment-and-booking-for-gravity-forms') . '</option>
					<option value="confirmed" ' . selected($status, 'confirmed', false) . '>' . esc_html__('Confirmed', 'appointment-and-booking-for-gravity-forms') . '</option>
					<option value="visited" ' . selected($status, 'visited', false) . '>' . esc_html__('Visited', 'appointment-and-booking-for-gravity-forms') . '</option>
					<option value="cancelled" ' . selected($status, 'cancelled', false) . '>' . esc_html__('Cancelled', 'appointment-and-booking-for-gravity-forms') . '</option>
					</select>';
					
						if ( 'cancelled' === $status && ! empty(trim($cancel_reason)) ) {
							echo '<br/> <a href="#" class="apbgf_show_reason" data-reason="' . esc_html($cancel_reason) . '">' . esc_html__('Reason', 'appointment-and-booking-for-gravity-forms') . '</a>';
						}
					}
					break;
				
				case 'actions':
				echo '<a href="#" data-type="appointment" data-id="apbgf-appointment-modal" data-post_id="' . esc_attr( $postId ) . '" class="wc-dashicons apbgf-edit"> <i class="fa fa-info-circle customer--icon"></i></a>';
					if ( 'cancelled' == $status ) {
						echo '<a href="#" data-type="appointment" data-post_id="' . esc_attr( $postId ) . '" class="wc-dashicons apbgf-delete" title="Delete"> <i class="fa fa-trash customer--icon"></i></a>';
					}               
					break;
			}
		}

		public function apbgf_modify_column_names( $columns ) {           
			unset($columns['date']);
			unset($columns['title']);
			unset($columns['cb']);  

			$columns['id'] = __('&nbsp;&nbsp;Booking ID', 'appointment-and-booking-for-gravity-forms');
			$columns['app_date_time'] = __('Appointment Date', 'appointment-and-booking-for-gravity-forms');
			$columns['customer'] = __('Customer', 'appointment-and-booking-for-gravity-forms');
			$columns['staff'] = __('Staff', 'appointment-and-booking-for-gravity-forms');         
			$columns['service'] = __('Service', 'appointment-and-booking-for-gravity-forms');
			$columns['payment'] = __('Payment', 'appointment-and-booking-for-gravity-forms');
			$columns['status'] = __('Status', 'appointment-and-booking-for-gravity-forms');
			$columns['actions'] = __('Actions', 'appointment-and-booking-for-gravity-forms');

			return apply_filters('apbgf_appointment_columns', $columns);
		}

		public static function apbgf_get_appointments_by_customer( $user_id = '' ) {

			if ( empty( $user_id ) ) {
				return false;
			}

			$args = array(
				'post_type' => 'apbgf-appointment',
				'numberposts' => -1,
				'post_status' => 'draft',
				'meta_query' => array(
					'relation' => 'AND',                
					array(
						'key' => 'wp_user',
						'value' => $user_id,
						'compare' => '='
					)
				)
			);

			return get_posts($args);
		}

		public static function apbgf_check_day_available_with_slots( $staff_id, $date, $staffData, $dayName, $day_type = 'normal', $location_id = 0, $service_id = 0 ) {

			if ( 'normal' === $day_type ) {
				if ( is_array($staffData) && isset($staffData['timeslots'][ $dayName ]['start']) && isset( $staffData['timeslots'][ $dayName ]['capacity'] ) && count($staffData['timeslots'][ $dayName ]['capacity']) > 0 ) {

					$total_slots_in_a_day = (int) array_sum($staffData['timeslots'][ $dayName ]['capacity']);             

					$total_slots_consumed = 0;

					$current_time = gmdate('Y-m-d H:i');              
					$check_time = gmdate($date . ' ' . end($staffData['timeslots'][ $dayName ]['start']) );
					if ( strtotime($check_time) > strtotime($current_time) ) {
						
						$booked_capacities = (int) self::apbgf_all_appointment_by_date($staff_id, $date, $location_id, $service_id);
						$total_slots_consumed = $total_slots_consumed + $booked_capacities;
						return $total_slots_in_a_day > $total_slots_consumed;
					}
				}
			} elseif ( is_array($staffData) && isset($staffData['spl_day_timeslots'][ $date ][ $dayName ]['start']) && isset( $staffData['spl_day_timeslots'][ $date ][ $dayName ]['capacity'] ) && count($staffData['spl_day_timeslots'][ $date ][ $dayName ]['capacity']) > 0 ) {

					$total_slots_in_a_day = (int) array_sum($staffData['spl_day_timeslots'][ $date ][ $dayName ]['capacity']);              

					$total_slots_consumed = 0;              

					$current_time = gmdate('Y-m-d H:i');              
					$check_time = gmdate($date . ' ' . end($staffData['spl_day_timeslots'][ $date ][ $dayName ]['start']) );
				if ( strtotime($check_time) > strtotime($current_time) ) {
						
					$booked_capacities = (int) self::apbgf_all_appointment_by_date($staff_id, $date, $location_id, $service_id);
					$total_slots_consumed = $total_slots_consumed + $booked_capacities;
					return $total_slots_in_a_day > $total_slots_consumed;
				}
			}

			return false;
		}

		public static function apbgf_all_appointment_by_date( $staff_id, $date, $location_id = 0, $service_id = 0 ) {

			$service_check = array();
			$location_check = array();

			if ( true === apply_filters('apbgf_all_appointment_by_date_time_service', false) && ! empty($service_id) && $service_id != '' && $service_id != '0' ) {
				$service_check = array(
					'key' => 'service_id',
					'value' => $service_id,
					'compare' => '='
				);
			}

			if ( true === apply_filters('apbgf_all_appointment_by_date_time_location', false) && ! empty($location_id) && $location_id != '' && $location_id != '0' ) {
				$location_check = array(
					'key' => 'location_id',
					'value' => $location_id,
					'compare' => '='
				);
			}

			$slot_count = 0;

			if ( ! empty( $date ) ) {
				$args = array(
					'post_type' => 'apbgf-appointment',
					'fields' => 'ids',
					'numberposts' => -1,
					'post_status' => 'draft',
					'meta_query' => array(
						'relation' => 'AND',
						array(
							'key' => 'staff_id',
							'value' => $staff_id,
							'compare' => '='
						),
						array(
							'key' => 'date',
							'value' => $date,
							'compare' => 'LIKE'
						),                      
						array(
							'key' => 'status',
							'value' => 'cancelled',
							'compare' => '!='
						),
						$location_check,
						$service_check
					)
				);

				$appointments = get_posts($args);
				if ( is_array( $appointments ) && count( $appointments ) > 0 ) {                    
					foreach ( $appointments as $appointment_id ) {
						$slot = get_post_meta( $appointment_id, 'slot', true );
						$slot_count += $slot;
					}
				}
			}

			return $slot_count;
		}

		public static function apbgf_all_appointment_by_date_time( $staff_id, $date, $formatted_slot, $type = 'custom', $service_id = 0, $location_id = 0 ) {

			$service_check = array();
			$location_check = array();

			if ( true === apply_filters('apbgf_all_appointment_by_date_time_service', false) && ! empty($service_id) && $service_id != '' && $service_id != '0' ) {
				$service_check = array(
					'key' => 'service_id',
					'value' => $service_id,
					'compare' => '='
				);
			}

			if ( true === apply_filters('apbgf_all_appointment_by_date_time_location', false) && ! empty($location_id) && $location_id != '' && $location_id != '0' ) {
				$location_check = array(
					'key' => 'location_id',
					'value' => $location_id,
					'compare' => '='
				);
			}

			$slot_count = 0;

			if ( 'fullday' == $type ) {

				if ( ! empty( $date ) ) {
					$args = array(
						'post_type' => 'apbgf-appointment',
						'fields' => 'ids',
						'numberposts' => -1,
						'post_status' => 'draft',
						'meta_query' => array(
							'relation' => 'AND',
							array(
								'key' => 'staff_id',
								'value' => $staff_id,
								'compare' => '='
							),
							array(
								'key' => 'date',
								'value' => $date,
								'compare' => 'LIKE'
							),
							array(
								'key' => 'booking_type',
								'value' => $type,
								'compare' => '='
							),
							array(
								'key' => 'status',
								'value' => 'cancelled',
								'compare' => '!='
							),
							$service_check,
							$location_check,
						)
					);

					$appointments = get_posts($args);
					if ( is_array( $appointments ) && count( $appointments ) > 0 ) {                    
						foreach ( $appointments as $appointment_id ) {
							$slot = get_post_meta( $appointment_id, 'slot', true );
							$slot_count += $slot;
						}
					}
				}

			} elseif ( ! empty( $date ) && ! empty( $formatted_slot ) ) {

					$args = array(
						'post_type' => 'apbgf-appointment',
						'fields' => 'ids',
						'numberposts' => -1,
						'post_status' => 'draft',
						'meta_query' => array(
							'relation' => 'AND',
							array(
								'key' => 'staff_id',
								'value' => $staff_id,
								'compare' => '='
							),
							array(
								'key' => 'date',
								'value' => $date,
								'compare' => 'LIKE'
							),
							array(
								'key' => 'time',
								'value' => $formatted_slot,
								'compare' => 'LIKE'
							),
							array(
								'key' => 'status',
								'value' => 'cancelled',
								'compare' => '!='
							),
							$service_check,
							$location_check,
						)
					);

					
					$appointments = get_posts($args);
					
					if ( is_array( $appointments ) && count( $appointments ) > 0 ) {                    
						foreach ( $appointments as $appointment_id ) {
							$slot = get_post_meta( $appointment_id, 'slot', true );
							$slot_count += $slot;
						}
					}

			}
			return $slot_count;
		}

		/**
		*
		* This function is used to passed amount as product so third party payment methods addon can process the payments.
		*/
		public function apbgf_add_appointment_fee( $product_info, $form, $lead ) {

			$form_id = absint( $form['id'] );
			$id = apbgf_field_exist( $form );
			$lead_id = absint( $lead['id'] );

			// Sanitize $_POST data
			$input_data = filter_input_array( INPUT_POST, FILTER_SANITIZE_FULL_SPECIAL_CHARS );

			if (
				$id &&
				isset( $input_data[ 'input_' . $id ]['service'] ) &&
				isset( $input_data[ 'input_' . $id ]['staff'] ) &&
				isset( $input_data[ 'input_' . $id ]['cost'] ) &&
				isset( $input_data[ 'input_' . $id ]['slot'] )
			) {
				$field_data   = $input_data[ 'input_' . $id ];
				$service_id   = absint( $field_data['service'] );
				$staff_id     = absint( $field_data['staff'] );
				$cost         = (float) $field_data['cost'];
				$slot         = (int) $field_data['slot'];
				$service_title = get_the_title( $service_id );

				$staffData = APBGF_Staff::get_staff_by_id( $staff_id );

				if (
					! empty( $staffData['services'] ) &&
					isset( $staffData['services'][ $service_id ]['available'] ) &&
					'yes' === $staffData['services'][ $service_id ]['available']
				) {
					$service_price = (float) $staffData['services'][ $service_id ]['price'];
					if ( $service_price <= 0 ) {
						$service_info   = APBGF_Service::get_service_by_id( $service_id );
						$service_price  = (float) $service_info['price'];
					}
					$product_info['products']['appointment_cost'] = array(
						'name'     => $service_title,
						'price'    => $service_price,
						'quantity' => $slot
					);
				}
			} else {
				// Fallback: use data from entry meta
				$appointment_data = gform_get_meta( $lead_id, $id, true );

				if ( $id && is_array( $appointment_data ) ) {
					$service_id    = absint( $appointment_data['service'] );
					$staff_id      = absint( $appointment_data['staff'] );
					$cost          = (float) $appointment_data['cost'];
					$slot          = (int) $appointment_data['slot'];
					$service_title = get_the_title( $service_id );

					$staffData = APBGF_Staff::get_staff_by_id( $staff_id );

					if (
						! empty( $staffData['services'] ) &&
						isset( $staffData['services'][ $service_id ]['available'] ) &&
						'yes' === $staffData['services'][ $service_id ]['available']
					) {
						$service_price = (float) $staffData['services'][ $service_id ]['price'];
						if ( $service_price <= 0 ) {
							$service_info   = APBGF_Service::get_service_by_id( $service_id );
							$service_price  = (float) $service_info['price'];
						}
						$product_info['products']['appointment_cost'] = array(
							'name'     => $service_title,
							'price'    => $service_price,
							'quantity' => $slot
						);
					}
				}
			}

			return apply_filters( 'apbgf_product_info', $product_info );
		}


		public function apbgf_paypal_payment_status( $feed, $entry, $status, $transaction_id, $subscriber_id, $amount, $pending_reason, $reason ) {  
			
			$appointment_id = gform_get_meta( $entry['id'], 'apbgf_appointment', true );

			if ( $status == 'Completed' || $status == 'Paid' ) {
				update_post_meta( $appointment_id, 'status', 'confirmed' );
				APBGF_Email::send_notification( $appointment_id, 'template_1', 'customer' ); # template_1
			} elseif ( $status == 'Refunded' || $status == 'Reversed' || $status == 'Canceled_Reversal' ) {
				update_post_meta( $appointment_id, 'status', 'cancelled' );
				update_post_meta( $appointment_id, 'cancel_reason', $reason );
				APBGF_Email::send_notification( $appointment_id, 'template_3', 'customer' ); # template_3
				APBGF_Email::send_notification( $appointment_id, 'template_6', 'admin' ); # template_6
				APBGF_Email::send_notification( $appointment_id, 'template_7', 'staff' ); # template_6
			}
		}

		public function add_default_value_to_fields( $form, $ajax, $field_values ) {            

			if ( is_user_logged_in() ) {

				$user_id = get_current_user_id();
				$user_details = get_user_by('ID', $user_id);
				$first_name = get_user_meta($user_id, 'first_name', true);
				$last_name = get_user_meta($user_id, 'last_name', true);
				$phone = get_user_meta($user_id, 'phone', true);
				
				$fields = $form['fields'];              

				$results = array_filter($fields, function ( $item ) {
					return ( $item->type === 'apbgf_appointment_calendar' );
				});

				if ( $results ) {

					foreach ($fields as &$field) {                  

						if ( $field->type == 'email' ) {                        
							$field->defaultValue = $user_details->user_email;
						}

						if ( $field->type == 'phone' ) {                        
							$field->defaultValue = $phone;
						}

						if ( $field->type == 'name' ) {                         
							$field->inputs[0]['defaultValue'] = $first_name;
							$field->inputs[1]['defaultValue'] = $last_name;

						}
					}
				}
				
			}

			return $form;
		}

		

		/**
		 * Create Appointment
		 */
		public function create_appointment( $entry, $form ) {

		    $entry_id       = absint( $entry['id'] );
		    $form_id        = absint( $form['id'] );
		    $id             = apbgf_field_exist( $form );         
		    $form_settings  = get_option( 'apbgf_form_settings_' . $form_id, true );
		    $data           = array();
		    $payment_status = isset( $entry['payment_status'] ) ? sanitize_text_field( $entry['payment_status'] ) : '';
		    $woo_flag       = false;
		    $apbgf_settings = APBGF_Setting::get_settings();

		    // Verify nonce
		    if (
		        isset( $_POST['apbgf-booking-form-nonce'] )
		        && wp_verify_nonce(
		            sanitize_text_field( wp_unslash( $_POST['apbgf-booking-form-nonce'] ) ),
		            'apbgf-form-submit-nonce'
		        )
		    ) {

		        // Always work with a sanitized copy of request data
		        $_POSTED = array();
		        if ( ! empty( $_REQUEST ) && is_array( $_REQUEST ) ) {
		            foreach ( $_REQUEST as $key => $value ) {
		                if ( is_array( $value ) ) {
		                    $_POSTED[ sanitize_key( $key ) ] = array_map( 'sanitize_text_field', wp_unslash( $value ) );
		                } else {
		                    $_POSTED[ sanitize_key( $key ) ] = sanitize_text_field( wp_unslash( $value ) );
		                }
		            }
		        }

		        // If WooCommerce is present, pull data safely
		        if ( function_exists( 'WC' ) ) {
		            $cart = WC()->cart;
		            if ( $cart && ! $cart->is_empty() ) {
		                $cart_items = $cart->get_cart_contents();

		                $fname_id  = isset( $form_settings['registration_field']['fname'] ) ? sanitize_key( $form_settings['registration_field']['fname'] ) : '';
		                $lname_id  = isset( $form_settings['registration_field']['lname'] ) ? sanitize_key( $form_settings['registration_field']['lname'] ) : '';
		                $email_id  = isset( $form_settings['registration_field']['email'] ) ? sanitize_key( $form_settings['registration_field']['email'] ) : '';
		                $phone_id  = isset( $form_settings['registration_field']['phone'] ) ? sanitize_key( $form_settings['registration_field']['phone'] ) : '';

		                foreach ( $cart_items as $cart_item ) {

		                    if ( isset( $cart_item['_gravity_form_lead'][ $id ] ) ) {
		                        $_POSTED[ 'input_' . $id ] = array_map( 'sanitize_text_field', (array) $cart_item['_gravity_form_lead'][ $id ] );
		                    }

		                    if ( isset( $cart_item['_gravity_form_lead'][ $fname_id ] ) ) {
		                        $woo_flag                     = true;
		                        $_POSTED[ 'input_' . $fname_id ] = sanitize_text_field( $cart_item['_gravity_form_lead'][ $fname_id ] );
		                    }

		                    if ( isset( $cart_item['_gravity_form_lead'][ $lname_id ] ) ) {
		                        $_POSTED[ 'input_' . $lname_id ] = sanitize_text_field( $cart_item['_gravity_form_lead'][ $lname_id ] );
		                    }

		                    if ( isset( $cart_item['_gravity_form_lead'][ $email_id ] ) ) {
		                        $_POSTED[ 'input_' . $email_id ] = sanitize_email( $cart_item['_gravity_form_lead'][ $email_id ] );
		                    }

		                    if ( isset( $cart_item['_gravity_form_lead'][ $phone_id ] ) ) {
		                        $_POSTED[ 'input_' . $phone_id ] = sanitize_text_field( $cart_item['_gravity_form_lead'][ $phone_id ] );
		                    }

		                    if ( isset( $cart_item['_gravity_form_lead'][ $id ]['total_id'] ) ) {
		                        $get_total_id                  = absint( $cart_item['_gravity_form_lead'][ $id ]['total_id'] );
		                        $total_field_value             = floatval( $cart_item['_gravity_form_lead'][ $get_total_id ] );
		                        $_POSTED[ 'input_' . $get_total_id ] = $total_field_value;
		                    }

		                    break; // Only need first cart item
		                }
		            }
		        }

		        // Process appointment fields
		        if ( ! empty( $id ) && isset( $_POSTED[ 'input_' . $id ] ) ) {

		            gform_delete_meta( $entry_id, $id );
		            gform_update_meta( $entry_id, $id, $_POSTED[ 'input_' . $id ] );

		            $appointmentData = $_POSTED[ 'input_' . $id ];

		            // Sanitize date(s)
		            $date = isset( $_POSTED['apbgf_selected_dates'] ) && ! empty( $_POSTED['apbgf_selected_dates'] )
		                ? (array) $_POSTED['apbgf_selected_dates']
		                : ( isset( $appointmentData['date'] ) ? (array) $appointmentData['date'] : array() );

		            $date = array_map( 'sanitize_text_field', $date );

		            // Validate dates
		            $valid_dates = array();
		            foreach ( $date as $date_val ) {
		                $date_obj = DateTime::createFromFormat( 'Y-m-d', $date_val );
		                if ( $date_obj ) {
		                    $valid_dates[] = $date_obj->format( 'Y-m-d' );
		                }
		            }

		            $date_array_formatted = implode( ' - ', $valid_dates );

		            // Sanitize time
		            $time = isset( $appointmentData['time'] ) ? $appointmentData['time'] : '';
		            if ( is_array( $time ) ) {
		                $time = array_map( 'sanitize_text_field', $time );
		            } else {
		                $time = sanitize_text_field( $time );
		            }

		            // Slot
		            $slot = ! empty( $valid_dates ) && count( $valid_dates ) > 1 ? 1 : ( isset( $appointmentData['slot'] ) ? absint( $appointmentData['slot'] ) : 1 );

		            // Sanitize related entities
		            $location_id   = isset( $appointmentData['location'] ) ? absint( $appointmentData['location'] ) : 0;
		            $service_id    = isset( $appointmentData['service'] ) ? absint( $appointmentData['service'] ) : 0;
		            $staff_id      = isset( $appointmentData['staff'] ) ? absint( $appointmentData['staff'] ) : 0;

		            $location_name = $location_id ? sanitize_text_field( get_the_title( $location_id ) ) : '';
		            $service_name  = $service_id ? sanitize_text_field( get_the_title( $service_id ) ) : '';
		            $staff_name    = $staff_id ? sanitize_text_field( get_the_title( $staff_id ) ) : '';

		            $service_other = isset( $appointmentData['service_other'] ) ? sanitize_text_field( $appointmentData['service_other'] ) : '';

		            gform_update_meta( $entry_id, 'location_name', $location_name );
		            gform_update_meta( $entry_id, 'service_name', $service_name );
		            if ( ! empty( $service_other ) ) {
		                gform_update_meta( $entry_id, 'service_other', $service_other );
		            }
		            gform_update_meta( $entry_id, 'staff_name', $staff_name );

		            // Build post title safely
		            $post_title = $date_array_formatted . ' ' . ( is_array( $time ) ? implode( ', ', $time ) : $time );
		            $post_title = sanitize_text_field( $post_title );
					
					if ( !$woo_flag ) {
						$fname_id = isset( $form_settings['registration_field']['fname'] ) ? str_replace( '.', '_', $form_settings['registration_field']['fname'] ) : '';
						$lname_id = isset( $form_settings['registration_field']['lname'] ) ? str_replace( '.', '_', $form_settings['registration_field']['lname'] ) : '';
						$email_id = isset( $form_settings['registration_field']['email'] ) ? $form_settings['registration_field']['email'] : '';
						$phone_id = isset( $form_settings['registration_field']['phone'] ) ? $form_settings['registration_field']['phone'] : '';
					}	
		            // Build safe args
					if ( isset( $_POSTED['input_' . $fname_id] ) ) {
						$data['fname'] = $_POSTED['input_' . $fname_id];
					} else {
						$data['fname'] = '';
					}

					if ( isset( $_POSTED['input_' . $lname_id] ) ) {
						$data['lname'] = $_POSTED['input_' . $lname_id];
					} else {
						$data['lname'] = '';
					}

					if ( isset( $_POSTED['input_' . $email_id] ) ) {
						$data['email'] = $_POSTED['input_' . $email_id];
					} else {
						$data['email'] = '';
					}

					if ( isset( $_POSTED['input_' . $phone_id] ) ) {
						$data['phone'] = $_POSTED['input_' . $phone_id];
					} else {
						$data['phone'] = '';
					}
					$wp_user = APBGF_Customer::apbgf_create_customer( $data );

					$cost = isset($appointmentData['cost']) ? floatval($appointmentData['cost']) : 0;
		           
					$args = apply_filters(
		                'apbgf_add_appointment_args',
		                array(
		                    'post_title'  => $post_title,
		                    'post_type'   => 'apbgf-appointment',
		                    'post_status' => 'draft',
		                    'wp_error'    => true,
		                    'meta_input'  => array(
		                        'form_id'       => $form_id,
		                        'entry_id'      => $entry_id,
		                        'wp_user'       => absint( $wp_user ),
		                        'apbgf_user'    => sanitize_text_field( get_user_meta( $wp_user, 'apbgf_user', true ) ),
		                        'location_id'   => $location_id,
		                        'location_name' => $location_name,
		                        'service_id'    => $service_id,
		                        'service_name'  => $service_name,
		                        'service_other' => $service_other,
		                        'staff_id'      => $staff_id,
		                        'staff_name'    => $staff_name,
		                        'date'          => $valid_dates,
		                        'time'          => $time,
		                        'slot'          => $slot,
		                        'cost'          => floatval( $cost ),
		                        'status'        => ! empty( $payment_status ) && in_array( strtolower( $payment_status ), array( 'paid', 'completed' ), true )
		                            ? 'confirmed'
		                            : 'pending',
		                    ),
		                )
		            );

		            $appointment_id = wp_insert_post( $args );

		            if ( $appointment_id && ! is_wp_error( $appointment_id ) ) {
		                do_action( 'apbgf_created_appointment', $appointment_id );

		                if ( ! empty( $appointmentData['apbgf_booking_type'] ) ) {
		                    update_post_meta( $appointment_id, 'booking_type', sanitize_text_field( $appointmentData['apbgf_booking_type'] ) );
		                }

		                gform_update_meta( $entry_id, 'apbgf_appointment', $appointment_id );
		                APBGF_Email::send_notification( $appointment_id, 'template_8', 'staff' );
		                APBGF_Email::send_notification( $appointment_id, 'template_5', 'admin' );
		                if ( 'confirmed' === get_post_meta( $appointment_id, 'status', true ) ) {
		                    APBGF_Email::send_notification( $appointment_id, 'template_1', 'customer' );
		                }
		            }
		        }
		    }
		}


		public function register_appointment_posttype() {
			$labels = array(
				'name'                  => _x( 'Appointment', 'Post type general name', 'appointment-and-booking-for-gravity-forms' ),
				'singular_name'         => _x( 'Appointment', 'Post type singular name', 'appointment-and-booking-for-gravity-forms' ),
				'menu_name'             => _x( 'Appointment', 'Admin Menu text', 'appointment-and-booking-for-gravity-forms' ),
				'name_admin_bar'        => _x( 'Appointment', 'Add New on Toolbar', 'appointment-and-booking-for-gravity-forms' ),
				'add_new'               => __( 'Add Appointment', 'appointment-and-booking-for-gravity-forms' ),
				'add_new_item'          => __( 'Add New Appointment', 'appointment-and-booking-for-gravity-forms' ),
				'new_item'              => __( 'New Appointment', 'appointment-and-booking-for-gravity-forms' ),
				'edit_item'             => __( 'Edit Appointment', 'appointment-and-booking-for-gravity-forms' ),
				'view_item'             => __( 'View Appointment', 'appointment-and-booking-for-gravity-forms' ),
				'all_items'             => __( 'Appointments', 'appointment-and-booking-for-gravity-forms' ),
				'search_items'          => __( 'Search Appointment', 'appointment-and-booking-for-gravity-forms' ),
				'parent_item_colon'     => __( 'Parent Appointment:', 'appointment-and-booking-for-gravity-forms' ),
				'not_found'             => __( 'No Appointment found.', 'appointment-and-booking-for-gravity-forms' ),
				'not_found_in_trash'    => __( 'No Appointment found in Trash.', 'appointment-and-booking-for-gravity-forms' ),
				'featured_image'        => _x( 'Appointment Cover Image', 'Overrides the “Featured Image” phrase for this post type. Added in 4.3', 'appointment-and-booking-for-gravity-forms' ),
				'set_featured_image'    => _x( 'Set Appointment image', 'Overrides the “Set featured image” phrase for this post type. Added in 4.3', 'appointment-and-booking-for-gravity-forms' ),
				'remove_featured_image' => _x( 'Remove Appointment image', 'Overrides the “Remove featured image” phrase for this post type. Added in 4.3', 'appointment-and-booking-for-gravity-forms' ),
				'use_featured_image'    => _x( 'Use as Appointment image', 'Overrides the “Use as featured image” phrase for this post type. Added in 4.3', 'appointment-and-booking-for-gravity-forms' ),
				'archives'              => _x( 'Appointment archives', 'The post type archive label used in nav menus. Default “Post Archives”. Added in 4.4', 'appointment-and-booking-for-gravity-forms' ),
				'insert_into_item'      => _x( 'Insert into Appointment', 'Overrides the “Insert into post”/”Insert into page” phrase (used when inserting media into a post). Added in 4.4', 'appointment-and-booking-for-gravity-forms' ),
				'uploaded_to_this_item' => _x( 'Uploaded to this Appointment', 'Overrides the “Uploaded to this post”/”Uploaded to this page” phrase (used when viewing media attached to a post). Added in 4.4', 'appointment-and-booking-for-gravity-forms' ),
				'filter_items_list'     => _x( 'Filter Appointment list', 'Screen reader text for the filter links heading on the post type listing screen. Default “Filter posts list”/”Filter pages list”. Added in 4.4', 'appointment-and-booking-for-gravity-forms' ),
				'items_list_navigation' => _x( 'Appointment list navigation', 'Screen reader text for the pagination heading on the post type listing screen. Default “Posts list navigation”/”Pages list navigation”. Added in 4.4', 'appointment-and-booking-for-gravity-forms' ),
				'items_list'            => _x( 'Appointment list', 'Screen reader text for the items list heading on the post type listing screen. Default “Posts list”/”Pages list”. Added in 4.4', 'appointment-and-booking-for-gravity-forms' ),
			);

			// $show_in_menu = false;

			// if ( is_user_logged_in() ) {                
			// 	if ( current_user_can( 'apbgf-staff' ) && ! current_user_can( 'mange_options' ) ) {
			// 		$show_in_menu = true;
			// 		$labels['all_items'] = esc_html__( 'Appointment', 'appointment-and-booking-for-gravity-forms' );
			// 	} else {
			// 		$show_in_menu = 'appointment-and-booking-for-gravity-forms';
			// 	}
			// }

			$args = array(
				'labels'             => $labels,
				'public'             => false,
				'publicly_queryable' => false,
				'show_ui'            => true,
				'show_in_menu'       => 'appointment-and-booking-for-gravity-forms',
				'menu_icon'          => 'dashicons-calendar-alt',
				'show_in_rest'       => true,
				'query_var'          => true,
				'rewrite'            => array( 'slug' => 'apbgf-appointment' ),
				'capability_type'    => 'apbgf-appointment',
				// 'capabilities' => array(
				//  'create_posts' => false, // Removes support for the "Add New" function ( use 'do_not_allow' instead of false for multisite set ups )
				// ),
				'has_archive'        => false,
				'hierarchical'       => false,
				'supports'           => array( 'title' ),
				'menu_position'      => 0           
			);

			register_post_type( 'apbgf-appointment', $args );         
		}

		/*
		*  merging tags for the Notifications
		*/
		public function apbgf_merge_tags() {

			$merge_tags[] = array(
				'label' => esc_html__('GB Staff', 'appointment-and-booking-for-gravity-forms'),
				'tag'   => '{gb_staff}',
			);
		
			$merge_tags[] = array(
				'label' => esc_html__('GB Location', 'appointment-and-booking-for-gravity-forms'),
				'tag'   => '{gb_location}',
			);
		
			$merge_tags[] = array(
				'label' => esc_html__('GB Service', 'appointment-and-booking-for-gravity-forms'),
				'tag'   => '{gb_service}',
			);
		
			$merge_tags[] = array(
				'label' => esc_html__('GB Service Category', 'appointment-and-booking-for-gravity-forms'),
				'tag'   => '{gb_service_category}',
			);
			$merge_tags[] = array(
				'label' => esc_html__('GB Date', 'appointment-and-booking-for-gravity-forms'),
				'tag'   => '{gb_date}',
			);
			$merge_tags[] = array(
				'label' => esc_html__('GB Time', 'appointment-and-booking-for-gravity-forms'),
				'tag'   => '{gb_time}',
			);
			$merge_tags[] = array(
				'label' => esc_html__('GB Slot', 'appointment-and-booking-for-gravity-forms'),
				'tag'   => '{gb_slot}',
			);
			$merge_tags[] = array(
				'label' => esc_html__('GB Cost', 'appointment-and-booking-for-gravity-forms'),
				'tag'   => '{gb_cost}',
			);
		
			return $merge_tags;
		}

		/**
		 * Replacing custom merged tags with values
		 */
		public function apbgf_replace_merge_tags( $text, $form, $entry, $url_encode, $esc_html, $nl2br, $format ) {
			
			$apbgf_staff_tag = '{gb_staff}';
			$apbgf_location_tag = '{gb_location}';
			$apbgf_service_tag = '{gb_service}';
			$apbgf_service_category_tag = '{gb_service_category}';
			$apbgf_date_tag = '{gb_date}';
			$apbgf_time_tag = '{gb_time}';
			$apbgf_slot_tag = '{gb_slot}';
			$apbgf_cost_tag = '{gb_cost}';
		
			$field_id = '';
		
			$fields = GFAPI::get_fields_by_type( $form, array( 'apbgf_appointment_calendar' ), true );
			foreach ($fields as $field) {
				
				if ('apbgf_appointment_calendar' == $field->type ) {
					$field_id = $field->id;
					break;
				}
			}
		
			if (empty($field_id)) {
				return $text;
			}
		
			if ( strpos( $text, $apbgf_staff_tag ) != false ) {
				$staff = get_the_title($entry[ $field_id . '_staff' ]);
				$staff_label = esc_html__('Staff : ', 'appointment-and-booking-for-gravity-forms');
				$staff_value = $staff;
				$field_value = $staff_label . $staff_value;
				$text = str_replace( $apbgf_staff_tag, $field_value, $text );
			}
		
			if ( strpos( $text, $apbgf_location_tag ) != false ) {
				$location = get_the_title($entry[ $field_id . '_location' ]);
				$location_label = esc_html__('Location : ', 'appointment-and-booking-for-gravity-forms');
				$location_value = $location;
				$field_value = $location_label . $location_value;
				$text = str_replace( $apbgf_location_tag, $field_value, $text );
			}
			if ( strpos( $text, $apbgf_service_tag ) != false ) {
				$service = get_the_title($entry[ $field_id . '_service' ]);
				$service_label = esc_html__('Service : ', 'appointment-and-booking-for-gravity-forms');
				$service_value = $service;
				$field_value = $service_label . $service_value;
				$text = str_replace( $apbgf_service_tag, $field_value, $text );
			}
			if ( strpos( $text, $apbgf_service_category_tag ) != false ) {
				$service_category = get_the_title($entry[ $field_id . '_service_category' ]);

				$service_category_label = esc_html__('Service Category : ', 'appointment-and-booking-for-gravity-forms');
				$service_category_value = $service_category;
				$field_value = $service_category_label . $service_category_value;
				$text = str_replace( $apbgf_service_category_tag, $field_value, $text );
			}
			if ( strpos( $text, $apbgf_date_tag ) != false ) {
				$date = $entry[ $field_id . '_date' ];
				$date_label = esc_html__('Date : ', 'appointment-and-booking-for-gravity-forms');
				$date_value = $date;
				$field_value = $date_label . $date_value;
				$text = str_replace( $apbgf_date_tag, $field_value, $text );
			}
			if ( strpos( $text, $apbgf_time_tag ) != false ) {
				$time = $entry[ $field_id . '_time' ];
				$time_label = esc_html__('Time : ', 'appointment-and-booking-for-gravity-forms');
				$time_value = $time;
				$field_value = $time_label . $time_value;
				$text = str_replace( $apbgf_time_tag, $field_value, $text );
			}
			if ( strpos( $text, $apbgf_slot_tag ) != false ) {
				$slot = $entry[ $field_id . '_slot' ];
				$slot_label = esc_html__('Slot : ', 'appointment-and-booking-for-gravity-forms');
				$slot_value = $slot;
				$field_value = $slot_label . $slot_value;
				$text = str_replace( $apbgf_slot_tag, $field_value, $text );
			}
			if ( strpos( $text, $apbgf_cost_tag ) != false ) {
				$cost = $entry[ $field_id . '_cost' ];
				$cost_label = esc_html__('Cost : ', 'appointment-and-booking-for-gravity-forms');
				$cost_value = $cost;
				$field_value = $cost_label . $cost_value;
				$text = str_replace( $apbgf_cost_tag, $field_value, $text );
			}
			
			return $text;
		}



		/**
		 * Singleton Class Instatnce.
		 */
		public static function get_instance() {
			if ( null === self::$instance ) {
				self::$instance = new APBGF_Appointment();
			}

			return self::$instance;
		}
	}

	APBGF_Appointment::get_instance();
}
