# easy-hotel/2.0.2/admin/includes/classes/class.booking.php

Easy Hotel – Powerful Hotel Booking, version 2.0.2. 2,940 lines.

- Page: https://pluginprobe.com/plugins/easy-hotel/2.0.2/code/admin/includes/classes/class.booking.php
- Raw: https://pluginprobe.com/plugins/easy-hotel/2.0.2/raw/admin/includes/classes/class.booking.php
- Modified: 2026-06-15T17:21:30+00:00

Line numbers below start at 1. Link to a line or a range by appending a fragment to the
page URL, for example `https://pluginprobe.com/plugins/easy-hotel/2.0.2/code/admin/includes/classes/class.booking.php#L10-L20`.

```php
<?php
use SureCart\Support\Currency;
use SureCart\Models\Product;
use SureCart\Models\Price;
use SureCart\Models\LineItem;
use SureCart\Models\ProductMedia;
use SureCart\Models\Order;
use SureCart\Models\Checkout;
use SureCart\Models\Customer;
use SureCart\Models\Coupon;

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

class ESHB_Booking {

    private static $_instance = null;
    private $eshb_notice_printed = false;
	
	public static function instance() {

		if ( is_null( self::$_instance ) ) {
			self::$_instance = new self();
		}
		return self::$_instance;

	}

    public function __construct() {

		add_filter('litespeed_cacheable', [$this, 'disable_eshb_cache_from_cacheplugin'], 10, 1);

		if(!is_admin()){
			add_action( 'woocommerce_before_calculate_totals', [ $this, 'apply_custom_price_to_cart_item' ], 20, 1 );
			add_action( 'woocommerce_checkout_create_order_line_item', [ $this, 'save_custom_meta_to_order' ], 10, 4 );
			add_filter( 'woocommerce_get_item_data', [ $this, 'display_custom_meta_in_cart_and_order' ], 10, 2 );

			add_action(	'woocommerce_thankyou', [$this, 'create_woocommerce_booking_on_checkout'], 10, 1 );
			add_action(	'woocommerce_thankyou', [$this, 'capture_payment_after_checkout'], 20, 1 );
			add_filter(	'woocommerce_hidden_order_itemmeta', [$this, 'hide_meta_from_display'] );
			add_filter(	'woocommerce_order_item_get_formatted_meta_data', [$this, 'unset_specific_order_item_meta_data'], 10, 2 );
			add_action( 'woocommerce_cart_item_removed', [ $this, 'eshb_clear_cart_block_on_removal' ], 10, 2 );
			add_action( 'woocommerce_thankyou', [ $this, 'eshb_clear_session_cart_blocks_on_order' ], 5, 1 );
		}
		
		add_action(	'woocommerce_order_status_changed', [$this, 'update_booking_status_on_woocommerce_order_status_change'], 10, 4 );
		add_action(	'save_post_eshb_booking', [$this, 'update_woocommerce_order_status_on_booking_status_change'], 20, 3 );
		add_action(	'save_post_eshb_booking', [$this, 'send_booking_email_notification_for_booking_status'], 20, 3 );
		add_filter('woocommerce_payment_complete_order_status', [$this, 'filter_status_based_on_booking_meta'], 10, 2);
		
		add_action( "wp_ajax_nopriv_eshb_get_extra_services_charge", [$this, 'eshb_get_extra_services_charge'] );
        add_action( "wp_ajax_eshb_get_extra_services_charge", [$this, 'eshb_get_extra_services_charge'] );
        add_action( "wp_ajax_nopriv_eshb_get_booking_prices", [$this, 'eshb_get_booking_prices'] );
        add_action( "wp_ajax_eshb_get_booking_prices", [$this, 'eshb_get_booking_prices'] );
		add_action( "wp_ajax_nopriv_eshb_add_to_cart_reservation", [$this, 'eshb_add_to_cart_reservation'] );
		add_action( "wp_ajax_eshb_add_to_cart_reservation", [$this, 'eshb_add_to_cart_reservation'] );
		add_action( "wp_ajax_nopriv_eshb_send_reservation_request", [$this, 'eshb_send_reservation_request'] );
		add_action( "wp_ajax_eshb_send_reservation_request", [$this, 'eshb_send_reservation_request'] );
		add_action( 'wp_ajax_nopriv_eshb_get_accomodation_available_capacity_counts', [ $this, 'eshb_get_accomodation_available_capacity_counts' ] );
        add_action( 'wp_ajax_eshb_get_accomodation_available_capacity_counts', [ $this, 'eshb_get_accomodation_available_capacity_counts' ] );
		add_action( 'wp_ajax_nopriv_eshb_get_available_rooms_counts_data', [ $this, 'eshb_get_available_rooms_counts_data' ] );
        add_action( 'wp_ajax_eshb_get_available_rooms_counts_data', [ $this, 'eshb_get_available_rooms_counts_data' ] );
		add_action( 'wp_ajax_nopriv_eshb_get_cart_blocks', [ $this, 'eshb_get_cart_blocks_ajax' ] );
		add_action( 'wp_ajax_eshb_get_cart_blocks', [ $this, 'eshb_get_cart_blocks_ajax' ] );
		add_action( 'wp_ajax_nopriv_eshb_clear_cart_on_block_expiry', [ $this, 'eshb_clear_cart_on_block_expiry' ] );
		add_action( 'wp_ajax_eshb_clear_cart_on_block_expiry', [ $this, 'eshb_clear_cart_on_block_expiry' ] );
		add_action( 'wp_ajax_nopriv_eshb_check_my_session_blocks', [ $this, 'eshb_check_my_session_blocks' ] );
		add_action( 'wp_ajax_eshb_check_my_session_blocks', [ $this, 'eshb_check_my_session_blocks' ] );
		add_filter( 'eshb_get_disabled_dates_in_search', [ $this, 'eshb_add_blocked_dates_to_calendar' ], 10, 3 );
		// Inline notice: shortcode-based cart/checkout (block themes use JS injection instead)
		add_action( 'woocommerce_before_cart',          [ $this, 'eshb_render_cart_block_notice_inline' ] );
		add_action( 'woocommerce_before_checkout_form', [ $this, 'eshb_render_cart_block_notice_inline' ] );
		// Cart item remove via AJAX on checkout (NOTE: woocommerce_checkout_cart_item_quantity filter
		// is registered once at file load, not in the constructor — see bottom of file. Constructor
		// runs each time `new ESHB_Booking()` is called, which would duplicate the filter.)
		add_action( 'wp_ajax_nopriv_eshb_remove_cart_item', [ $this, 'eshb_remove_cart_item' ] );
		add_action( 'wp_ajax_eshb_remove_cart_item', [ $this, 'eshb_remove_cart_item' ] );
		add_action( 'eshb_before_availability_calendar', [ $this, 'eshb_render_calendar_legend' ], 10, 1 );

		add_action('rest_api_init', function() {
			register_rest_route('eshb/v1', '/booking-prices', [
				'methods'  => 'POST',
				'callback' => [ $this, 'eshb_get_booking_prices_rest' ], // class method
				'permission_callback' => function($request) {
					return true;
				},
				'args' => [
					'accomodationId' => [
						'required' => true,
						'sanitize_callback' => 'absint',
					],
					'startDate' => [
						'sanitize_callback' => 'sanitize_text_field',
					],
					'endDate' => [
						'sanitize_callback' => 'sanitize_text_field',
					],
					'startTime' => [
						'sanitize_callback' => 'sanitize_text_field',
					],
					'endTime' => [
						'sanitize_callback' => 'sanitize_text_field',
					],
					'roomQuantity' => [
						'sanitize_callback' => 'absint',
					],
					'extraBedQuantity' => [
						'sanitize_callback' => 'absint',
					],
					'adultQuantity' => [
						'sanitize_callback' => 'absint',
					],
					'childrenQuantity' => [
						'sanitize_callback' => 'absint',
					],
					'selectedServices' => [
						'sanitize_callback' => function($param) {
							return json_decode(sanitize_text_field($param), true);
						}
					],
					'nonce' => [
						'required' => true,
						'sanitize_callback' => 'sanitize_text_field',
					],
				],
			]);
		});

		
	}

	function disable_eshb_cache_from_cacheplugin($cacheable){
	     // Disable LSCache for accommodation single pages
        if( is_singular('eshb_accomodation') ){
            return false; // don't cache
        }

        // Never cache the Native Checkout / customer account pages: they are
        // per-visitor (reservation token + a freshly generated nonce baked
        // into the page). A shared cache would serve a stale nonce to other
        // visitors — which makes checkout fail for logged-out users (logged-in
        // users bypass the cache, so it "only works when logged in").
        if ( is_singular() ) {
            global $post;
            if ( $post instanceof WP_Post ) {
                $eshb_content = (string) $post->post_content;
                if ( has_shortcode( $eshb_content, 'eshb_native_checkout' ) || has_shortcode( $eshb_content, 'eshb_account' ) ) {
                    return false; // don't cache
                }
            }
        }

        return $cacheable;
	}
	
	public function update_product_price_by_id($product_id, $new_price) {
		// Update the regular price
		update_post_meta($product_id, '_regular_price', $new_price);
		
		// Update the price (current price)
		update_post_meta($product_id, '_price', $new_price);
		
		// Optional: if the product is on sale, update the sale price to match the new price
		//update_post_meta($product_id, '_sale_price', $new_price);
	
		// Clear WooCommerce product cache
		wc_delete_product_transients($product_id);
	}

	public function get_booked_dates($accomodation_id, $start_date = '', $end_date = '') {

		$single_day_booking = false;
		if($start_date == $end_date){
			$single_day_booking = true;
		}

		$booked_dates = [];
		$total_room_bookings_per_date = []; // Track room bookings per date
		$eshb_settings = get_option('eshb_settings', []);
	
		// Get total rooms allowed for this accommodation
		$accomodation_metas = get_post_meta($accomodation_id, 'eshb_accomodation_metaboxes', true);
		$allowed_total_rooms = isset($accomodation_metas['total_rooms']) ? intval($accomodation_metas['total_rooms']) : 0;
	
		// Find all bookings for this accommodation
		$bookings_args = [
			'post_type'      => 'eshb_booking',
			'posts_per_page' => -1,
			'post_status'    => ['publish', 'deposit-payment', 'pending', 'processing', 'on-hold', 'completed'],
			'fields' => 'ids',
		];
	
		$bookings = new WP_Query($bookings_args);
	
		if ($bookings->have_posts()) {
			while ($bookings->have_posts()) {
				$bookings->the_post();
				$meta_values = get_post_meta(get_the_ID(), 'eshb_booking_metaboxes', true);
				$booking_status = isset($meta_values['booking_status']) ? $meta_values['booking_status'] : '';

				$completed_booking_status_maps = array(
					'pending',
					'deposit-payment',
					'processing',
					'on-hold',
					'completed'
				); 

				// Ensure required keys exist
				if (is_array($meta_values) && in_array($booking_status, $completed_booking_status_maps) && isset($meta_values['booking_accomodation_id'], $meta_values['booking_start_date'], $meta_values['booking_end_date'])) {
					$booking_accomodation_id = intval($meta_values['booking_accomodation_id']);
					$booking_start_date = $meta_values['booking_start_date'];
					$booking_end_date = $meta_values['booking_end_date'];

					$booked_accomodation_ids = [];
                    $booking_accomodation_id = ESHB_Helper::get_main_post_id_for_translated($booking_accomodation_id);
	
					if ($booking_accomodation_id == $accomodation_id) {
						// Convert dates to DateTime objects
						$booking_start_date = new DateTime($booking_start_date);
						$booking_end_date = new DateTime($booking_end_date);

						// if($booking_end_date == $booking_end_date) {
						// 	$booking_end_date->modify('+1 day');
						// }

						while ($booking_start_date <= $booking_end_date) {
							
							$formatted_date = $booking_start_date->format('Y-m-d');

							if($meta_values['booking_end_date'] != $formatted_date){
								$booked_id = get_the_ID();
								$booking_metas = get_post_meta($booked_id, 'eshb_booking_metaboxes', true);
								$booked_room_quantity = isset($booking_metas['room_quantity']) ? intval($booking_metas['room_quantity']) : 0;
								
								
								// Track total booked rooms per date
								if (!isset($total_room_bookings_per_date[$formatted_date])) {
									$total_room_bookings_per_date[$formatted_date] = 0;
								}
								$total_room_bookings_per_date[$formatted_date] = $booked_room_quantity;
							}
							// Move to next day
							$booking_start_date->modify('+1 day');
						}
						
					}
				}
			}
		}

		if(!$single_day_booking){
			unset($total_room_bookings_per_date[$end_date]);
		}

		// Determine which dates should be disabled (fully booked)
		foreach ($total_room_bookings_per_date as $date => $total_booked_rooms) {

			 // skip this booking if slots hours available
			 // allow external plugins to modify available slots
				$available_slots = apply_filters(
					'eshb_available_slots_in_booked_dates_loop',
					false,
					$date,
					$total_booked_rooms,
					$accomodation_id
				);
			
                if($available_slots) {
                    $total_booked_rooms = 0;
                }
            

			if ($allowed_total_rooms <= $total_booked_rooms) {
				$date_obj = new DateTime($date);
				$booked_dates[] = $date_obj->format('Y, m, d');
			}
		}

	
		// Remove duplicate dates
		$booked_dates = array_unique($booked_dates);
	
		// Apply filter hook to allow external modifications
		$booked_dates = apply_filters('eshb_modify_booked_dates', $booked_dates, $accomodation_id);

	
		return $booked_dates;
	}

	public function get_holiday_dates($accomodation_id, $start_date = '', $end_date = '') {

		$eshb_settings = get_option('eshb_settings', []);

        $holidays = isset($eshb_settings['holidays']) ? $eshb_settings['holidays'] : [];
        
        $finally_holidays = [];

        if ( ! empty( $holidays ) ) {
            foreach ( $holidays as $holiday ) {
                $accommodation_ids = $holiday['accomodation-ids'] ?? [];
                $holiday_date      = $holiday['holiday-date'] ?? null;

			
                // Check if holiday is applicable for all or specific accommodation
                $is_applicable = empty($accommodation_ids) || (is_array($accommodation_ids) && in_array($accomodation_id, $accommodation_ids));

                if ( $is_applicable && $holiday_date ) {
                    if ( is_array($holiday_date) && isset($holiday_date['from'], $holiday_date['to']) ) {
                        $start = DateTime::createFromFormat('Y-m-d', $holiday_date['from']);
                        $end   = DateTime::createFromFormat('Y-m-d', $holiday_date['to']);
                        if ( $start && $end ) {
                            $end->modify('+1 day'); // Include end date
                            $interval  = new DateInterval('P1D');
                            $dateRange = new DatePeriod($start, $interval, $end);

                            foreach ( $dateRange as $date ) {
                                $finally_holidays[] = $date->format('Y-m-d');
                            }
                        }
                    } else {
                        $finally_holidays[] = $holiday_date;
                    }
                }
            }
        }

		return $finally_holidays;
	}

	public function get_holiday_dates_in_date_ranges($accomodation_id, $start_date, $end_date){

		$overlap = [];
		if(!empty($accomodation_id)){
			$holiday_dates = $this->get_holiday_dates($accomodation_id, $start_date, $end_date);
			$overlap = [];
			// Generate all dates in the range
			$range_dates = [];
			$current_date = new DateTime($start_date);
			$end_date_obj = new DateTime($end_date);
		
			while ($current_date <= $end_date_obj) {
				$range_dates[] = $current_date->format('Y-m-d');
				$current_date->modify('+1 day');
			}
		
			// Check for overlap
			$overlap = array_intersect($range_dates, $holiday_dates);
		}
		return $overlap;
	}

	public function get_actual_booked_dates_in_date_ranges($accomodation_id, $start_date, $end_date){

		$booked_dates = $this->get_booked_dates($accomodation_id, $start_date, $end_date); // retun arary like ['2025, 01, 27', '2025, 01, 28', '2025, 01, 13']

		// Format booked dates to 'Y-m-d' for comparison
		$booked_dates = array_map(function($date) {
			return DateTime::createFromFormat('Y, m, d', $date)->format('Y-m-d');
		}, $booked_dates);
	
		// Generate all dates in the range
		$range_dates = [];
		$current_date = new DateTime($start_date);
		$end_date_obj = new DateTime($end_date);
	
		while ($current_date <= $end_date_obj) {
			$range_dates[] = $current_date->format('Y-m-d');
			$current_date->modify('+1 day');
		}

		$single_day_booking = false;
		if($start_date == $end_date){
			$single_day_booking = true;
		}

		if(!$single_day_booking){
			array_pop($range_dates); // Remove the last date if it's a range booking
		}
	
		// Check for overlap
		$overlap = array_intersect($range_dates, $booked_dates);
		
		return $overlap;

	}

	public function save_booking_request($booking_args = array(), $customer_args = array()) {
		$defaults = array(
			'booking_accomodation_id'   => '',
			'booking_start_date'        => '',
			'booking_end_date'          => '',
			'room_quantity'     => 1,
			'extra_bed_quantity'=> 0,
			'adult_quantity'    => 1,
			'children_quantity' => 0,
			'details_html'      => '',
			'extra_services'    => array(),
			'extra_services_html' => '',
			'booking_status'	=> 'pending'
		);
		
		// Merge with default values
		$booking_args = wp_parse_args($booking_args, $defaults);
	
		$accomodation_id = $booking_args['booking_accomodation_id'];

		if(!empty($accomodation_id)){

			$start_date = $booking_args['booking_start_date'];
			$end_date = $booking_args['booking_end_date'];

			// Insert the post
			$post_id = wp_insert_post(array(
				'post_type'   => 'eshb_booking_request',
				'post_title'  => 'Booking request for ' . $start_date . ' - ' . $end_date,
				'post_status' => 'publish',
				'meta_input'  => array(
					'eshb_booking_request_metaboxes' => $booking_args,
					'eshb_booking_request_customer_metaboxes' => $customer_args,
				)
			));

			// Check if the post was inserted successfully
			if (!is_wp_error($post_id)) {
				// Update the post title to include the post ID

				$accomodation_title = get_the_title($accomodation_id);

				wp_update_post(array(
					'ID'         => $post_id,
					'post_title' => 'Booking request #' . $post_id . ' for: ' . $accomodation_title,
					'post_status' => 'publish' // Update status to 'publish'
				));
			}

		}
		
	}
	
	public function eshb_send_reservation_request(){

		// Verify nonce for security
		if (!isset($_POST['nonce']) || !wp_verify_nonce( sanitize_text_field(wp_unslash($_POST['nonce'])), ESHB_Helper::generate_secure_nonce_action('eshb_global_nonce_action'))) {

			$error = array(
				'code' => 'invalid_nonce', 
				'message' => __('invalid_nonce', 'easy-hotel')
			);
			
			wp_send_json_error([
				'error' => $error,
			]);

			die();
		}

		
		if(isset($_POST['accomodationId']) && !empty($_POST['accomodationId'])){
			
			$hotel_core = new ESHB_Core();
			$customer = !empty($_POST['customerInfo']) ? map_deep( sanitize_text_field( wp_unslash($_POST['customerInfo'])), 'sanitize_text_field' ) : [];
			$accomodation_id = isset( $_POST['accomodationId'] ) ? (int) sanitize_text_field( wp_unslash($_POST['accomodationId']) ) : '';
			$today_date = esc_html(gmdate('Y-m-d')); // Get today's date
			$date = new DateTime($today_date); // Create a DateTime object from today's date
			$date->modify('+1 day'); // Add one day
			$tomorrow = $date->format('Y-m-d'); // Get the new date in 'Y-m-d' format
			$start_date = isset( $_POST['startDate'] ) ? sanitize_text_field( wp_unslash($_POST['startDate']) ) : $today_date;
			$end_date = isset( $_POST['endDate'] ) ? sanitize_text_field( wp_unslash($_POST['endDate']) ) : $tomorrow;
			$start_time = isset( $_POST['startTime'] ) ? sanitize_text_field( wp_unslash($_POST['startTime']) ) : '';
			$end_time = isset( $_POST['endTime'] ) ? sanitize_text_field( wp_unslash($_POST['endTime']) ) : '';
			$start_day_name = $start_date ? strtolower(gmdate('l', strtotime($start_date))) : '';
			$accomodation_metaboxes = get_post_meta($accomodation_id, 'eshb_accomodation_metaboxes', true);
			$eshb_settings = get_option( 'eshb_settings', [] );
			$string_booking_success_msg = isset($eshb_settings['string_booking_request_success_msg']) && !empty($eshb_settings['string_booking_request_success_msg']) ? $eshb_settings['string_booking_request_success_msg'] : 'Booking request has been sent successfully.';
			$string_booking_failed_msg = isset($eshb_settings['string_booking_request_failed_msg']) && !empty($eshb_settings['string_booking_request_failed_msg']) ? $eshb_settings['string_booking_request_failed_msg'] : 'Ops! Booking request can\'t be sent.';
			$string_already_booked_msg = isset($eshb_settings['string_already_booked_msg']) && !empty($eshb_settings['string_already_booked_msg']) ? $eshb_settings['string_already_booked_msg'] : 'Ops! The date range is already booked:';
			$room_visibility = in_array('rooms', $eshb_settings['booking-form-fields']) ? true : false;
			$adult_visibility = in_array('adults', $eshb_settings['booking-form-fields']) ? true : false;
			$childrens_visibility = in_array('childrens', $eshb_settings['booking-form-fields']) ? true : false;
			$extra_beds_visibility = in_array('extra_beds', $eshb_settings['booking-form-fields']) ? true : false;

			$eshb_week_settings = [
				'string_check_in_day_error_msg' => 'Only allowed check in day is',
				'eshb_booking_allowed_check_in_day' => 'all',
			];
			$eshb_week_settings = apply_filters( 'eshb_week_settings', $eshb_week_settings );
			$allowed_check_in_day = apply_filters( 'eshb_booking_allowed_check_in_day', 'all', $accomodation_id, $accomodation_metaboxes );
			$string_check_in_day_error_msg = !empty($eshb_week_settings['string_check_in_day_error_msg']) ? $eshb_week_settings['string_check_in_day_error_msg'] : 'Only allowed check in day is : ';

			
			// Min Max Booking Configurations
			$min_max_settings = [
				'required_min_nights' => '',
				'required_max_nights' => '',
				'is_global_source_for_min_max' => true,
			];
			$min_max_settings = apply_filters( 'eshb_min_max_settings', $min_max_settings, $accomodation_id, $accomodation_metaboxes );
			$required_min_nights = isset($min_max_settings['required_min_nights']) ? $min_max_settings['required_min_nights'] : '';
			$required_max_nights = isset($min_max_settings['required_max_nights']) ? $min_max_settings['required_max_nights'] : '';
			$string_required_minimum_nights_msg = esc_html__( 'Ops! This Reservation has been failed. Requried Minumum', 'easy-hotel' );
			$string_required_maximum_nights_msg = esc_html__( 'Ops! This Reservation has been failed. Requried Maximum', 'easy-hotel' );

			$min_stay_night_by_session = ESHB_Helper::get_eshb_min_stay_night_by_session($accomodation_id, $start_date, $end_date);
			
			// get booked dates in the range
			$actual_booked_dates = $this->get_actual_booked_dates_in_date_ranges($accomodation_id, $start_date, $end_date);

			if(!empty($actual_booked_dates)){

				$booked_dates_str = implode( ', ', array_map( 'esc_html', $actual_booked_dates ) );

				$error_message = sprintf(
					/* translators: 1: already booked message text, 2: list of booked dates */
					esc_html__( '%1$s %2$s', 'easy-hotel' ),
					esc_html( $string_already_booked_msg ),
					$booked_dates_str
				);

				$error = array(
					'code'    => 'already_booked',
					'message' => $error_message,
				);

				wp_send_json_error([
					'error' => $error,
					'booked_dates' => implode(', ', $actual_booked_dates),
				]);

				wp_die();

			}

			// check rooms capacity
			if(isset($_POST['roomQuantity']) && !empty($_POST['roomQuantity'])){
				$roomQuantity = isset( $_POST['roomQuantity'] ) ? (int) sanitize_text_field( wp_unslash($_POST['roomQuantity'] ) ) : 1;
				
				$availableRoom = $this->get_available_room_count_by_date_range($accomodation_id, $start_date, $end_date);

				if($roomQuantity > $availableRoom){
					$error = array(
						'code'    => 'room_capacity_not_enough',
						'message' => sprintf(
							/* translators: %s: number of available rooms */
							esc_html__( 'Selected room is not available. Available room: %s', 'easy-hotel' ),
							esc_html( $availableRoom )
						),
					);

					wp_send_json_error([
						'error' => $error,
					]);
				}
				
			}


			// Validate check-in day
			if($allowed_check_in_day != 'all' && $start_day_name != '' && !empty($allowed_check_in_day) && strpos($allowed_check_in_day, $start_day_name) === false){
				$error = array(
					'code'    => 'check_in_day_error',
					'message' => sprintf(
						/* translators: %s: allowed check-in day */
						esc_html__( '%1$s %1$s', 'easy-hotel' ),
						esc_html( $string_check_in_day_error_msg ),
						esc_html( $allowed_check_in_day )
					),
				);

				wp_send_json_error([
					'error' => $error,
				]);
			}

			$start = new DateTime($start_date);
			$end = new DateTime($end_date);
			$interval = $start->diff($end);
			$days_count = $interval->days;
			$room_quantity = isset( $_POST['roomQuantity'] ) ? (int) sanitize_text_field( wp_unslash($_POST['roomQuantity'] ) ) : 1;
			$extra_bed_quantity = isset( $_POST['extraBedQuantity'] ) ? (int) sanitize_text_field( wp_unslash($_POST['extraBedQuantity'] ) ) : 0;
			$adult_quantity = isset( $_POST['adultQuantity'] ) ? (int) sanitize_text_field( wp_unslash($_POST['adultQuantity'] ) ) : 1;
			$children_quantity = isset( $_POST['childrenQuantity'] ) ? (int) sanitize_text_field( wp_unslash($_POST['childrenQuantity'] ) ) : 0;
			$total_guest_quantity = $adult_quantity + $children_quantity;

			$selected_services = [];
			if(isset($_POST['selectedServices']) && !empty($_POST['selectedServices'])){

				$selected_services = sanitize_text_field(wp_unslash($_POST['selectedServices']));
				$selected_services = json_decode($selected_services, true);
				
			}


			if(!empty($allowed_check_in_day) && $allowed_check_in_day != 'all'){
				$days_count = 1;
			}

			// validate min stay night by session
			if(class_exists('ESHB_ADVANCED_PRICING') && !empty($min_stay_night_by_session) && $days_count < $min_stay_night_by_session){
				$error = array(
					'code'    => 'min_stay_night_by_session',
					'message' => sprintf(
						/* translators: 1: minimum nights message text, 2: required minimum nights */
						esc_html__( '%1$s %2$s nights!', 'easy-hotel' ),
						esc_html( $string_required_minimum_nights_msg ),
						esc_html( $min_stay_night_by_session )
					),
				);
				wp_send_json_error([
					'error' => $error,
				]);
			}
			
			// validate minimum nights
			if(!empty($required_min_nights) && $days_count < $required_min_nights){
				$error = array(
					'code'    => 'required_min_nights',
					'message' => sprintf(
						/* translators: 1: minimum nights message text, 2: required minimum nights */
						esc_html__( '%1$s %2$s nights!', 'easy-hotel' ),
						esc_html( $string_required_minimum_nights_msg ),
						esc_html( $required_min_nights )
					),
				);

				wp_send_json_error([
					'error' => $error,
				]);
			}
			if(!empty($required_max_nights) && $days_count > $required_max_nights){
				$error = array(
					'code'    => 'required_max_nights',
					'message' => sprintf(
						/* translators: 1: maximum nights message text, 2: required maximum nights */
						esc_html__( '%1$s %2$s nights allowed!', 'easy-hotel' ),
						esc_html( $string_required_maximum_nights_msg ),
						esc_html( $required_max_nights )
					),
				);

				wp_send_json_error([
					'error' => $error,
				]);
			}


			

			if (get_post_type($accomodation_id) === 'eshb_accomodation') {

				$details = [];

				if ($room_visibility && $room_quantity > 0) {
					$details[] = 'Room: ' . $room_quantity;
				}
				if ($extra_beds_visibility && $extra_bed_quantity > 0) {
					$details[] = 'Extra Bed: ' . $extra_bed_quantity;
				}
				if ($adult_visibility && $adult_quantity > 0) {
					$details[] = 'Adult: ' . $adult_quantity;
				}
				if ($childrens_visibility && $children_quantity > 0) {
					$details[] = 'Children: ' . $children_quantity;
				}

				$details_html = implode(', ', $details);

				$extra_service_titles = [];
				$extra_services_html = '';
				
				if(!empty($selected_services) && is_array($selected_services) && count($selected_services) > 0 ){
				
					foreach ($selected_services as $service) {
		
						$service_id = $service['id'];

						$service_quantity = $service['quantity'];

						if(!empty($service_quantity)){
							$eshb_service_metaboxes = get_post_meta($service_id, 'eshb_service_metaboxes', true);

							$charge_type = $eshb_service_metaboxes['service_charge_type'];

							$service_title = get_the_title($service_id) . ' For ' . $service_quantity . ' ' .  ucfirst(strtolower($charge_type));

							if(!$room_visibility && $charge_type == 'room'){
								$service_title = get_the_title($service_id);
							}
						}else{
							$service_title = get_the_title($service_id);
						}

						array_push($extra_service_titles, $service_title);
		
					}
					$extra_services_html = implode(", ",$extra_service_titles);
				}
				

				$pricing = $this->calculate_booking_pricing($accomodation_id, $start_date, $end_date, $room_quantity, $extra_bed_quantity, $adult_quantity, $children_quantity, $selected_services, true, $start_time, $end_time);

				$base_price = $pricing['basePrice'];
				$extra_services_charge = $pricing['extraServicesPrice'];
				$extra_bed_price= $pricing['extraBedPrice'];
				$subtotal_price = $pricing['subtotalPrice'];
				$total_price = $pricing['totalPrice'];

				$dates = date_i18n( get_option('date_format'), strtotime( $start_date ) ) .' - '. date_i18n( get_option('date_format'), strtotime( $end_date ) );
				if($start_date == $end_date){
					$dates = date_i18n( get_option('date_format'), strtotime( $start_date ) );
				}

				
				$times = '';
				if(!empty($start_time) && !empty($end_time)) {
					// Get WP formatted time (according to Settings > General > Time Format)
					$formated_start_timestamp = strtotime( $start_time );
					$formated_end_timestamp = strtotime( $end_time );
					$wp_time_format = get_option( 'time_format' ); // WP settings
					$formatted_start_time = wp_date( $wp_time_format, $formated_start_timestamp );
					$formatted_end_time = wp_date( $wp_time_format, $formated_end_timestamp );
					$times = $formatted_start_time . ' - ' . $formatted_end_time;
				}


				$accomodation_title = get_the_title($accomodation_id);

				$customer_name = $customer['name'];
				$customer_email = $customer['email'];
				$customer_phone = $customer['phone'];
				$customer_message = $customer['message'];

				$admin_email = get_option('admin_email');
				$recipent_email = $eshb_settings['recipent_email'];
				$recipent_email = empty($recipent_email) ? $admin_email : $recipent_email;
				$from_name = wp_parse_url(get_site_url(), PHP_URL_HOST);
				
				$subject = __('Booking Request!', 'easy-hotel');

				$message = '';
				$message .= '<div>';
				$message .= '<h2>Great news!</h2><p>You have a new booking request.</p>';
				$message .= '<h3>Customer  Details</h3>';
				$message .= '<table style="text-align:left;">';
				$message .= '<tr><th>Name: ' . $customer_name . '</th></tr>';
				$message .= '<tr><th>Email: ' . $customer_email . '</th></tr>';
				$message .= '<tr><th>Phone: ' . $customer_phone . '</th></tr>';
				$message .= '</table>';
				$message .= '<h3>Booking  Details</h3>';
				$message .= '<table style="text-align:left;">';
				$message .= '<tr><th>Accomodation: ' . $accomodation_title . '</th></tr>';
				$message .= '<tr><th>Date: ' . date_i18n( get_option('date_format'), strtotime( $start_date ) ) .' - '. date_i18n( get_option('date_format'), strtotime( $end_date ) ) . '</th></tr>';
				
				if(!empty($times)) {
					$message .= '<tr><th>Times: ' . $times . '</th></tr>';
				}

				$message .= '<tr><th>Details: ' . $details_html . '</th></tr>';

				if(!empty($extra_services_html)){
					$message .= '<tr><th>Exra Services: ' . $extra_services_html . '</th></tr>';
				}

				$message .= '</table>';
				$message .= '<h5>Message:</h5><p>'.$customer_message.'</p>';
				$message .= '</div>';

				// Prepare the data array to store in post meta
				$form_data = [
					'booking_status' => 'processing',
					'booking_accomodation_id' => $accomodation_id,
					'total_price' => $total_price,
					'subtotal_price' => $subtotal_price,
					'base_price' => $base_price,
					'extra_service_price' => $extra_services_charge,
					'extra_bed_price' => $extra_bed_price,
					'booking_start_date' => $start_date,
					'booking_end_date' => $end_date,
					'booking_start_time' => $start_time,
					'booking_end_time' => $end_time,
					'dates' => $dates,
					'room_quantity' => $room_quantity,
					'extra_bed_quantity' => $extra_bed_quantity,
					'adult_quantity' => $adult_quantity,
					'children_quantity' => $children_quantity,
					'extra_services' => $selected_services,
					'details_html' => $details_html,
					'extra_services_html' => $extra_services_html,
					'customer' => $customer
				];

				if(!empty($start_time)) {
					$form_data['start_time'] = $start_time;
				}

				if(!empty($end_time)) {
					$form_data['end_time'] = $end_time;
				}

				if(!empty($times)) {
					$form_data['times'] = $times;
				}

				// Insert the post
				$post_id = wp_insert_post(array(
					'post_type'   => 'eshb_booking',
					'post_title'  => 'Booking for ' . $start_date . ' - ' . $end_date,
					'post_status' => 'publish',
					'meta_input'  => array(
						'eshb_booking_metaboxes' => $form_data
					)
				));
		
				// Check if the post was inserted successfully
				
				if (!is_wp_error($post_id)) {

					// Update the post title to include the post ID
					wp_update_post(array(
						'ID'         => $post_id,
						'post_title' => 'Booking #' . $post_id . ' for: ' . $accomodation_title,
						'post_status' => 'publish' // Update status to 'publish'
					));
					
					// Update Available Rooms Count For This Accomodation
					$accomodation_metaboxes = get_post_meta( $accomodation_id, 'eshb_accomodation_metaboxes', true );
					$total_rooms = !empty($accomodation_metaboxes['total_rooms']) ? floatval($accomodation_metaboxes['total_rooms']) : 1;
					$current_available_rooms = !empty($accomodation_metaboxes['available_rooms']) ? floatval($accomodation_metaboxes['available_rooms']) : 0;

					if(!empty($current_available_rooms)){
						$available_rooms = $current_available_rooms - floatval($room_quantity);
					}else{
						$available_rooms = $total_rooms - floatval($room_quantity);
					}
					
					$accomodation_metaboxes['available_rooms'] = $available_rooms;
					update_post_meta($accomodation_id, 'eshb_accomodation_metaboxes', $accomodation_metaboxes);
					
				}
				
				$save_booking = $this->save_booking_request($form_data, $customer);
				$send_email = $hotel_core->eshb_send_html_email($recipent_email, $subject, $message, $from_name, $customer_email);
				
				if ( $send_email ) {

					// Return success response
					wp_send_json_success([
						'message' => esc_html( $string_booking_success_msg ),
						'admin_email' => esc_html( $admin_email ),
					]);

				} else {
					$error = array(
						'code'    => 'email_failed',
						'message' => esc_html( $string_booking_failed_msg ),
					);

					wp_send_json_error([
						'error' => $error,
					]);
				}

			}else{
				$error = array(
					'code'    => 'accomodation_post_type_not_found',
					'message' => esc_html( $string_booking_failed_msg ),
				);

				wp_send_json_error([
					'error' => $error,
				]);
			}
			wp_die();
		}
			
	}

	public function apply_custom_price_to_cart_item($cart) {

		// Early return for admin requests (except AJAX)
		if (is_admin() && !defined('DOING_AJAX')) {
			return;
		}

		// Use the passed cart object if valid, otherwise fallback
		if (!$cart || !is_object($cart) || !method_exists($cart, 'get_cart')) {
			$cart = WC()->cart;
			if (!$cart || !is_object($cart) || !method_exists($cart, 'get_cart')) {
				return;
			}
		}
		
		$redirect_added = false;

		foreach ($cart->get_cart() as $cart_item_key => $cart_item) {
			if (empty($cart_item['total_price']) || $cart_item['total_price'] <= 0) {
				continue;
			}
			if (isset($cart_item['data']) && is_object($cart_item['data'])) {
				$cart_item['data']->set_price($cart_item['total_price']);
			}
		}
	}

	private function add_currency_redirect() {
		static $redirect_added = false;
		if ($redirect_added) {
			return;
		}
		add_action('wp_footer', function() {
			echo '<script>if(typeof window.eshb_currency_redirect==="undefined"){window.eshb_currency_redirect=true;window.location.href="' . esc_url(get_permalink(get_the_ID())) . '";}</script>';
		});
		$redirect_added = true;
	}

	public function save_custom_meta_to_order($item, $cart_item_key, $values, $order) {

		if (isset($values['accomodation_id'])) {
			$item->add_meta_data('Accomodation ID', $values['accomodation_id'], true);
		} 

		if (isset($values['total_price'])) {
			$item->add_meta_data('Total Price', $values['total_price'], true);
		}

		if (isset($values['subtotal_price'])) {
			$item->add_meta_data('Subtotal Price', $values['subtotal_price'], true);
		}

		if (isset($values['base_price'])) {
			$item->add_meta_data('Base Price', $values['base_price'], true);
		}

		if (isset($values['extra_services_charge'])) {
			$item->add_meta_data('Extra Services Charge', $values['extra_services_charge'], true);
		}

		if (isset($values['extra_bed_price'])) {
			$item->add_meta_data('Extra Bed Price', $values['extra_bed_price'], true);
		}

		if(class_exists('ESHB_CURRENCY_WOO_FUNCTIONS')){
			$currency_functions = new ESHB_CURRENCY_WOO_FUNCTIONS();

			if (isset($values['total_price'])) {
				$item->add_meta_data('Total Price', $currency_functions->apply_custom_currency_rate($values['total_price']), true);
			}

			if (isset($values['subtotal_price'])) {
				$item->add_meta_data('Subtotal Price', $currency_functions->apply_custom_currency_rate($values['subtotal_price']), true);
			}
	
			if (isset($values['base_price'])) {
				$item->add_meta_data('Base Price', $currency_functions->apply_custom_currency_rate($values['base_price']), true);
			}
	
			if (isset($values['extra_services_charge'])) {
				$item->add_meta_data('Extra Services Charge', $currency_functions->apply_custom_currency_rate($values['extra_services_charge']), true);
			}
	
			if (isset($values['extra_bed_price'])) {
				$item->add_meta_data('Extra Bed Price', $currency_functions->apply_custom_currency_rate($values['extra_bed_price']), true);
			}
		}

		if (isset($values['room_quantity'])) {
			$item->add_meta_data('Rooms', $values['room_quantity'], true);
		} 

		if (isset($values['extra_bed_quantity'])) {
			$item->add_meta_data('Extra Bed', $values['extra_bed_quantity'], true);
		} 

		if (isset($values['adult_quantity'])) {
			$item->add_meta_data('Adults', $values['adult_quantity'], true);
		} 

		if (isset($values['children_quantity'])) {
			$item->add_meta_data('Children', $values['children_quantity'], true);
		}

		if (isset($values['start_date'])) {
			$item->add_meta_data('Start Date', $values['start_date'], true);
		} 

		if (isset($values['end_date'])) {
			$item->add_meta_data('End Date', $values['end_date'], true);
		} 
	
		if (isset($values['dates'])) {
			$item->add_meta_data('Date', $values['dates'], true);
		} 

		if (isset($values['start_time'])) {
			$item->add_meta_data('Start Time', $values['start_time'], true);
		} 

		if (isset($values['end_time'])) {
			$item->add_meta_data('End Time', $values['end_time'], true);
		}

		if (!empty($values['times'])) {
			$item->add_meta_data('Time', $values['times'], true);
		} 

		if (isset($values['details_html'])) {
			$item->add_meta_data('Details', $values['details_html'], true);
		} 

		if (isset($values['extra_services'])) {
			$item->add_meta_data('Extra Services IDs', $values['extra_services'], true);
		} 

		if (isset($values['extra_services_html'])) {
			$item->add_meta_data('Extra Services', $values['extra_services_html'], true);
		} 

	}
	
	public function capture_payment_after_checkout($order_id){
		// capture payment
		ESHB_Helper::eshb_capture_payment($order_id);
	}
	public function create_woocommerce_booking_on_checkout($order_id){

		if (!$order_id) {
			// error_log("Error: Missing order ID.");
			return;
		}
	
		// Get the order object
		$order = wc_get_order($order_id);
	
		if (!$order) {
			// error_log("Error: Invalid order ID: $order_id");
			return;
		}
		
		$eshb_settings = get_option('eshb_settings', []);
		
		// Get the order object
		$order = wc_get_order($order_id);
		$order_status = $order->get_status();
		$booking_status = $order_status;

		if ( $order && $order->is_paid() && $order->get_status() !== 'completed' && isset($eshb_settings['booking-auto-approval']) && $eshb_settings['booking-auto-approval'] == true) {
			$order->update_status('completed', 'Payment successful, status updated via code.');
			$booking_status = 'completed';
		}
		
		$first_name = $order->get_billing_first_name();
		$last_name = $order->get_billing_last_name();
		$customer_name = trim($first_name . ' ' . $last_name); // Concatenate first and last name
		$customer_email = $order->get_billing_email(); // Get customer email
		$customer_phone = $order->get_billing_phone(); // Get customer phone number

		// Check if the booking post has already been created
		if (get_post_meta($order_id, '_booking_post_created', true)) {
			return; // Exit if the booking post has already been created
		}
		
		// Loop through order items
		foreach ($order->get_items() as $item_id => $item) {

			// Retrieve meta data saved in the order item
			$accomodation_id = $item->get_meta('Accomodation ID');
			$accomodation_title = get_the_title( $accomodation_id );
			$room_quantity = $item->get_meta('Rooms');
			$extra_bed_quantity = $item->get_meta('Extra Bed');
			$adult_quantity = $item->get_meta('Adults');
			$children_quantity = $item->get_meta('Children');
			$start_date = $item->get_meta('Start Date');
			$end_date = $item->get_meta('End Date');
			$dates = $item->get_meta('Date');
			$times = $item->get_meta('Time');
			$start_time = $item->get_meta('Start Time');
			$end_time = $item->get_meta('End Time');
			$details_html = $item->get_meta('Details');
			$extra_services = $item->get_meta('Extra Services IDs');
			$extra_services_html = $item->get_meta('Extra Services');
			$base_price = $item->get_meta('Base Price');
			$extra_services_charge = $item->get_meta('Extra Service Price');
			$extra_bed_price = $item->get_meta('Extra Bed Price');
			$total_without_discount = $item->get_meta('Subtotal Price');
			$total_price = $item->get_meta('Total Price');
	
			// Prepare the data array to store in post meta
			$cart_item_data = [
				'booking_status' => $booking_status,
				'order_id' => $order_id,
				'booking_accomodation_id' => $accomodation_id,
				'subtotal_price' => $order->get_subtotal(),
				'total_price' => $total_price,
				'total_paid' => 0,
				'base_price' => $base_price,
				'extra_service_price' => $extra_services_charge,
				'extra_bed_price' => $extra_bed_price,
				'booking_start_date' => $start_date,
				'booking_end_date' => $end_date,
				'booking_start_time' => !empty($start_time) ? $start_time : '10:00',
				'booking_end_time' => !empty($end_time) ? $end_time : '22:00',
				'dates' => $dates,
				'room_quantity' => $room_quantity,
				'extra_bed_quantity' => $extra_bed_quantity,
				'adult_quantity' => $adult_quantity,
				'children_quantity' => $children_quantity,
				'extra_services' => $extra_services,
				'start_time' => !empty($start_time) ? $start_time : '10:00',
				'end_time' => !empty($end_time) ? $end_time : '22:00',
				'times' => $times,
				'details_html' => $details_html,
				'extra_services_html' => $extra_services_html,
			];

			// filter for $cart_item_data;
			$cart_item_data = apply_filters( 'on_booking_cart_item_data', $cart_item_data );
			
			// Insert the booking
			if($accomodation_id && !empty($accomodation_id)) {
				ESHB_Helper::eshb_insert_booking($order_id, $booking_status, $cart_item_data);
			}
			
			
		}

	}

	public function display_custom_meta_in_cart_and_order($item_data, $cart_item) {

		if (!empty($cart_item['discount']) && is_cart()) {
			$discount = $cart_item['discount'];
			$currency_symbol = $cart_item['currency_symbol'];

			$item_data[] = array(
				'key' => __('Save', 'easy-hotel'),
				'value' => wc_price($discount)
			);
		}

		if (isset($cart_item['dates'])) {

			$dates = $cart_item['dates'];

			$item_data[] = array(
				'key' => __('Date', 'easy-hotel'),
				'value' => esc_html( $dates )
			);
		}

		if (!empty($cart_item['times'])) {

			$times = $cart_item['times'];

			$item_data[] = array(
				'key' => __('Time', 'easy-hotel'),
				'value' => esc_html( $times )
			);
		}


		if (!empty($cart_item['night'])) {

			$night = $cart_item['night'];
			$night_label = esc_html__('Night', 'easy-hotel');
			if ($night > 1) {
				$night_label = esc_html__('Nights', 'easy-hotel');
			}

			$item_data[] = array(
				'key' => $night_label,
				'value' => esc_html( $night )
			);
		}

		

		if (isset($cart_item['details_html'])) {

			$details_html = $cart_item['details_html'];

			$item_data[] = array(
				'key' => __('Details', 'easy-hotel'),
				'value' => esc_html( $details_html )
			);
		}

		$extra_services_ids = isset($cart_item['extra_services']) ? $cart_item['extra_services'] : '';

		if(!empty($extra_services_ids)){
			if (isset($cart_item['extra_services_html'])) {

				$extra_services_html = $cart_item['extra_services_html'];
	
				$item_data[] = array(
					'key' => __('Extra Services', 'easy-hotel'),
					'value' => esc_html( $extra_services_html )
				);
			}
		}

		// make unique item data
		$item_data = array_unique($item_data, SORT_REGULAR);

		return $item_data;
	
	}

	public function hide_meta_from_display($hidden_meta_keys) {
		// Add meta keys to hide
		$keys_to_hide = array(
			'Accomodation ID',
			'Subtotal Price',
			'Total Price',
			'Base Price',
			'Extra Services Charge',
			'Extra Bed Price',
			'Rooms',
			'Extra Bed',
			'Adults',
			'Children',
			'Start Date',
			'End Date',
			'Start Time',
			'End Time',
			'Save'
		);
	
		return array_merge($hidden_meta_keys, $keys_to_hide);
	}
	
	public function unset_specific_order_item_meta_data($formatted_meta, $item){
	
		$keys_to_hide = array(
			'Accomodation ID',
			'Subtotal Price',
			'Total Price',
			'Base Price',
			'Extra Services Charge',
			'Extra Bed Price',
			'Rooms',
			'Extra Bed',
			'Adults',
			'Children',
			'Start Date',
			'End Date',
			'Start Time',
			'End Time',
			'Save'
		);
	
		foreach($formatted_meta as $key => $meta){
			if(in_array($meta->key, $keys_to_hide)) {
				unset($formatted_meta[$key]);
			}
		}
		return $formatted_meta;
	}

	public function calculate_booking_pricing($accomodation_id, $start_date, $end_date, $room_quantity, $extra_bed_quantity, $adult_quantity, $children_quantity, $selected_services, $currency_converter = false, $start_time = '', $end_time = '') {
		if (empty($accomodation_id)) return;
	
		$accomodation_id = (int) $accomodation_id;
		$total_guest_quantity = (int) $adult_quantity + (int) $children_quantity;
		$start = new DateTime($start_date);
		$end = new DateTime($end_date);
		$days_count = max(1, $start->diff($end)->days);
		$hours_count = ESHB_Helper::eshb_calculate_time_diff($start_date, $end_date, $start_time, $end_time);
		$today = new DateTime('now', new DateTimeZone('GMT'));
		$today_date = $today->format('Y-m-d');
		$tomorrow = $today->modify('+1 day')->format('Y-m-d');
		$hotel_core = new ESHB_Core();
		$metaboxes = get_post_meta($accomodation_id, 'eshb_accomodation_metaboxes', true);
		$allowed_check_in_day = apply_filters( 'eshb_booking_allowed_check_in_day', 'all', $accomodation_id, $metaboxes );
		$single_day_price = 0;
	
		// Handle week-based or same-day bookings
		if (!empty($allowed_check_in_day) && $allowed_check_in_day !== 'all') {
			$days_count = 1;
		}
		
		$pricing_periodicity = false;

		if ($start_date === $end_date) {
			$days_count = 1;
			$pricing_periodicity = apply_filters( 'eshb_pricing_periodicity', false, $accomodation_id, $metaboxes );
			$single_day_price = apply_filters( 'eshb_single_day_price', 0, $accomodation_id);
		}


		// Base price
		$base_price = 0;
		$base_price = $hotel_core->get_eshb_day_wise_price($start_date, $end_date, $accomodation_id, true, $days_count, $adult_quantity, $children_quantity);
		$base_price = !empty($single_day_price) ? $single_day_price : $base_price;
		$has_session_price = $hotel_core->has_upcoming_or_current_session_price($accomodation_id, $start_date, $end_date, $days_count, $adult_quantity, $children_quantity);

		if($has_session_price){
			$session_price = $hotel_core->get_eshb_price_by_session($accomodation_id, $start_date, $end_date, $days_count, $adult_quantity, $children_quantity);
		}

        $base_price = !empty($session_price) && $session_price > 0 ? $session_price : $base_price;
		$regular_base_price = $hotel_core->get_eshb_day_wise_price($start_date, $end_date, $accomodation_id, true, $days_count, $adult_quantity, $children_quantity);
	
		// Pricing logic
		$bed_price = (int) ($metaboxes['extra_bed_price'] ?? 0);
		$pricing_type = $metaboxes['pricing_type'] ?? 'room_wise';
	
		
		$pricing_base = $pricing_type === 'room_wise'
			? $base_price * $room_quantity
			: $base_price * $total_guest_quantity;

		
		$regular_pricing_base = $pricing_type === 'room_wise'
		? $regular_base_price * $room_quantity
		: $regular_base_price * $total_guest_quantity;

	
		$extra_bed_price = $extra_bed_quantity > 0
			? $extra_bed_quantity * $bed_price * $days_count
			: 0;
	
		

		$subtotal_price = $pricing_base + $extra_bed_price;
		$regular_subtotal_price = $regular_pricing_base + $extra_bed_price;

		if($pricing_periodicity && !empty($hours_count)){
			$subtotal_price = $pricing_periodicity == 'per_hour' ? $subtotal_price * (int) $hours_count : $subtotal_price;
			$regular_subtotal_price = $pricing_periodicity == 'per_hour' ? $regular_subtotal_price * (int) $hours_count : $regular_subtotal_price;
		}

	
		// Extra services
		$extra_services_charge = 0;
	
		if (!empty($selected_services) && is_array($selected_services)) {
			$extra_services_charge = array_reduce($selected_services, function ($carry, $service) use ($days_count, $room_quantity, $total_guest_quantity) {
				$service_id = !empty($service['id']) ? $service['id'] : 0;
				$service_quantity = !empty($service['quantity']) ? $service['quantity'] : 0;

				if(empty($service_id) || empty($service_quantity)) {
					return $carry;
				}

				$meta = get_post_meta($service_id, 'eshb_service_metaboxes', true);
				$price = $meta['service_price'] ?? 0;
				$periodicity = $meta['service_periodicity'] ?? 'once';
				$charge_type = $meta['service_charge_type'] ?? 'room';
	
				//$single_price = $price * $service_quantity;
				$single_price = $price ? $price : 0;
	
				if ($periodicity == 'per_day') {
					$single_price *= $days_count;
				}

				if($charge_type == 'room'){
					$single_price *= $room_quantity;
				}else{
					$single_price *= $service_quantity;
				}
	
				return $carry + floatval($single_price);
			}, 0);
		}


		$eshb_settings = get_option('eshb_settings');
		$booking_type = isset($eshb_settings['booking-type']) ? $eshb_settings['booking-type'] : '';

		$regular_subtotal_price = $regular_subtotal_price + $extra_services_charge;
		$regular_total_price = $regular_subtotal_price;

		$subtotal_price = $subtotal_price + $extra_services_charge;
		$total_price = $subtotal_price;

		$discount =  $total_price < $regular_total_price ? abs( (float) $regular_total_price - (float) $total_price) : 0;

		$currency_symbol = $hotel_core->get_eshb_currency_symbol();
		$currency_symbol = html_entity_decode($currency_symbol);
		$currency_position = $hotel_core->get_eshb_currency_position();
	
		
		$extra_bed_price = apply_filters( 'eshb_apply_currency_converter_on_pricing_calculation', $extra_bed_price, $currency_converter);
		$extra_services_charge = apply_filters( 'eshb_apply_currency_converter_on_pricing_calculation', $extra_services_charge, $currency_converter);
		$base_price = apply_filters( 'eshb_apply_currency_converter_on_pricing_calculation', $base_price, $currency_converter);
		$regular_base_price = apply_filters( 'eshb_apply_currency_converter_on_pricing_calculation', $regular_base_price, $currency_converter);
		$subtotal_price = apply_filters( 'eshb_apply_currency_converter_on_pricing_calculation', $subtotal_price, $currency_converter);
		$regular_subtotal_price = apply_filters( 'eshb_apply_currency_converter_on_pricing_calculation', $regular_subtotal_price, $currency_converter);
		$total_price = apply_filters( 'eshb_apply_currency_converter_on_pricing_calculation', $total_price, $currency_converter);
		$regular_total_price = apply_filters( 'eshb_apply_currency_converter_on_pricing_calculation', $regular_total_price, $currency_converter);
		$single_day_price = apply_filters( 'eshb_apply_currency_converter_on_pricing_calculation', $single_day_price, $currency_converter);
		$discount = apply_filters( 'eshb_apply_currency_converter_on_pricing_calculation', $discount, $currency_converter);


		$single_day_price_html = $hotel_core->eshb_price( $single_day_price );
		$regular_base_price_html = $hotel_core->eshb_price( $regular_base_price );
		$base_price_html = $hotel_core->eshb_price( $base_price );
		$extra_bed_price_html = $hotel_core->eshb_price( $extra_bed_price );
		$extra_services_charge_html = $hotel_core->eshb_price( $extra_services_charge );
		$subtotal_price_html = $hotel_core->eshb_price( $subtotal_price );
		$regular_subtotal_price_html = $hotel_core->eshb_price( $regular_subtotal_price );
		$total_price_html = $hotel_core->eshb_price( $total_price );
		$regular_total_price_html = $hotel_core->eshb_price( $regular_total_price );
		$discount_html = $hotel_core->eshb_price( $discount );
		
		$is_wc_price = ($booking_type === 'woocommerce' && class_exists('WooCommerce')) ? true : false;

		return [
			'startDate'           => $start_date,
			'endDate'             => $end_date,
			'today'               => $today_date,
			'tomorrow'            => $tomorrow,
			'daysCount'           => $days_count,
			'singleDayPrice'      => $single_day_price,
			'extraServicesPrice'  => $extra_services_charge,
			'extraBedPrice'       => $extra_bed_price,
			'basePrice'           => $base_price,
			'regularBasePrice'    => $regular_base_price,
			'subtotalPrice'       => $subtotal_price,
			'regularSubtotalPrice'=> $regular_subtotal_price,
			'totalPrice'          => $total_price,
			'regularTotalPrice'   => $regular_total_price,
			'discount'   		  => $discount,
			'currencySymbol'      => $currency_symbol,
			'currencyPosition'    => $currency_position,

			'singleDayPriceHtml'      => $single_day_price_html,
			'extraServicesPriceHtml'  => $extra_services_charge_html,
			'extraBedPriceHtml'       => $extra_bed_price_html,
			'basePriceHtml'           => $base_price_html,
			'regularBasePriceHtml'    => $regular_base_price_html,
			'subtotalPriceHtml'       => $subtotal_price_html,
			'regularSubtotalPriceHtml'=> $regular_subtotal_price_html,
			'totalPriceHtml'          => $total_price_html,
			'regularTotalPriceHtml'   => $regular_total_price_html,
			'discountHtml'   		  => $discount_html,

			'isWcPrice'               => $is_wc_price
		];
	}

	public function eshb_add_to_cart_reservation(){

		// Verify nonce for security
		if (!isset($_POST['nonce']) || !wp_verify_nonce( sanitize_text_field(wp_unslash($_POST['nonce'])), ESHB_Helper::generate_secure_nonce_action('eshb_global_nonce_action'))) {

			$error = array(
				'code' => 'invalid_nonce', 
				'message' => __('invalid_nonce', 'easy-hotel')
			);
			
			wp_send_json_error([
				'error' => $error,
			]);

			die();
		}


		if(isset($_POST['accomodationId']) && !empty($_POST['accomodationId'])){
	
			$hotel_core = new ESHB_Core();
			$accomodation_id = isset( $_POST['accomodationId'] ) ? (int) sanitize_text_field( wp_unslash($_POST['accomodationId']) ) : '';
			$today_date = esc_html(gmdate('Y-m-d')); // Get today's date
			$date = new DateTime($today_date); // Create a DateTime object from today's date
			$date->modify('+1 day'); // Add one day
			$tomorrow = $date->format('Y-m-d'); // Get the new date in 'Y-m-d' format
			$start_date = isset( $_POST['startDate'] ) ? sanitize_text_field( wp_unslash($_POST['startDate']) ) : $today_date;
			$end_date = isset( $_POST['endDate'] ) ? sanitize_text_field( wp_unslash($_POST['endDate']) ) : $tomorrow;
			$start_day_name = $start_date ? strtolower(gmdate('l', strtotime($start_date))) : '';
			$start_time = isset( $_POST['startTime'] ) ? sanitize_text_field( wp_unslash($_POST['startTime']) ) : '';
			$end_time = isset( $_POST['endTime'] ) ? sanitize_text_field( wp_unslash($_POST['endTime']) ) : '';
			$accomodation_metaboxes = get_post_meta($accomodation_id, 'eshb_accomodation_metaboxes', true);

			$start = new DateTime($start_date);
			$end = new DateTime($end_date);
			$interval = $start->diff($end);
			$days_count = $interval->days;

			$room_quantity = isset( $_POST['roomQuantity'] ) ? (int) sanitize_text_field( wp_unslash($_POST['roomQuantity'] ) ) : 1;
			$extra_bed_quantity = isset( $_POST['extraBedQuantity'] ) ? (int) sanitize_text_field( wp_unslash($_POST['extraBedQuantity'] ) ) : 0;
			$adult_quantity = isset( $_POST['adultQuantity'] ) ? (int) sanitize_text_field( wp_unslash($_POST['adultQuantity'] ) ) : 1;
			$children_quantity = isset( $_POST['childrenQuantity'] ) ? (int) sanitize_text_field( wp_unslash($_POST['childrenQuantity'] ) ) : 0;
			$total_guest_quantity = $adult_quantity + $children_quantity;

			$selected_services = [];
			if(isset($_POST['selectedServices']) && !empty($_POST['selectedServices'])){

				$selected_services = sanitize_text_field(wp_unslash($_POST['selectedServices']));
				$selected_services = json_decode($selected_services, true);
				
			}

			$eshb_settings = get_option( 'eshb_settings', [] );
			$booking_type = isset($eshb_settings['booking-type']) && !empty($eshb_settings['booking-type']) ? $eshb_settings['booking-type'] : 'woocommerce';
			$string_booking_success_msg = isset($eshb_settings['string_book_success_msg']) && !empty($eshb_settings['string_booking_success_msg']) ? $eshb_settings['string_booking_success_msg'] : 'Reservation Successfully added to your cart.';
			$string_booking_failed_msg = isset($eshb_settings['string_booking_failed_msg']) && !empty($eshb_settings['string_booking_failed_msg']) ? $eshb_settings['string_booking_failed_msg'] : 'Ops! This Reservation has been failed.';
			$string_already_booked_msg = isset($eshb_settings['string_already_booked_msg']) && !empty($eshb_settings['string_already_booked_msg']) ? $eshb_settings['string_already_booked_msg'] : 'Ops! The date range is already booked:';
			$string_minimum_week_nights_msg = isset($eshb_settings['string_minimum_week_nights_msg']) && !empty($eshb_settings['string_minimum_week_nights_msg']) ? $eshb_settings['string_minimum_week_nights_msg'] : 'Please select more than 1 night!';
			$string_time_error_msg = isset($eshb_settings['string_time_error_msg']) && !empty($eshb_settings['string_time_error_msg']) ? $eshb_settings['string_time_error_msg'] : 'Selected time slot is not available!';
			$room_visibility = in_array('rooms', $eshb_settings['booking-form-fields']) ? true : false;
			$adult_visibility = in_array('adults', $eshb_settings['booking-form-fields']) ? true : false;
			$childrens_visibility = in_array('childrens', $eshb_settings['booking-form-fields']) ? true : false;
			$extra_beds_visibility = in_array('extra_beds', $eshb_settings['booking-form-fields']) ? true : false;

			$eshb_week_settings = [
				'string_check_in_day_error_msg' => 'Only allowed check in day is',
				'eshb_booking_allowed_check_in_day' => 'all',
			];
			$eshb_week_settings = apply_filters( 'eshb_week_settings', $eshb_week_settings );
			$allowed_check_in_day = apply_filters( 'eshb_booking_allowed_check_in_day', 'all', $accomodation_id, $accomodation_metaboxes );
			$string_check_in_day_error_msg = !empty($eshb_week_settings['string_check_in_day_error_msg']) ? $eshb_week_settings['string_check_in_day_error_msg'] : 'Only allowed check in day is : ';

			// Min Max Booking Configurations
			$min_max_settings = [
				'required_min_nights' => '',
				'required_max_nights' => '',
				'is_global_source_for_min_max' => true,
			];
			$min_max_settings = apply_filters( 'eshb_min_max_settings', $min_max_settings, $accomodation_id, $accomodation_metaboxes );
			$required_min_nights = $start_date !== $end_date && isset($min_max_settings['required_min_nights']) ? $min_max_settings['required_min_nights'] : '';
			$required_max_nights = $start_date !== $end_date && isset($min_max_settings['required_max_nights']) ? $min_max_settings['required_max_nights'] : '';
			$string_required_minimum_nights_msg = esc_html__( 'Ops! This Reservation has been failed. Requried Minumum', 'easy-hotel' );
			$string_required_maximum_nights_msg = esc_html__( 'Ops! This Reservation has been failed. Requried Maximum', 'easy-hotel' );
			$pricing_periodicity = apply_filters( 'eshb_pricing_periodicity', false, $accomodation_id, $accomodation_metaboxes );
			
			$min_stay_night_by_session = ESHB_Helper::get_eshb_min_stay_night_by_session($accomodation_id, $start_date, $end_date);

			// Validate booking type
			if ( $booking_type == 'woocommerce' && ! class_exists( 'WooCommerce' ) ) {
				$error = array(
					'code'    => 'woocommerce_not_activated',
					'message' => esc_html__( 'Ops! Woocommerce not activated. Activate Woocommerce.', 'easy-hotel'),
				);
				wp_send_json_error( [ 'error' => $error ] );

			} elseif ( $booking_type == 'surecart' && ! class_exists( 'SureCart' ) ) {
				$error = array(
					'code'    => 'surecart_not_activated',
					'message' => esc_html__( 'Ops! Surecart not activated. Activate Surecart.', 'easy-hotel' ),
				);
				wp_send_json_error( [ 'error' => $error ] );

			} elseif ( $booking_type == 'surecart' && ! class_exists( 'ESHB_SURECART' ) ) {
				$error = array(
					'code'    => 'surecart_addon_not_activated',
					'message' => esc_html__( 'Ops! EHB Surecart addons not activated. Activate EHB Surecart.', 'easy-hotel' ),
				);
				wp_send_json_error( [ 'error' => $error ] );
			}


			$available_times = ESHB_Helper::get_available_times_by_date($accomodation_id, $start_date);
			$is_valid_time = false;
			
			if($pricing_periodicity == 'per_hour' && (!empty($accomodation_metaboxes['single_day_price']) || !empty($accomodation_metaboxes['single_day_sale_price'])) && !empty($available_times)){
				$available_slots = isset($available_times['available_slots']) ? $available_times['available_slots'] : [];

				if(count($available_slots) > 0) {
					foreach ($available_slots as $slot) {
						if ($start_time >= $slot[0] && $end_time <= $slot[1]) {
							$is_valid_time = true;
							break;
						}
					}
				}else{
					$is_valid_time = false;
				}

				if(!$is_valid_time){
					$error = array('code' => 'invalid_time', 'message' => esc_html($string_time_error_msg));
					wp_send_json_error([
						'error' => $error,
					]);
				}
			}

			$actual_booked_dates = $this->get_actual_booked_dates_in_date_ranges($accomodation_id, $start_date, $end_date);
			$booked_dates_str = '';
			if(!empty($actual_booked_dates)){

				$error_message = sprintf(
					/* translators: 1: already booked message text, 2: list of booked dates */
					esc_html__( '%1$s %2$s', 'easy-hotel' ),
					esc_html( $string_already_booked_msg ),
					$booked_dates_str
				);

				$error = array(
					'code'    => 'already_booked',
					'message' => $error_message,
				);
				wp_send_json_error([
					'error' => $error,
					'booked_dates' => implode(', ', $actual_booked_dates),
				]);

			}

			$holiday_dates = $this->get_holiday_dates_in_date_ranges($accomodation_id, $start_date, $end_date);

			if(!empty($holiday_dates)){
				$error = array('code' => 'holiday_dates', 'message' => esc_html__('Selected date range is not available. These dates are in holidays.', 'easy-hotel'));
				wp_send_json_error([
					'error' => $error,
					'holiday_dates' => implode(', ', $holiday_dates),
				]);
			}

			// Check cart blocking (temporary holds by other users)
			$cart_block_msg = $this->eshb_check_cart_block($accomodation_id, $start_date, $end_date);
			if (!empty($cart_block_msg)) {
				$error = array('code' => 'cart_blocked', 'message' => esc_html($cart_block_msg));
				wp_send_json_error(['error' => $error]);
			}

			// check rooms capacity
			if(!$is_valid_time && isset($_POST['roomQuantity']) && !empty($_POST['roomQuantity'])){
				$roomQuantity = isset( $_POST['roomQuantity'] ) ? (int) sanitize_text_field( wp_unslash($_POST['roomQuantity'] ) ) : 1;
				
				$availableRoom = $this->get_available_room_count_by_date_range($accomodation_id, $start_date, $end_date);

				if($roomQuantity > $availableRoom){
					$error = array(
						'code'    => 'room_capacity_not_enough',
						'message' => sprintf(
							/* translators: %s: number of available rooms */
							esc_html__( 'Selected room is not available. Available room: %s', 'easy-hotel' ),
							esc_html( $availableRoom )
						),
					);
					wp_send_json_error([
						'error' => $error,
					]);
				}
			}


			// Validate check-in day
			if($allowed_check_in_day != 'all' && $start_day_name != '' && !empty($allowed_check_in_day) && $allowed_check_in_day == $start_day_name) {
				$error = array(
					'code'    => 'check_in_day_error',
					'message' => sprintf(
						/* translators: %s: allowed check-in day */
						esc_html__( '%1$s %1$s', 'easy-hotel' ),
						esc_html( $string_check_in_day_error_msg ),
						esc_html( $allowed_check_in_day )
					),
				);
				wp_send_json_error([
					'error' => $error,
				]);
			}
		

			if(!empty($allowed_check_in_day) && $allowed_check_in_day != 'all'){
				$days_count = 1;
			}

			// validate min stay night by session
			if(class_exists('ESHB_ADVANCED_PRICING') && !empty($min_stay_night_by_session) && $days_count < $min_stay_night_by_session){
				$error = array(
					'code'    => 'min_stay_night_by_session',
					'message' => sprintf(
						/* translators: 1: minimum nights message text, 2: required minimum nights */
						esc_html__( '%1$s %2$s nights!', 'easy-hotel' ),
						esc_html( $string_required_minimum_nights_msg ),
						esc_html( $min_stay_night_by_session )
					),
				);
				wp_send_json_error([
					'error' => $error,
				]);
			}
			
			if(!empty($required_min_nights) && $days_count < $required_min_nights){
				$error = array(
					'code'    => 'required_min_nights',
					'message' => sprintf(
						/* translators: 1: minimum nights message text, 2: required minimum nights */
						esc_html__( '%1$s %2$s nights!', 'easy-hotel' ),
						esc_html( $string_required_minimum_nights_msg ),
						esc_html( $required_min_nights )
					),
				);
				wp_send_json_error([
					'error' => $error,
				]);
			}
			if(!empty($required_max_nights) && $days_count > $required_max_nights){
				$error = array(
					'code'    => 'required_max_nights',
					'message' => sprintf(
						/* translators: 1: maximum nights message text, 2: required maximum nights */
						esc_html__( '%1$s %2$s nights allowed!', 'easy-hotel' ),
						esc_html( $string_required_maximum_nights_msg ),
						esc_html( $required_max_nights )
					),
				);
				wp_send_json_error([
					'error' => $error,
				]);
			}

			
			
			// validate capacities
			$adult_capacity = !empty($accomodation_metaboxes['adult_capacity']) ? $accomodation_metaboxes['adult_capacity'] : 0;
			$children_capacity = !empty($accomodation_metaboxes['children_capacity']) ? $accomodation_metaboxes['children_capacity'] : 0;
			$total_capacity = !empty($accomodation_metaboxes['total_capacity']) ? $accomodation_metaboxes['total_capacity'] : 0;
			$extra_bed_capacity = !empty($accomodation_metaboxes['total_extra_beds']) ? $accomodation_metaboxes['total_extra_beds'] : 0;
			
			// multiply total capacity by per rooms
			$total_capacity = $total_capacity * $room_quantity;

			if(!empty($total_capacity)){
				if($adult_capacity < 1 && $children_capacity > 0){
					$adult_capacity = $total_capacity - $children_quantity;
				}elseif($adult_capacity < 1 && $children_capacity < 1){
					$adult_capacity = $total_capacity;
				}

				if($children_capacity < 1 && $adult_capacity > 0){
					$children_capacity = $total_capacity - $adult_quantity;
				}elseif($children_capacity < 1 && $adult_capacity < 1){
					$children_capacity = $total_capacity;
				}
			}

			// multiply capacity by per rooms
			$adult_capacity = $adult_capacity * $room_quantity;
			$children_capacity = $children_capacity * $room_quantity;
			$extra_bed_capacity = $extra_bed_capacity * $room_quantity;

			if(!empty($adult_capacity) && $adult_quantity > 0 && $adult_capacity < $adult_quantity){
				$error = array('code' => 'adult_capacity_not_enough', 'message' => esc_html__('Maximum Adult Capacity', 'easy-hotel') . ' ' . $adult_capacity);
				wp_send_json_error([
					'error' => $error,
				]);
			}

			if(!empty($children_capacity) && $children_quantity > 0 && $children_capacity < $children_quantity){
				$error = array('code' => 'children_capacity_not_enough', 'message' => esc_html__('Maximum Children Capacity', 'easy-hotel') . ' ' . $children_capacity);
				wp_send_json_error([
					'error' => $error,
				]);
			}
			
			if($extra_bed_quantity > 0 && $extra_bed_capacity < $extra_bed_quantity){
				$error = array('code' => 'extra_bed_capacity_not_enough', 'message' => esc_html__('Maximum Extra Bed Capacity', 'easy-hotel') . ' ' . $extra_bed_capacity );
				wp_send_json_error([
					'error' => $error,
				]);
			}

			
			
			$pricing = $this->calculate_booking_pricing($accomodation_id, $start_date, $end_date, $room_quantity, $extra_bed_quantity, $adult_quantity, $children_quantity, $selected_services, false, $start_time, $end_time );

			$base_price = $pricing['basePrice'];
			$extra_services_charge = $pricing['extraServicesPrice'];
			$extra_bed_price= $pricing['extraBedPrice'];
			$subtotal_price = $pricing['subtotalPrice'];
			$total_price = $pricing['totalPrice'];
			$discount = $pricing['discount'];
			$currency_symbol = $pricing['currencySymbol'];
			$quantity = 1;

			$details = [];

			if ($room_visibility && $room_quantity > 0) {
				$details[] = 'Room: ' . $room_quantity;
			}
			if ($extra_beds_visibility && $extra_bed_quantity > 0) {
				$details[] = 'Extra Bed: ' . $extra_bed_quantity;
			}
			if ($adult_visibility && $adult_quantity > 0) {
				$details[] = 'Adult: ' . $adult_quantity;
			}
			if ($childrens_visibility && $children_quantity > 0) {
				$details[] = 'Children: ' . $children_quantity;
			}

			$details_html = implode(', ', $details);

			
			$extra_service_titles = [];
			$extra_services_html = '';
			
			if(!empty($selected_services) && is_array($selected_services) && count($selected_services) > 0 ){
			
				foreach ($selected_services as $service) {
	
					$service_id = $service['id'];

					$service_quantity = $service['quantity'];

					if(!empty($service_quantity)){
						$eshb_service_metaboxes = get_post_meta($service_id, 'eshb_service_metaboxes', true);

						$charge_type = $eshb_service_metaboxes['service_charge_type'];

						$service_title = get_the_title($service_id) . ' For ' . $service_quantity . ' ' .  ucfirst(strtolower($charge_type));

						if(!$room_visibility && $charge_type == 'room'){
							$service_title = get_the_title($service_id);
						}
					}else{
						$service_title = get_the_title($service_id);
					}

					

					array_push($extra_service_titles, $service_title);
	
				}
				$extra_services_html = implode(", ",$extra_service_titles);
			}

			$dates = date_i18n( get_option('date_format'), strtotime( $start_date ) ) .' - '. date_i18n( get_option('date_format'), strtotime( $end_date ) );
			if($start_date == $end_date){
				$dates = date_i18n( get_option('date_format'), strtotime( $start_date ) );
			}

			$formated_start_timestamp = strtotime( $start_time );
			$formated_end_timestamp = strtotime( $end_time );

			$cart_item_data = [
					'accomodation_id' => $accomodation_id,
					'subtotal_price' => $subtotal_price,
					'total_price' => $total_price,
					'base_price' => $base_price,
					'discount' => $discount, 
					'extra_services_charge' => $extra_services_charge,
					'extra_bed_price' => $extra_bed_price,
					'currency_symbol' => $currency_symbol,
					'start_date' => $start_date,
					'end_date' => $end_date,
					'night' => $days_count,
					'dates' => $dates,
					'room_quantity' => $room_quantity,
					'adult_quantity' => $adult_quantity,
					'details_html' => $details_html,
					'extra_services_html' => $extra_services_html
				];

				if(!empty($extra_bed_quantity)) {
					$cart_item_data['extra_bed_quantity'] = $extra_bed_quantity;
				}
				if(!empty($start_time)) {
					$cart_item_data['start_time'] = $start_time;
				}
				if(!empty($end_time)) {
					$cart_item_data['end_time'] = $end_time;
				}

				if(!empty($start_time) && !empty($end_time)) {
					// Get WP formatted time (according to Settings > General > Time Format)
					$wp_time_format = get_option( 'time_format' ); // WP settings
					$formatted_start_time = wp_date( $wp_time_format, $formated_start_timestamp );
					$formatted_end_time = wp_date( $wp_time_format, $formated_end_timestamp );
					$times = $formatted_start_time . ' - ' . $formatted_end_time;
					$cart_item_data['times'] = $times;
				}

				if(!empty($children_quantity)) {
					$cart_item_data['children_quantity'] = $children_quantity;
				}

				if(!empty($selected_services)) {
					$cart_item_data['extra_services'] = $selected_services;
				}
				
				if(!empty($extra_services_charge)) {
					$cart_item_data['extra_services_html'] = $extra_services_html;
				}

			if (get_post_type($accomodation_id) === 'eshb_accomodation') {

				$thumbnail_id = get_post_thumbnail_id($accomodation_id);
				$price_id = 0;
				$product_id = ESHB_Helper::get_product_id_for_cart($accomodation_id, $booking_type);
				$product_id = apply_filters( 'eshb_product_id_for_cart', $product_id, $accomodation_id, $thumbnail_id );
				
				$cart_item_data['product_id'] = $product_id;
				$cart_item_data['price_id'] = $price_id;

				do_action( 'eshb_before_add_to_cart', $booking_type, $cart_item_data, $string_booking_success_msg );

				if($booking_type == 'woocommerce'){

					update_post_meta($product_id, '_accomodation_id', $accomodation_id);
					$this->update_product_price_by_id($product_id, $subtotal_price);

					$cart_item_data['unique_key'] = uniqid( '', true );
					$cart_item_key = WC()->cart->add_to_cart($product_id, $quantity, 0, [], $cart_item_data);

					if ( $cart_item_key ) {

						$blocked_until = $this->eshb_set_cart_block($accomodation_id, $start_date, $end_date, $room_quantity);

						wp_send_json_success([
							'booking-type'    => $booking_type,
							'message'         => esc_html( $string_booking_success_msg ),
							'cart_item_key'   => $cart_item_key,
							'cart_count'      => WC()->cart->get_cart_contents_count(),
							'blocked_until'   => $blocked_until,
							'accomodation_id' => $accomodation_id,
							'start_date'      => $start_date,
							'end_date'        => $end_date,
						]);

					} else {

						$error = array(
							'code'    => 'cart_item_key_not_found',
							'message' => esc_html( $string_booking_failed_msg ),
						);

						wp_send_json_error([
							'error'          => $error,
							'cart_item_data' => $cart_item_data,
							'product_id'     => $product_id,
						]);
					}

				}

				do_action( 'eshb_after_add_to_cart', $booking_type, $cart_item_data, $string_booking_success_msg );

			}else{
				$error = array('code' => 'accomodation_post_type_not_found', 'message' => esc_html($string_booking_failed_msg));
				wp_send_json_error([
					'error' => $error,
				]);
			}
			die();
		}
	
	}

	public function eshb_get_booking_prices() {
		// Ensure external filters are loaded during AJAX requests
		do_action('eshb_before_calculate_pricing');
		
		if (isset($_POST['accomodationId']) && !empty($_POST['accomodationId'])) {
	
			// Verify nonce for security
			if (!isset($_POST['nonce']) || !wp_verify_nonce(sanitize_text_field(wp_unslash($_POST['nonce'])), ESHB_Helper::generate_secure_nonce_action('eshb_global_nonce_action'))) {
				wp_send_json_error(['message' => 'Invalid nonce']);
				die();
			}
	
			$accomodation_id = (int) sanitize_text_field(wp_unslash($_POST['accomodationId']));
	
			$start_date = sanitize_text_field(wp_unslash($_POST['startDate'] ?? $today_date));
			$end_date = sanitize_text_field(wp_unslash($_POST['endDate'] ?? $tomorrow));

			$start_time = sanitize_text_field(wp_unslash($_POST['startTime'] ?? ''));
			$end_time = sanitize_text_field(wp_unslash($_POST['endTime'] ?? ''));
	
			$room_quantity     = (int) sanitize_text_field(wp_unslash($_POST['roomQuantity'] ?? 1));
			$extra_bed_quantity = (int) sanitize_text_field(wp_unslash($_POST['extraBedQuantity'] ?? 0));
			$adult_quantity     = (int) sanitize_text_field(wp_unslash($_POST['adultQuantity'] ?? 1));
			$children_quantity  = (int) sanitize_text_field(wp_unslash($_POST['childrenQuantity'] ?? 0));
			$selected_services = [];
			if(isset($_POST['selectedServices']) && !empty($_POST['selectedServices'])){

				$selected_services = sanitize_text_field(wp_unslash($_POST['selectedServices']));
				$selected_services = json_decode($selected_services, true);
				
			}
			

			$pricing = $this->calculate_booking_pricing($accomodation_id, $start_date, $end_date, $room_quantity, $extra_bed_quantity, $adult_quantity, $children_quantity, $selected_services, true, $start_time, $end_time);
			
			wp_send_json_success($pricing);
		}
	
		wp_die();
	}

	public function eshb_get_booking_prices_rest( $request ) {
		do_action('eshb_before_calculate_pricing');

		$params = $request->get_params();

		// // Nonce check
		if ( ! isset($params['nonce']) || ! wp_verify_nonce($params['nonce'], ESHB_Helper::generate_secure_nonce_action('eshb_global_nonce_action')) ) {
			return new WP_Error('invalid_nonce', 'Invalid nonce', ['status' => 403]);
		}

		$accomodation_id = (int) ($params['accomodationId'] ?? 0);
		$start_date      = $params['startDate'] ?? gmdate('Y-m-d');
		$end_date        = $params['endDate'] ?? gmdate('Y-m-d', strtotime('+1 day'));
		$start_time      = $params['startTime'] ?? '';
		$end_time        = $params['endTime'] ?? '';
		$room_quantity   = (int) ($params['roomQuantity'] ?? 1);
		$extra_bed_quantity = (int) ($params['extraBedQuantity'] ?? 0);
		$adult_quantity  = (int) ($params['adultQuantity'] ?? 1);
		$children_quantity = (int) ($params['childrenQuantity'] ?? 0);
		$selected_services = $params['selectedServices'] ?? [];

		$pricing = $this->calculate_booking_pricing(
			$accomodation_id,
			$start_date,
			$end_date,
			$room_quantity,
			$extra_bed_quantity,
			$adult_quantity,
			$children_quantity,
			$selected_services,
			true,
			$start_time,
			$end_time
		);

		return rest_ensure_response($pricing);
	}

    public function eshb_get_extra_services_charge(){

		// Verify nonce for security
		if (!isset($_POST['nonce']) || !wp_verify_nonce( sanitize_text_field(wp_unslash($_POST['nonce'])), ESHB_Helper::generate_secure_nonce_action('eshb_global_nonce_action'))) {
			wp_send_json_error(['message' => 'Invalid nonce']);
			die();
		}

        if(isset($_POST['selectedServices']) && !empty($_POST['selectedServices'])){

            $selected_services = array_map('sanitize_text_field', wp_unslash($_POST['selectedServices']));
			$days_count = isset($_POST['dayCount']) ? sanitize_text_field(wp_unslash($_POST['dayCount'])) : 1;

            $price = 0;

            if(is_array($selected_services)){
                foreach ($selected_services as $service) {
			
                    $service_id = $service['id'];
                    $quantity = $service['quantity'];
                    
                    $eshb_service_metaboxes = get_post_meta($service_id, 'eshb_service_metaboxes', true);

					$service_periodicity = $eshb_service_metaboxes['service_periodicity'];
                    
                    if (isset($eshb_service_metaboxes['service_price'])) { // Ensure 'service_price' is set
                        $single_price = $eshb_service_metaboxes['service_price'] * $quantity;
						if($service_periodicity == 'perday' && !empty($days_count)){
							$single_price = $days_count * $single_price;
						}
                        $price += floatval($single_price); // Add the single price to the total price
                    }

                }
            }
            
            wp_send_json_success( ['price' => $price] );

            wp_die();

        }

    }

	public function get_available_room_count_by_date_range($accomodation_id, $start_date, $end_date, $start_time = '', $end_time = '') {
		$accomodation_id = intval($accomodation_id);
		$start_date_obj = new DateTime($start_date);
		$end_date_obj = new DateTime($end_date);

		if ($end_date_obj < $start_date_obj) {
			return new WP_Error('invalid_date_range', 'End date cannot be earlier than start date.');
		}

		// Fetch total rooms
		$accomodation_metas = get_post_meta($accomodation_id, 'eshb_accomodation_metaboxes', true);
		$total_rooms = isset($accomodation_metas['total_rooms']) ? intval($accomodation_metas['total_rooms']) : 1;

		// Initialize bookings count array
		$bookings_per_date = [];

		// Query all bookings
		$bookings_args = [
			'post_type'      => 'eshb_booking',
			'posts_per_page' => -1,
			//'post_status'    => 'publish',
			'post_status'    => ['publish', 'completed', 'processing', 'deposit-payment', 'pending'],
			'fields' => 'ids',
		];
		$bookings = new WP_Query($bookings_args);

		if ($bookings->have_posts()) {
			while ($bookings->have_posts()) {
				$bookings->the_post();
				$booking_id = get_the_ID();
				$booking_metas = get_post_meta($booking_id, 'eshb_booking_metaboxes', true);
				$booking_accomodation_id = $booking_metas['booking_accomodation_id'];
				$booking_status = isset($booking_metas['booking_status']) ? $booking_metas['booking_status'] : '';
				$valid_statuses = array('pending', 'processing', 'on-hold', 'completed', 'deposit-payment');

				if (
					is_array($booking_metas) &&
					intval($booking_accomodation_id) === $accomodation_id &&
					isset($booking_metas['booking_start_date'], $booking_metas['booking_end_date']) &&
					in_array($booking_status, $valid_statuses)
				) {
					$booking_start = new DateTime($booking_metas['booking_start_date']);
					$booking_end = new DateTime($booking_metas['booking_end_date']);
					$booked_rooms = !empty($booking_metas['room_quantity']) ? intval($booking_metas['room_quantity']) : 1;
					$accomodation_metaboxes = get_post_meta( $booking_accomodation_id, 'eshb_accomodation_metaboxes', true );
					$total_rooms = !empty($accomodation_metaboxes['total_rooms']) ? $accomodation_metaboxes['total_rooms'] : 1;

					if(!empty($start_time) && !empty($end_time)) {
						$booking_start_time = !empty($booking_metas['booking_start_time']) ? $booking_metas['booking_start_time'] : '';
						$booking_end_time = !empty($booking_metas['booking_end_time']) ? $booking_metas['booking_end_time'] : '';

						if($booking_start_time !== $start_time) {
							$booked_rooms = 0;
						}
						if($booking_start_time === $start_time && $booking_end_time === $end_time) {
						
							$booked_rooms = 0;
						}
					}

					// Loop through each date in this booking
					$period = new DatePeriod($booking_start, new DateInterval('P1D'), (clone $booking_end)->modify('+0 day'));
					if($booking_start == $booking_end) {
						$period = new DatePeriod($booking_start, new DateInterval('P1D'), (clone $booking_end)->modify('+1 day'));
					}

					foreach ($period as $date) {
						$formatted = $date->format('Y-m-d');
						if (!isset($bookings_per_date[$formatted])) {
							$bookings_per_date[$formatted] = 0;
						}
						$bookings_per_date[$formatted] += $booked_rooms;
					}
					
				}
			}
			wp_reset_postdata();
		}

		

		// Now calculate the max number of rooms booked in the given date range
		$range_period = new DatePeriod($start_date_obj, new DateInterval('P1D'), (clone $end_date_obj)->modify('+0 day'));
		$max_booked_in_range = 0;

		if($start_date_obj == $end_date_obj){
			$formatted = $start_date_obj->format('Y-m-d');
			$available_rooms = isset($bookings_per_date[$formatted]) ? $total_rooms - $bookings_per_date[$formatted] : $total_rooms;
			return $available_rooms;
		}

		foreach ($range_period as $date) {
			$formatted = $date->format('Y-m-d');
			$booked = isset($bookings_per_date[$formatted]) ? $bookings_per_date[$formatted] : 0;
			if ($booked > $max_booked_in_range) {
				$max_booked_in_range = $booked;
			}
		}

		// Final available room count
		$available_rooms = max(0, $total_rooms - $max_booked_in_range);

		if($available_rooms < 0) {
			$available_rooms = 0;
		}

		return $available_rooms;
	}

	public function eshb_get_available_rooms_counts_data(){

		// Verify nonce for security
		if (!isset($_POST['nonce']) || !wp_verify_nonce(sanitize_text_field(wp_unslash($_POST['nonce'])), ESHB_Helper::generate_secure_nonce_action('eshb_global_nonce_action'))) {
			wp_send_json_error(['message' => 'Invalid nonce']);
			die();
		}
		

		$accomodation_id = !empty($_POST['accomodationId']) ? sanitize_text_field( wp_unslash($_POST['accomodationId']) ) : '';
		$start_date = !empty($_POST['startDate']) ? sanitize_text_field( wp_unslash($_POST['startDate']) ) : '';
		$end_date = !empty($_POST['endDate']) ? sanitize_text_field( wp_unslash($_POST['endDate']) ) : '';

		$start_time = !empty($_POST['startTime']) ? sanitize_text_field( wp_unslash($_POST['startTime']) ) : '';
		$end_time = !empty($_POST['endTime']) ? sanitize_text_field( wp_unslash($_POST['endTime']) ) : '';


		$start_date = new DateTime($start_date);
		$end_date = new DateTime($end_date);
		
		$eshb_accomodation_metaboxes = get_post_meta($accomodation_id, 'eshb_accomodation_metaboxes', true);
		$total_rooms = !empty($eshb_accomodation_metaboxes['total_rooms']) ? $eshb_accomodation_metaboxes['total_rooms'] : 0;

		$available = 1;
		$available = $this->get_available_room_count_by_date_range($accomodation_id, $start_date->format('Y-m-d'), $end_date->format('Y-m-d'), $start_time, $end_time);
		if($available < 0 ) {
            $available = 0;
        }

		wp_send_json_success( 
			array(
				'available' => $available,
				'total' => $total_rooms,
			) 
		);

		die();

	}

	public function eshb_get_accomodation_available_capacity_counts(){

		if (!isset($_POST['nonce']) || !wp_verify_nonce(sanitize_text_field(wp_unslash($_POST['nonce'])), ESHB_Helper::generate_secure_nonce_action('eshb_global_nonce_action'))) {
			wp_send_json_error(['message' => 'Invalid nonce']);
			die();
		}


		if(isset($_POST['accomodationId']) && !empty($_POST['accomodationId']) && isset($_POST['type']) && !empty($_POST['type'])){
			$type = sanitize_text_field( wp_unslash($_POST['type']) );
			$accomodation_id = sanitize_text_field( wp_unslash($_POST['accomodationId']) );
			$accomodation_metaboxes = get_post_meta($accomodation_id, 'eshb_accomodation_metaboxes', true);
			$total_guest_quantity = $accomodation_metaboxes['total_capacity'];
			$selected_rooms_count = !empty($_POST['rooms']) ? sanitize_text_field( wp_unslash($_POST['rooms']) ) : 1;
			$start_date = !empty($_POST['startDate']) ? sanitize_text_field( wp_unslash($_POST['startDate']) ) : '';
			$end_date = !empty($_POST['endDate']) ? sanitize_text_field( wp_unslash($_POST['endDate']) ) : '';
			$start_date = new DateTime($start_date);
			$end_date = new DateTime($end_date);

			$available = 1;
			$msg = __('Maximum Capacity', 'easy-hotel');

			if($type == 'room_quantity'){
				$total = $accomodation_metaboxes['total_rooms']; 

				$available = $this->get_available_room_count_by_date_range($accomodation_id, $start_date->format('Y-m-d'), $end_date->format('Y-m-d'));
				
				if($available < 1){
					$msg = __('Available Room', 'easy-hotel');
				}
				
			}

			if($type == 'adult_quantity'){
			
				if(!empty($accomodation_metaboxes['adult_capacity'])){
					$available = $accomodation_metaboxes['adult_capacity']; 
					$available = $available * $selected_rooms_count;
				}else{
					$childrenQuantity = !empty($_POST['childrenQuantity']) ? sanitize_text_field( wp_unslash( $_POST['childrenQuantity'] ) ) : 0;	
				
					$total_capacity = $accomodation_metaboxes['total_capacity'];
					
					$available = $total_capacity - $childrenQuantity;

					$available = $available * $selected_rooms_count;

					$msg = __('Maximum Adult and Children Capacity', 'easy-hotel');
				}
				
			}

			if($type == 'children_quantity'){

				$total_capacity = $accomodation_metaboxes['total_capacity'];

				if(!empty($accomodation_metaboxes['children_capacity'])){
					$available = $accomodation_metaboxes['children_capacity']; 
					$available = $available * $selected_rooms_count;
				}else{
					$childrenQuantity = !empty($_POST['adultQuantity']) ? sanitize_text_field( wp_unslash( $_POST['adultQuantity'] ) ) : 0;	
				
					$available = $total_capacity - $childrenQuantity;

					$available = $available * $selected_rooms_count;

					$msg = __('Maximum Adult and Children Capacity', 'easy-hotel');
				}
				
			}

			if($type == 'extra_bed_quantity'){
				$available = $accomodation_metaboxes['total_extra_beds']; 
				$available = $available * $selected_rooms_count;
			}

			if($type == 'service-quantity'){
				$available = $total_guest_quantity;
			}


			if(($type != 'room_quantity') && (empty($available) || $available < 1)){
				$available = $total;
			}

			if($available < 0) {
				$available = 0;
			}

			$msg = $type != 'adult_quantity' || $type != 'children_quantity' ? $msg . ' ' . $available : $msg;

			wp_send_json_success( 
				array(
					'message' => $msg,
					'available' => $available,
					'type' => $type,
				) 
			);
		}
	}

	public function get_accomodation_available_extra_bed_counts(){

		// Verify nonce for security
		if (!isset($_POST['nonce']) || !wp_verify_nonce(sanitize_text_field(wp_unslash($_POST['nonce'])), ESHB_Helper::generate_secure_nonce_action('eshb_global_nonce_action'))) {
			wp_send_json_error(['message' => 'Invalid nonce']);
			die();
		}

		if(isset($_POST['accomodationId']) && !empty($_POST['accomodationId']) && !empty($_POST['accomodationId'])){

			$total_extra_beds = 0;
			$accomodation_id = (int) sanitize_text_field( wp_unslash($_POST['accomodationId']) );
			$accomodation_metaboxes = get_post_meta($accomodation_id, 'eshb_accomodation_metaboxes', true);
			
			$total_extra_beds = $accomodation_metaboxes['total_extra_beds']; 

			wp_send_json_success( $total_extra_beds );

		}
	}

	public function send_email_woocommerce_style($email, $subject, $heading, $message) {
		if ( ! function_exists( 'WC' ) ) {
			return;
		}
	
		// Get WooCommerce mailer
		$mailer = WC()->mailer();
	
		// Wrap message with WooCommerce email template
		$wrapped_message = $mailer->wrap_message($heading, $message);
	
		// Create new WC_Email instance
		$wc_email = new WC_Email();
	
		// Style the wrapped message with WooCommerce inline styles
		$html_message = $wc_email->style_inline($wrapped_message);
	
		// Headers
		$headers = array('Content-Type: text/html; charset=UTF-8');
	
		// Send the email
		$mailer->send($email, $subject, $html_message, $headers);
	}

	public function filter_status_based_on_booking_meta($status, $order_id) {
		// Check if custom meta _booking_post_created exists
		$booking_post_id = get_post_meta($order_id, '_booking_post_created', true);

		$eshb_settings = get_option('eshb_settings', []);
		

		if ( ! empty($booking_post_id) ) {
			if(isset($eshb_settings['booking-auto-approval']) && $eshb_settings['booking-auto-approval'] == true){
				return 'completed'; // Mark order as completed
			}
		}

		// Otherwise, keep default status (usually 'processing')
		return $status;
	}
	
	public function update_booking_status_on_woocommerce_order_status_change($order_id, $old_status, $new_status, $order) {

		if($old_status == $new_status) {
			return;
		}
		
		$screen = function_exists( 'get_current_screen' ) ? get_current_screen() : null;

		//if ( $screen && $screen->id !== 'woocommerce_page_wc-orders' ) return;
		if ( $screen && $screen->id === 'edit-eshb_booking' ) return;

		if ( $screen && 'woocommerce_page_wc-orders' === $screen->id ) {
			//return;
    	}

		// Retrieve the order object
		$order = wc_get_order($order_id);
	
		// Get the booking post ID from order meta
		$booking_post_id = get_post_meta($order_id, '_booking_post_created', true); // Adjusted to your meta key
	
		if ($booking_post_id) {

			// update booking status
            $updated_booking = array(
                'ID'           => $booking_post_id,
                'post_status'  => $new_status,
            );

            wp_update_post( $updated_booking );

			// Get the existing meta for the custom post
			$booking_meta = get_post_meta($booking_post_id, 'eshb_booking_metaboxes', true);
	
			// Ensure the meta is an array before modifying it
			if (is_array($booking_meta)) {
				// Update the `booking_status` field
				$booking_meta['booking_status'] = $new_status;
	
				// Save the updated meta back to the post
				update_post_meta($booking_post_id, 'eshb_booking_metaboxes', $booking_meta);
			}
		}
	}

	public function update_woocommerce_order_status_on_booking_status_change($post_id, $post, $update) {
		
		if(class_exists('ESHB_MANUAL_BOOKING') && is_admin()){
			return;
		}

		if ( ! function_exists( 'WC' ) ) {
			return;
		}

		// Ensure this runs only during post update
		if (!$update || wp_is_post_autosave($post_id) || wp_is_post_revision($post_id)) {
			return;
		}
	
		// Check if the post type matches
		if ($post->post_type !== 'eshb_booking') {
			return;
		}

		
	
		// Retrieve the metabox data
		$eshb_booking_metaboxes = get_post_meta($post_id, 'eshb_booking_metaboxes', true) ?? [];
	
		// Validate the required fields
		if (empty($eshb_booking_metaboxes) || empty($eshb_booking_metaboxes['booking_status']) || empty($eshb_booking_metaboxes['order_id'])) {
			return;
		}
	
		$booking_status = sanitize_text_field($eshb_booking_metaboxes['booking_status']);
		$order_id = intval($eshb_booking_metaboxes['order_id']);
	
		// Get the WooCommerce order object
		$order = wc_get_order($order_id);
		if (!$order) {
			return; // Invalid order
		}
	
		// Check if the current order status matches the booking status to avoid redundant updates
		if ($order->get_status() === $booking_status) {
			return; // Status is already up-to-date
		}
	
		try {
			$order->update_status($booking_status, 'Booking status updated to: ' . $booking_status);
		} catch (Exception $e) {
			// Log error for debugging
			//error_log('Error updating order status: ' . $e->getMessage());
		}
	}

	public function send_booking_email_notification_for_booking_status($post_id, $post, $update){

		// Ensure this runs only during post update
		if (!$update || wp_is_post_autosave($post_id) || wp_is_post_revision($post_id)) {
			return;
		}
	
		// Check if the post type matches
		if ($post->post_type !== 'eshb_booking') {
			return;
		}
	
		// Retrieve the metabox data
		$eshb_booking_metaboxes = get_post_meta($post_id, 'eshb_booking_metaboxes', true) ?? [];
	

		// Validate the required fields
		if (empty($eshb_booking_metaboxes) || empty($eshb_booking_metaboxes['booking_status']) || empty($eshb_booking_metaboxes['order_id'])) {
			return;
		}

		$booking_status = $post->post_status;
		$order_id = $eshb_booking_metaboxes['order_id'];

		$eshb_settings = get_option('eshb_settings', []);
		$booking_type = isset($eshb_settings['booking-type']) && !empty($eshb_settings['booking-type']) ? $eshb_settings['booking-type'] : 'woocommerce';


		do_action('eshb_booking_status_changed', $post_id, $booking_status, $booking_type, $order_id);

		if(class_exists('ESHB_Booking_Templates')) {
			return;
		}
		// send email for woocommerce
		if ( $booking_type == 'woocommerce' && function_exists( 'WC' ) ) {

			$order = wc_get_order($order_id);
			if (!$order) {
				return; // Invalid order
			}
			// Trigger email manually
			$mailer = WC()->mailer();
			
			switch ( $booking_status ) {

				case 'cancelled':
					$to      = $order->get_billing_email();
					$subject = sprintf(
						/* translators: %s: booking/post ID */
						__( 'Your Booking #%s has been Cancelled', 'easy-hotel' ),
						esc_html( $post_id )
					);
					$heading = __( 'Booking Cancelled', 'easy-hotel' );

					$first_name = esc_html( $order->get_billing_first_name() );
					$post_title = esc_html( get_the_title( $post_id ) );

					$message  = '<p>' . sprintf(
						/* translators: %s: customer first name */
						__( 'Hi %s,', 'easy-hotel' ),
						$first_name
					) . '</p>';

					$message .= '<p>' . sprintf(
						/* translators: %s: booking title */
						__( 'We regret to inform you that your <strong>%s</strong> has been <strong>cancelled</strong>.', 'easy-hotel' ),
						$post_title
					) . '</p>';

					$message .= '<p>' . __( 'If you have any questions, please feel free to reply to this email.', 'easy-hotel' ) . '</p>';
					$message .= '<p>' . __( 'Thank you for shopping with us.', 'easy-hotel' ) . '</p>';

					$this->send_email_woocommerce_style( $to, $subject, $heading, $message );
					break;
			}

		}
	}

	// -------------------------------------------------------------------------
	// Cart Blocking Methods
	// -------------------------------------------------------------------------

	private function eshb_get_session_token() {
		// Native Checkout does not use a WooCommerce session — the visitor
		// is identified by the per-visitor reservation token instead. Use
		// that as the hold key so holds created during the native flow are
		// attributed to (and excludable for) the right user across the
		// booking form, calendar and checkout page.
		if ( function_exists( 'eshb_native_checkout_is_enabled' ) && eshb_native_checkout_is_enabled()
			&& function_exists( 'eshb_native_checkout_get_token' ) ) {
			$native_token = eshb_native_checkout_get_token( false );
			if ( ! empty( $native_token ) ) {
				return 'native_' . $native_token;
			}
		}
		if ( class_exists( 'WooCommerce' ) && WC()->session ) {
			return (string) WC()->session->get_customer_id();
		}
		return '';
	}

	private function eshb_dates_overlap( $s1, $e1, $s2, $e2 ) {
		return $s1 < $e2 && $s2 < $e1;
	}

	private function eshb_get_blocking_settings() {
		$eshb_settings   = get_option( 'eshb_settings', [] );
		$enabled         = ! empty( $eshb_settings['cart-blocking-switcher'] );
		$blocking_time   = ! empty( $eshb_settings['cart-blocking-time'] ) ? (int) $eshb_settings['cart-blocking-time'] : 5;
		return [ 'enabled' => $enabled, 'minutes' => $blocking_time ];
	}

	private function eshb_set_cart_block( $accom_id, $start_date, $end_date, $room_qty ) {
		$cfg = $this->eshb_get_blocking_settings();
		if ( ! $cfg['enabled'] ) return 0;

		$session = $this->eshb_get_session_token();
		if ( empty( $session ) ) return 0;

		$key   = 'eshb_cart_holds_' . (int) $accom_id;
		$holds = get_transient( $key );
		if ( ! is_array( $holds ) ) $holds = [];

		$now   = time();
		$until = $now + ( $cfg['minutes'] * 60 );

		// Clean expired entries
		foreach ( $holds as $token => $hold ) {
			if ( $hold['until'] < $now ) unset( $holds[ $token ] );
		}

		$holds[ $session ] = [
			'start_date' => $start_date,
			'end_date'   => $end_date,
			'qty'        => (int) $room_qty,
			'until'      => $until,
		];

		set_transient( $key, $holds, $cfg['minutes'] * 60 + 60 );
		return $until;
	}

	private function eshb_check_cart_block( $accom_id, $start_date, $end_date ) {
		$cfg = $this->eshb_get_blocking_settings();
		if ( ! $cfg['enabled'] ) return '';

		$key   = 'eshb_cart_holds_' . (int) $accom_id;
		$holds = get_transient( $key );
		if ( ! is_array( $holds ) ) return '';

		$session = $this->eshb_get_session_token();
		$now     = time();

		foreach ( $holds as $token => $hold ) {
			if ( $token === $session ) continue;
			if ( $hold['until'] < $now ) continue;
			if ( $this->eshb_dates_overlap( $start_date, $end_date, $hold['start_date'], $hold['end_date'] ) ) {
				$remaining = (int) ceil( ( $hold['until'] - $now ) / 60 );
				/* translators: %d: remaining minutes */
				return sprintf( __( 'These dates are temporarily reserved by another user. Please try again in %d minute(s).', 'easy-hotel' ), $remaining );
			}
		}
		return '';
	}

	/**
	 * Remove the current visitor's hold for one accommodation, deleting the
	 * transient entirely when no holds remain. Shared by the cart-removal,
	 * order-completion and Native Checkout release paths.
	 */
	private function eshb_remove_session_hold( $accom_id ) {
		$accom_id = (int) $accom_id;
		if ( ! $accom_id ) return;

		$session = $this->eshb_get_session_token();
		if ( empty( $session ) ) return;

		$key   = 'eshb_cart_holds_' . $accom_id;
		$holds = get_transient( $key );
		if ( ! is_array( $holds ) ) return;

		unset( $holds[ $session ] );
		if ( empty( $holds ) ) {
			delete_transient( $key );
		} else {
			$cfg = $this->eshb_get_blocking_settings();
			set_transient( $key, $holds, $cfg['minutes'] * 60 + 60 );
		}
	}

	// -------------------------------------------------------------------------
	// Public cart-blocking API (used by the Native Checkout controller, which
	// is a separate class and short-circuits the WooCommerce add-to-cart flow)
	// -------------------------------------------------------------------------

	/**
	 * Place a temporary hold for a native reservation. Returns the unix
	 * timestamp the hold expires at, or 0 when blocking is disabled.
	 */
	public function eshb_block_dates_for_reservation( $accom_id, $start_date, $end_date, $room_qty ) {
		return $this->eshb_set_cart_block( $accom_id, $start_date, $end_date, $room_qty );
	}

	/**
	 * Whether the given dates collide with another visitor's active hold.
	 * Returns a translated message on conflict, or '' when clear.
	 */
	public function eshb_get_cart_block_conflict( $accom_id, $start_date, $end_date ) {
		return $this->eshb_check_cart_block( $accom_id, $start_date, $end_date );
	}

	/**
	 * Release the current visitor's hold for an accommodation (on
	 * completed booking or expired/abandoned native reservation).
	 */
	public function eshb_release_cart_block( $accom_id ) {
		$this->eshb_remove_session_hold( $accom_id );
	}

	/**
	 * Expiry timestamp (unix) of the current visitor's own hold for an
	 * accommodation, or 0 when there is none. Lets the Native Checkout
	 * page render an accurate countdown.
	 */
	public function eshb_get_my_block_until( $accom_id ) {
		$accom_id = (int) $accom_id;
		if ( ! $accom_id ) return 0;

		$holds = get_transient( 'eshb_cart_holds_' . $accom_id );
		if ( ! is_array( $holds ) ) return 0;

		$session = $this->eshb_get_session_token();
		if ( empty( $session ) || empty( $holds[ $session ]['until'] ) ) return 0;

		return (int) $holds[ $session ]['until'];
	}

	/**
	 * Expose the hold-countdown notice markup so the Native Checkout
	 * template can render the same banner used by the WooCommerce flow.
	 */
	public function eshb_cart_block_notice_html( $mode = 'inline' ) {
		return $this->eshb_get_blocking_notice_html( $mode );
	}

	public function eshb_add_blocked_dates_to_calendar( $all_dates, $accom_id, $accom_metas ) {
		$key   = 'eshb_cart_holds_' . (int) $accom_id;
		$holds = get_transient( $key );

		$blocked_ranges = [];
		if ( is_array( $holds ) ) {
			$now = time();
			// Show every active hold as "Reserved" on the calendar,
			// including the current visitor's own. The native flow keys
			// holds by a cookie token that is reliably present on this
			// AJAX request, so skipping the own session here would hide
			// the held dates from the holder (whereas the WooCommerce
			// session token isn't consistently resolved here, so its
			// holds always showed). Own-hold exclusion is kept only in
			// the booking-validation path so the holder can still finish
			// their own reservation.
			foreach ( $holds as $token => $hold ) {
				if ( $hold['until'] < $now ) continue;
				$blocked_ranges[] = [
					'start_date' => $hold['start_date'],
					'end_date'   => $hold['end_date'],
					'until'      => $hold['until'],
				];
			}
		}

		$all_dates['blocked_dates'] = $blocked_ranges;
		return $all_dates;
	}

	public function eshb_get_cart_blocks_ajax() {
		check_ajax_referer( ESHB_Helper::generate_secure_nonce_action( 'eshb_global_nonce_action' ), 'nonce' );

		$accom_id = isset( $_POST['accomodation_id'] ) ? (int) sanitize_text_field( wp_unslash( $_POST['accomodation_id'] ) ) : 0;
		if ( ! $accom_id ) {
			wp_send_json_error( [ 'message' => 'Invalid accommodation ID' ] );
			return;
		}

		$key   = 'eshb_cart_holds_' . $accom_id;
		$holds = get_transient( $key );

		$blocked_ranges = [];
		if ( is_array( $holds ) ) {
			$now = time();
			// Include every active hold (own included) so the calendar
			// renders the held dates as "Reserved" consistently across
			// the WooCommerce and Native Checkout flows. See the note in
			// eshb_add_blocked_dates_to_calendar().
			foreach ( $holds as $token => $hold ) {
				if ( $hold['until'] < $now ) continue;
				$blocked_ranges[] = [
					'start_date' => $hold['start_date'],
					'end_date'   => $hold['end_date'],
					'until'      => $hold['until'],
				];
			}
		}

		wp_send_json_success( [ 'blocked_ranges' => $blocked_ranges ] );
	}

	public function eshb_clear_cart_block_on_removal( $cart_item_key, $cart ) {
		$removed = isset( $cart->removed_cart_contents[ $cart_item_key ] ) ? $cart->removed_cart_contents[ $cart_item_key ] : null;
		if ( ! $removed ) return;

		$accom_id = isset( $removed['accomodation_id'] ) ? (int) $removed['accomodation_id'] : 0;
		if ( ! $accom_id ) return;

		$this->eshb_remove_session_hold( $accom_id );
	}

	public function eshb_render_calendar_legend( $accomodation_id = 0 ) {
		static $rendered = false;
		if ( $rendered || is_admin() ) return;
		$rendered = true;

		$eshb_settings       = get_option( 'eshb_settings', [] );
		$cart_blocking_on    = ! empty( $eshb_settings['cart-blocking-switcher'] );

		$items = [
			'available'     => [ 'class' => 'eshb-legend-available',  'label' => __( 'Available',    'easy-hotel' ) ],
			'selected'      => [ 'class' => 'eshb-legend-selected',   'label' => __( 'Selected',     'easy-hotel' ) ],
			'booked'        => [ 'class' => 'eshb-legend-booked',     'label' => __( 'Booked',       'easy-hotel' ) ],
			'holiday'       => [ 'class' => 'eshb-legend-holiday',    'label' => __( 'Holiday',      'easy-hotel' ) ],
		];

		if ( $cart_blocking_on ) {
			$items['reserved'] = [ 'class' => 'eshb-legend-reserved', 'label' => __( 'Reserved', 'easy-hotel' ) ];
		}

		$items = apply_filters( 'eshb_calendar_legend_items', $items, $accomodation_id );
		?>
		<div class="eshb-calendar-legend">
			<?php foreach ( $items as $item ) : ?>
			<div class="eshb-legend-item">
				<span class="eshb-legend-swatch <?php echo esc_attr( $item['class'] ); ?>"></span>
				<span class="eshb-legend-label"><?php echo esc_html( $item['label'] ); ?></span>
			</div>
			<?php endforeach; ?>
		</div>
		<?php
	}

	private function eshb_get_blocking_notice_html( $mode = 'fixed' ) {
		$eshb_settings = get_option( 'eshb_settings', [] );
		if ( empty( $eshb_settings['cart-blocking-switcher'] ) ) return '';

		$msg = ! empty( $eshb_settings['cart-blocking-notice-msg'] ) ? esc_html( $eshb_settings['cart-blocking-notice-msg'] ) : esc_html__( 'Your reservation is held for', 'easy-hotel' );

		$class = $mode === 'inline'
			? 'woocommerce-info eshb-cart-block-notice eshb-cart-block-notice--inline'
			: 'eshb-cart-block-notice eshb-cart-block-notice--fixed';

		return '<div id="eshb-cart-block-notice" class="' . $class . '" data-mode="' . esc_attr( $mode ) . '" style="display:none;" aria-live="polite">'
			. '&#x23F3; <span class="eshb-block-msg">' . $msg . '</span> <span class="eshb-block-timer">0:00</span>'
			. '</div>';
	}

	public function eshb_render_cart_block_notice_inline() {
		if ( $this->eshb_notice_printed || is_admin() ) return;
		$this->eshb_notice_printed = true;
		// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
		echo $this->eshb_get_blocking_notice_html( 'inline' );
	}

	public function eshb_prepend_notice_to_woo_block( $block_content, $block ) {
		if ( $this->eshb_notice_printed || is_admin() ) return $block_content;
		if ( ! in_array( $block['blockName'], [ 'woocommerce/cart', 'woocommerce/checkout' ], true ) ) return $block_content;
		$html = $this->eshb_get_blocking_notice_html( 'inline' );
		if ( ! $html ) return $block_content;
		$this->eshb_notice_printed = true;
		// Append for checkout to avoid breaking React hydration; prepend for cart
		return $block['blockName'] === 'woocommerce/checkout'
			? $block_content . $html
			: $html . $block_content;
	}

	public function eshb_footer_notice_fallback() {
		if ( $this->eshb_notice_printed || is_admin() ) return;
		if ( ! is_cart() && ! is_checkout() ) return;
		$html = $this->eshb_get_blocking_notice_html( 'inline' );
		if ( ! $html ) return;
		$this->eshb_notice_printed = true;
		// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
		echo $html;
	}

	public function eshb_clear_cart_on_block_expiry() {
		check_ajax_referer( ESHB_Helper::generate_secure_nonce_action( 'eshb_global_nonce_action' ), 'nonce' );
		if ( class_exists( 'WooCommerce' ) && WC()->cart ) {
			WC()->cart->empty_cart();
		}
		wp_send_json_success( [ 'cleared' => true ] );
	}

	public function eshb_check_my_session_blocks() {
		check_ajax_referer( ESHB_Helper::generate_secure_nonce_action( 'eshb_global_nonce_action' ), 'nonce' );

		$accom_ids = isset( $_POST['accom_ids'] ) ? array_map( 'intval', (array) $_POST['accom_ids'] ) : [];
		if ( empty( $accom_ids ) ) {
			wp_send_json_success( [ 'active_ids' => [] ] );
			return;
		}

		$session    = $this->eshb_get_session_token();
		$now        = time();
		$active_ids = [];

		foreach ( $accom_ids as $accom_id ) {
			if ( ! $accom_id ) continue;
			$holds = get_transient( 'eshb_cart_holds_' . $accom_id );
			if ( is_array( $holds ) && isset( $holds[ $session ] ) && $holds[ $session ]['until'] > $now ) {
				$active_ids[] = $accom_id;
			}
		}

		wp_send_json_success( [ 'active_ids' => $active_ids ] );
	}

	public function eshb_clear_session_cart_blocks_on_order( $order_id ) {
		if ( ! $order_id ) return;

		$session = $this->eshb_get_session_token();
		if ( empty( $session ) ) return;

		$order = wc_get_order( $order_id );
		if ( ! $order ) return;

		foreach ( $order->get_items() as $item ) {
			$accom_id = (int) $item->get_meta( 'accomodation_id' );
			if ( ! $accom_id ) continue;

			$this->eshb_remove_session_hold( $accom_id );
		}
	}

	public function eshb_checkout_order_review_qty_input( $qty_html, $cart_item, $cart_item_key ) {
		if ( ! is_checkout() ) return $qty_html;
		$eshb_settings = get_option( 'eshb_settings', [] );
		if ( empty( $eshb_settings['direct-booking'] ) ) return $qty_html;
		$nonce   = wp_create_nonce( ESHB_Helper::generate_secure_nonce_action( 'eshb_global_nonce_action' ) );
		$ajaxurl = esc_url( admin_url( 'admin-ajax.php' ) );
		return $qty_html
			. ' <button type="button" class="eshb-cart-remove-btn" aria-label="' . esc_attr__( 'Remove', 'easy-hotel' ) . '" data-cart-key="' . esc_attr( $cart_item_key ) . '" data-nonce="' . esc_attr( $nonce ) . '" data-ajaxurl="' . esc_attr( $ajaxurl ) . '"><i class="fas fa-times" aria-hidden="true"></i></button>';
	}

	public function eshb_remove_cart_item() {
		check_ajax_referer( ESHB_Helper::generate_secure_nonce_action( 'eshb_global_nonce_action' ), 'nonce' );
		$cart_item_key = sanitize_text_field( wp_unslash( $_POST['cart_item_key'] ?? '' ) );
		if ( $cart_item_key && class_exists( 'WooCommerce' ) && WC()->cart ) {
			WC()->cart->remove_cart_item( $cart_item_key );
		}
		wp_send_json_success();
	}

}
ESHB_Booking::instance();

// Registered once on the singleton (constructor runs multiple times due to `new ESHB_Booking()` calls elsewhere)
add_filter( 'woocommerce_checkout_cart_item_quantity', [ ESHB_Booking::instance(), 'eshb_checkout_order_review_qty_input' ], 10, 3 );
```
