<?php
namespace JET_ABAF;

use JET_ABAF\Render\Price_Breakdown as Price_Breakdown_Renderer;

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

class Ajax_Handlers {

	public function __construct() {
		if ( defined( 'DOING_AJAX' ) && DOING_AJAX ) {
			add_action( 'wp_ajax_jet_booking_get_timepicker_slots', [ $this, 'get_timepicker_slots' ] );
			add_action( 'wp_ajax_nopriv_jet_booking_get_timepicker_slots', [ $this, 'get_timepicker_slots' ] );

			add_action( 'wp_ajax_jet_booking_get_price_breakdown', [ $this, 'get_price_breakdown' ] );
			add_action( 'wp_ajax_nopriv_jet_booking_get_price_breakdown', [ $this, 'get_price_breakdown' ] );

			add_action( 'wp_ajax_jet_booking_submit_booking_form', [ $this, 'submit_booking_form' ] );
			add_action( 'wp_ajax_nopriv_jet_booking_submit_booking_form', [ $this, 'submit_booking_form' ] );
		}
	}

	/**
	 * Get timepicker slots.
	 *
	 * Retrieves available time slots for booking based on check-in and check-out dates.
	 *
	 * @since 3.7.0
	 *
	 * @return void
	 */
	public function get_timepicker_slots() {

		// phpcs:disable WordPress.Security.NonceVerification
		$post_id        = ! empty( $_POST['postID'] ) ? jet_abaf()->db->get_initial_booking_item_id( absint( $_POST['postID'] ) ) : 0;
		$check_in_date  = ! empty( $_POST['checkInDate'] ) ? strtotime( sanitize_text_field( wp_unslash( $_POST['checkInDate'] ) ) ) : '';
		$check_out_date = ! empty( $_POST['checkOutDate'] ) ? strtotime( sanitize_text_field( wp_unslash( $_POST['checkOutDate'] ) ) ) : '';
		$booking        = ! empty( $_POST['bookingID'] ) && absint( $_POST['bookingID'] ) ? jet_abaf_get_booking( absint( $_POST['bookingID'] ) ) : 0;
		// phpcs:enable WordPress.Security.NonceVerification

		wp_cache_delete( jet_abaf()->settings::CONTEXT_KEY, 'jet-booking' );
		wp_cache_set( jet_abaf()->settings::CONTEXT_KEY, $post_id, 'jet-booking', 60 );

		if ( $check_in_date >= $check_out_date ) {
			$check_out_date = $check_in_date + 12 * HOUR_IN_SECONDS;
		}

		$booking_check_in_time  = apply_filters( 'jet-booking/form-fields/check-in-time/default-value', '' );
		$booking_check_out_time = apply_filters( 'jet-booking/form-fields/check-out-time/default-value', '' );

		if ( $booking ) {
			$booking_check_in_time  = $booking->get_check_in_time();
			$booking_check_out_time = $booking->get_check_out_time();
		}

		$range_start = jet_abaf()->settings->get( 'timepicker_range_start' );
		$range_end   = jet_abaf()->settings->get( 'timepicker_range_end' );

		$check_in_time_slots  = jet_abaf()->tools->get_timepicker_slots( $range_start, $range_end, $booking_check_in_time );
		$check_out_time_slots = jet_abaf()->tools->get_timepicker_slots( $range_start, $range_end, $booking_check_out_time );

		if ( jet_abaf()->settings->get( 'timepicker_restrictions' ) ) {
			$buffer = jet_abaf()->settings->get( 'timepicker_buffer' );
			$units  = jet_abaf()->db->get_apartment_units( $post_id );

			// Сase when the selected check-in date falls on an existing check-out date.
			$check_in_bookings = jet_abaf()->db->query( [
				'apartment_id'   => $post_id,
				'check_out_date' => $check_in_date,
			] );

			if ( ! empty( $check_in_bookings ) && count( $check_in_bookings ) >= count( $units ) ) {
				$check_out_time = $check_in_bookings[0]['check_out_time'];

				foreach ( $check_in_bookings as $check_in_booking ) {
					if ( $check_out_time && $check_in_booking['check_out_time'] < $check_out_time ) {
						$check_out_time = $check_in_booking['check_out_time'];
					}
				}

				$check_in_start_time = '';

				if ( $check_out_time ) {
					$check_in_start_time = $check_out_time + $buffer;
				}

				if ( $check_in_start_time ) {
					$check_in_time_slots = jet_abaf()->tools->get_timepicker_slots( $check_in_start_time, $range_end, $booking_check_in_time );
				}
			}

			// Сase when the selected check-out date falls on an existing check-in date.
			$check_out_bookings = jet_abaf()->db->query( [
				'apartment_id'  => $post_id,
				'check_in_date' => $check_out_date + 1,
			] );

			if ( ! empty( $check_out_bookings ) && count( $check_out_bookings ) >= count( $units ) ) {
				$check_in_time = $check_out_bookings[0]['check_in_time'];

				foreach ( $check_out_bookings as $check_out_booking ) {
					if ( $check_in_time && $check_out_booking['check_in_time'] > $check_in_time ) {
						$check_in_time = $check_out_booking['check_in_time'];
					}
				}

				$check_out_end_time = '';

				if ( $check_in_time ) {
					$check_out_end_time = $check_in_time - $buffer;
				}

				if ( $check_out_end_time ) {
					$check_out_time_slots = jet_abaf()->tools->get_timepicker_slots( $range_start, $check_out_end_time, $booking_check_out_time );
				}
			}
		}

		$response['check_in_time_slots']  = $check_in_time_slots;
		$response['check_out_time_slots'] = $check_out_time_slots;

		wp_send_json_success( $response );

	}

	/**
	 * Get a price breakdown.
	 *
	 * Returns rendered breakdown markup for the selected booking period.
	 *
	 * @since 4.1.0
	 *
	 * @return void
	 * @throws \Exception
	 */
	public function get_price_breakdown() {

		// phpcs:disable WordPress.Security.NonceVerification
		$post_id        = ! empty( $_POST['postID'] ) ? absint( $_POST['postID'] ) : 0;
		$check_in_date  = ! empty( $_POST['checkInDate'] ) ? absint( $_POST['checkInDate'] ) : 0;
		$check_out_date = ! empty( $_POST['checkOutDate'] ) ? absint( $_POST['checkOutDate'] ) : 0;
		// phpcs:enable WordPress.Security.NonceVerification

		if ( ! $post_id || ! $check_in_date || ! $check_out_date ) {
			$renderer = new Price_Breakdown_Renderer( [ 'apartment_id' => $post_id ] );

			wp_send_json_success( [ 'html' => $renderer->get_content() ] );
		}

		wp_cache_delete( jet_abaf()->settings::CONTEXT_KEY, 'jet-booking' );
		wp_cache_set( jet_abaf()->settings::CONTEXT_KEY, $post_id, 'jet-booking', 60 );

		$price = new Price( $post_id );

		$booking = [
			'apartment_id'   => $post_id,
			'check_in_date'  => $check_in_date,
			'check_out_date' => $check_out_date,
		];

		$breakdown = $price->get_booking_price_breakdown( $booking );
		$renderer  = new Price_Breakdown_Renderer( $booking );

		wp_send_json_success( [ 'html' => $renderer->get_content( $breakdown ) ] );

	}

	/**
	 * Submit a booking form widget request.
	 *
	 * @since 4.1.0
	 *
	 * @return void
	 * @throws \Exception
	 */
	public function submit_booking_form() {

		$form_data = ! empty( $_POST['formData'] ) ? jet_abaf()->tools->sanitize_array_recursively( wp_unslash( $_POST['formData'] ) ) : [];
		$post_id   = ! empty( $form_data['jet_abaf_booking_instance_id'] ) ? jet_abaf()->db->get_initial_booking_item_id( absint( $form_data['jet_abaf_booking_instance_id'] ) ) : 0;

		if ( ! $post_id ) {
			wp_send_json_error( [ 'message' => __( 'Invalid booking instance.', 'jet-booking' ) ] );
		}

		if ( ! jet_abaf()->tools->is_booking_post( $post_id ) ) {
			wp_send_json_error( [ 'message' => __( 'The selected post does not belong to any configured booking instance post type.', 'jet-booking' ) ] );
		}

		$nonce = ! empty( $form_data['jet_abaf_booking_form_nonce'] ) ? sanitize_text_field( $form_data['jet_abaf_booking_form_nonce'] ) : '';

		if ( ! $nonce || ! wp_verify_nonce( $nonce, 'jet_abaf_booking_form_' . absint( $post_id ) ) ) {
			wp_send_json_error( [ 'message' => __( 'Security check failed.', 'jet-booking' ) ] );
		}

		wp_cache_delete( jet_abaf()->settings::CONTEXT_KEY, 'jet-booking' );
		wp_cache_set( jet_abaf()->settings::CONTEXT_KEY, $post_id, 'jet-booking', 60 );

		$check_in_date  = ! empty( $form_data['jet_abaf_field__in'] ) ? sanitize_text_field( $form_data['jet_abaf_field__in'] ) : '';
		$check_out_date = ! empty( $form_data['jet_abaf_field__out'] ) ? sanitize_text_field( $form_data['jet_abaf_field__out'] ) : '';

		if ( ! $check_in_date ) {
			wp_send_json_error( [ 'message' => __( 'Please select a date range.', 'jet-booking' ) ] );
		}

		if ( ! $check_out_date ) {
			$check_out_date = $check_in_date;
		}

		$check_in_object     = \DateTime::createFromFormat( '!Y-m-d', $check_in_date );
		$check_out_object    = \DateTime::createFromFormat( '!Y-m-d', $check_out_date );
		$check_in_timestamp  = $check_in_object && $check_in_object->format( 'Y-m-d' ) === $check_in_date ? $check_in_object->getTimestamp() : false;
		$check_out_timestamp = $check_out_object && $check_out_object->format( 'Y-m-d' ) === $check_out_date ? $check_out_object->getTimestamp() : false;

		if ( ! $check_in_timestamp || ! $check_out_timestamp ) {
			wp_send_json_error( [ 'message' => __( 'Please select a valid date range.', 'jet-booking' ) ] );
		}

		if ( date( 'Ymd', $check_in_timestamp ) < date( 'Ymd', current_time( 'timestamp' ) ) ) {
			wp_send_json_error( [ 'message' => __( 'You must choose a future date.', 'jet-booking' ) ] );
		}

		if ( $check_in_timestamp >= $check_out_timestamp ) {
			$check_out_timestamp = $check_in_timestamp + 12 * HOUR_IN_SECONDS;
		}

		$start_day_offset = jet_abaf()->settings->get_config_setting( $post_id, 'start_day_offset', [
			'start_date' => $check_in_timestamp,
			'end_date'   => $check_out_timestamp,
		] );

		if ( $start_day_offset ) {
			$start_date = strtotime( "midnight +{$start_day_offset} days", current_time( 'timestamp' ) );

			if ( $check_in_timestamp < $start_date ) {
				$possible_date = date_i18n( get_option( 'date_format', 'F j, Y' ), $start_date );

				wp_send_json_error( [
					/* translators: next available date */
					'message' => sprintf( __( 'The earliest booking possible is currently %s.', 'jet-booking' ), $possible_date ),
				] );
			}
		}

		$check_in_days  = jet_abaf()->settings->get_days_by_rule( $post_id, 'check_in' );
		$check_out_days = jet_abaf()->settings->get_days_by_rule( $post_id, 'check_out' );

		if ( ( ! empty( $check_in_days ) && ! in_array( date( 'w', $check_in_timestamp ), $check_in_days ) ) || ( ! empty( $check_out_days ) && ! in_array( date( 'w', $check_out_timestamp ), $check_out_days ) ) ) {
			wp_send_json_error( [ 'message' => __( 'Selected dates are not available.', 'jet-booking' ) ] );
		}

		$user_email = ! empty( $form_data['jet_abaf_user_email'] ) ? sanitize_email( $form_data['jet_abaf_user_email'] ) : '';

		if ( array_key_exists( 'jet_abaf_user_email', $form_data ) ) {
			if ( ! $user_email ) {
				wp_send_json_error( [ 'message' => __( 'E-mail address is a required field.', 'jet-booking' ) ] );
			}

			if ( ! is_email( $user_email ) ) {
				wp_send_json_error( [ 'message' => __( 'E-mail address is invalid.', 'jet-booking' ) ] );
			}
		}

		if ( ! $user_email && is_user_logged_in() ) {
			$user       = wp_get_current_user();
			$user_email = $user->user_email ?? '';
		}

		$booking = [
			'status'         => 'pending',
			'apartment_id'   => $post_id,
			'check_in_date'  => $check_in_timestamp,
			'check_out_date' => $check_out_timestamp,
			'user_email'     => $user_email,
		];

		if ( jet_abaf()->settings->get( 'timepicker' ) ) {
			$check_in_time  = ! empty( $form_data['check-in-time'] ) ? sanitize_text_field( $form_data['check-in-time'] ) : '';
			$check_out_time = ! empty( $form_data['check-out-time'] ) ? sanitize_text_field( $form_data['check-out-time'] ) : '';

			if ( ! $check_in_time || ! $check_out_time ) {
				wp_send_json_error( [ 'message' => __( 'Time is required.', 'jet-booking' ) ] );
			}

			$booking['check_in_time']  = $check_in_time;
			$booking['check_out_time'] = $check_out_time;
		}

		if ( is_user_logged_in() ) {
			$booking['user_id'] = get_current_user_id();
		}

		$is_available        = jet_abaf()->db->booking_availability( $booking );
		$is_dates_available  = jet_abaf()->db->is_booking_dates_available( $booking );
		$is_period_available = jet_abaf()->tools->is_booking_period_available( $booking );

		if ( ! $is_period_available || ( ! $is_available && ! $is_dates_available ) ) {
			wp_send_json_error( [ 'message' => __( 'Selected dates are not available.', 'jet-booking' ) ] );
		}

		$booking_id = jet_abaf()->db->insert_booking( $booking );

		if ( ! $booking_id ) {
			wp_send_json_error( [ 'message' => __( 'Booking could not be created. Selected dates are no longer available.', 'jet-booking' ) ] );
		}

		do_action( 'jet-booking/form-action/booking-inserted', $booking_id );

		wp_send_json_success( [ 'message' => __( 'Booking was created successfully.', 'jet-booking' ) ] );

	}

}
