<?php
/**
 * AJAX Event Handlers.
 *
 * @class   HBFWC_AJAX
 * @package HBFWC\Classes
 */

use function HBFWC\HBF_WC;

defined( 'ABSPATH' ) || exit;

/**
 * WC_Ajax class.
 */
class HBFWC_AJAX {
	/**
	 * Hook in ajax handlers.
	 */
	public static function init() {
		add_action( 'template_redirect', array( __CLASS__, 'checkin_detection' ) );
		self::register_ajax_events();
	}

	/**
	 * Register ajax events & handlers.
	 */
	public static function register_ajax_events() {
		$ajax_events = array(
			'update_room_data',
			'update_room_price',
			'update_room_status',
			'update_rate_status',
			'create_new_amenity',
			'bulk_update',
		);

		foreach ( $ajax_events as $ajax_event ) {
			add_action( 'wp_ajax_hbfwc_' . $ajax_event, array( __CLASS__, $ajax_event ) );
		}
	}

	/**
	 * Bulk update.
	 */
	public static function bulk_update() {
		check_ajax_referer( 'run-bulk-update', 'security' );

		if ( ! current_user_can( 'edit_products' ) || ! isset( $_POST['data'] ) ) { // phpcs:ignore WordPress.WP.Capabilities.Unknown
			wp_die( -1 );
		}

		try {
			$data = map_deep( wp_unslash( $_POST['data'] ), 'sanitize_text_field' );

			$product_id = isset( $data['bulk_unit_id'] ) ? absint( $data['bulk_unit_id'] ) : false;
			$rates      = isset( $data['bulk_rates'] ) ? array_map( 'absint', $data['bulk_rates'] ) : array();
			$dates      = isset( $data['bulk_dates'] ) ? array_map( 'sanitize_text_field', $data['bulk_dates'] ) : array();
			$weekdays   = isset( $data['bulk_weekdays'] ) ? array_map( 'absint', $data['bulk_weekdays'] ) : array();
			$actions    = isset( $data['action_set'] ) ? $data['action_set'] : array();

			if ( ! $product_id || empty( $rates ) || empty( $dates ) || empty( $weekdays ) || empty( $actions ) ) {
				wp_send_json_error( array( 'error' => __( 'Cannot process the bulk updates. Please complete all fields', 'hotel-booking-for-woocommerce' ) ) );
				wp_die();
			}

			foreach ( $dates as $date_set ) {
				$date_set = explode( '-', $date_set );
				if ( count( $date_set ) < 2 ) {
					continue;
				}

				// Set the date.
				$from = new \DateTime( $date_set[0] );
				$end  = new \DateTime( $date_set[1] );

				// Read the actions.
				foreach ( $actions as $act_id => $act_value ) {
					// Get the action set.
					$action_next = isset( $data[ "action_next_{$act_id}_{$act_value}" ] ) ? sanitize_text_field( wp_unslash( $data[ "action_next_{$act_id}_{$act_value}" ] ) ) : '';
					$action_val  = isset( $data[ "action_value_{$act_id}_{$act_value}" ] ) ? sanitize_text_field( wp_unslash( $data[ "action_value_{$act_id}_{$act_value}" ] ) ) : '';

					// Dont bother if empty.
					if ( '' === $action_next || '' === $action_val ) {
						continue;
					}

					$args = array(
						'set'      => $action_next,
						'value'    => $action_val,
						'from'     => $from->format( 'Y-m-d' ),
						'end'      => $end->format( 'Y-m-d' ),
						'weekdays' => $weekdays,
					);

					// Get the global actions.
					if ( in_array( $act_value, array( 'availability', 'status' ), true ) ) {
						do_action( 'hbfwc_bulk_global_action', $act_value, $product_id, $args );
					} else {
						foreach ( $rates as $rate_id ) {
							do_action( 'hbfwc_bulk_rate_action', $act_value, $product_id, $rate_id, $args );
						}
					}
				}
			}

			wp_send_json_success(
				array(
					'message' => __( 'Bulk update is successfully performed.', 'hotel-booking-for-woocommerce' ),
				),
				201
			);
			wp_die();
		} catch ( \Exception $e ) {
			wp_send_json_error( array( 'error' => $e->getMessage() ) );
			wp_die();
		}
	}

	/**
	 * Update room data.
	 */
	public static function update_room_data() {
		check_ajax_referer( 'update-quantity', 'security' );

		if ( ! current_user_can( 'edit_products' ) || ! isset( $_POST['data'], $_POST['post_id'] ) ) { // phpcs:ignore WordPress.WP.Capabilities.Unknown
			wp_die( -1 );
		}

		try {
			$data = map_deep( wp_unslash( $_POST['data'] ), 'sanitize_text_field' );

			self::update_room_quantity( $data );

			wp_send_json_success();
			wp_die();
		} catch ( Exception $e ) {
			wp_send_json_error( array( 'error' => $e->getMessage() ) );
			wp_die();
		}
	}

	/**
	 * Update room status.
	 */
	public static function update_room_status() {
		check_ajax_referer( 'update-status', 'security' );

		if ( ! current_user_can( 'edit_products' ) || ! isset( $_POST['data'], $_POST['post_id'] ) ) { // phpcs:ignore WordPress.WP.Capabilities.Unknown
			wp_die( -1 );
		}

		try {
			$data = map_deep( wp_unslash( $_POST['data'] ), 'sanitize_text_field' );

			self::update_room_status_db( $data );

			wp_send_json_success();
			wp_die();
		} catch ( Exception $e ) {
			wp_send_json_error( array( 'error' => $e->getMessage() ) );
			wp_die();
		}
	}

	/**
	 * Update room price.
	 */
	public static function update_room_price() {
		check_ajax_referer( 'update-room-price', 'security' );

		if ( ! current_user_can( 'edit_products' ) || ! isset( $_POST['data'], $_POST['post_id'] ) ) { // phpcs:ignore WordPress.WP.Capabilities.Unknown
			wp_die( -1 );
		}

		try {
			$data = map_deep( wp_unslash( $_POST['data'] ), 'sanitize_text_field' );

			self::update_room_price_action( $data );

			wp_send_json_success();
			wp_die();
		} catch ( Exception $e ) {
			wp_send_json_error( array( 'error' => $e->getMessage() ) );
			wp_die();
		}
	}

	/**
	 * Update rate status.
	 */
	public static function update_rate_status() {
		check_ajax_referer( 'update-rate-status', 'security' );

		if ( ! current_user_can( 'edit_products' ) || ! isset( $_POST['data'], $_POST['post_id'] ) ) { // phpcs:ignore WordPress.WP.Capabilities.Unknown
			wp_die( -1 );
		}

		try {
			$data = map_deep( wp_unslash( $_POST['data'] ), 'sanitize_text_field' );

			if ( ! isset( $_POST['post_id'], $data['rate_id'], $data['date'], $data['status'] ) ) {
				wp_die( -1 );
			}

			$product_id = absint( wp_unslash( $_POST['post_id'] ) );

			if ( false !== hbfwc_is_pro() ) {
				// Pro version has own method.
				do_action( 'hbfwc_update_rate_status', $product_id, $data );
			} elseif ( absint( $data['rate_id'] ) === absint( get_option( 'hbfwc_default_rate_id', 0 ) ) ) {
				$product = \wc_get_product( $product_id );

				if ( ! $product ) {
					wp_die( -1 );
				}

				$current = get_post_meta( $product_id, '_default_rate_prices', true );
				$current = is_array( $current ) ? $current : array();

				$date_utc = absint( $data['date'] );
				$arr_key  = wp_date( 'Ymd', $date_utc );

				$default_price = $product->get_rate_default_price( $data['rate_id'], true, false );
				$default_price = wc_format_decimal( $default_price, wc_get_price_decimals() );

				$data_before = isset( $current[ $arr_key ] ) ? $current[ $arr_key ] : array();

				if ( ! empty( $data_before ) && ( 0 < absint( $data['status'] ) && $default_price === $data_before['price'] ) ) {
					// Let's keep it clean.
					unset( $current[ $arr_key ] );
				} else {
					$current[ $arr_key ] = array(
						'date'   => wp_date( 'Y-m-d', $date_utc ),
						'price'  => ( isset( $data_before['price'] ) ? $data_before['price'] : $default_price ),
						'status' => absint( $data['status'] ),
					);
				}

				update_post_meta( $product_id, '_default_rate_prices', $current );
			}

			wp_send_json_success();
			wp_die();
		} catch ( Exception $e ) {
			wp_send_json_error( array( 'error' => $e->getMessage() ) );
			wp_die();
		}
	}

	/**
	 * New amenity.
	 */
	public static function create_new_amenity() {
		check_ajax_referer( 'create-new-amenity', 'security' );

		if ( ! current_user_can( 'edit_products' ) || ! isset( $_POST['data'] ) ) { // phpcs:ignore WordPress.WP.Capabilities.Unknown
			wp_die( -1 );
		}

		try {
			add_filter( 'wp_kses_allowed_html', 'hbfwc_add_allowed_svg', 10, 2 );
			$data = map_deep( wp_unslash( $_POST['data'] ), 'wp_kses_post' );
			remove_filter( 'wp_kses_allowed_html', 'hbfwc_add_allowed_svg', 10 );

			$term = wp_insert_term(
				$data['name'],
				'amenities'
			);

			if ( is_wp_error( $term ) ) {
				wp_send_json_error( array( 'error' => $term->get_error_message() ) );
				wp_die();
			}

			// Group.
			update_term_meta( $term['term_id'], 'group', $data['group'] );

			// Icon.
			$icon = $data['icon_type'];
			if ( 'svg' === $icon ) {
				$icon_html = ( $data['svg'] !== '' ? wp_kses( $data['svg'], hbfwc_get_svg_args() ) : '' );
				update_term_meta( $term['term_id'], 'icon_svg', $icon_html );
			} else {
				update_term_meta( $term['term_id'], 'icon_class', $data['icon_class'] );
				$icon_html = '<i class="' . esc_attr( $data['icon_class'] ) . '"></i>';
			}
			update_term_meta( $term['term_id'], 'icon_type', $icon );

			$send_back = array(
				'term' => '<li><label><input type="checkbox" name="amenity[]" value="' . esc_attr( $term['term_id'] ) . '" checked></input>' . $icon_html . ' ' . $data['name'] . '</label></li>',
			);

			wp_send_json( $send_back );
			wp_die();
		} catch ( Exception $e ) {
			wp_send_json_error( array( 'error' => $e->getMessage() ) );
			wp_die();
		}
	}

	/**
	 * Update/delete rate price.
	 *
	 * @param array $data Data set to save.
	 *
	 * @return mixed
	 */
	private static function update_room_price_action( $data ) {
		// phpcs:disable WordPress.Security.NonceVerification.Missing
		if ( ! isset( $_POST['post_id'], $data['rate_id'], $data['date'], $data['price'] ) ) {
			wp_die( -1 );
		}

		$product_id = absint( wp_unslash( $_POST['post_id'] ) );

		if ( false !== hbfwc_is_pro() ) {

			do_action( 'hbfwc_update_room_price', $product_id, $data );

		} elseif ( absint( $data['rate_id'] ) === absint( get_option( 'hbfwc_default_rate_id', 0 ) ) ) {
			$product = \wc_get_product( $product_id );

			if ( ! $product ) {
				wp_die( -1 );
			}

			$current = get_post_meta( $product_id, '_default_rate_prices', true );
			$current = is_array( $current ) ? $current : array();

			$date_utc = absint( $data['date'] );
			$arr_key  = wp_date( 'Ymd', $date_utc );

			$default_price = $product->get_rate_default_price( $data['rate_id'], true, false );
			$default_price = wc_format_decimal( $default_price, wc_get_price_decimals() );

			// Normalize the price string.
			$price = wc_format_decimal( $data['price'], wc_get_price_decimals() );

			$data_before = isset( $current[ $arr_key ] ) ? $current[ $arr_key ] : array();

			if ( ! empty( $data_before ) && isset( $data_before['status'] ) && ( 0 < absint( $data_before['status'] ) && $default_price === $price ) ) {
				unset( $current[ $arr_key ] );
			} else {
				$current[ $arr_key ] = array(
					'date'   => wp_date( 'Y-m-d', $date_utc ),
					'price'  => $price,
					'status' => ( isset( $data_before['status'] ) ? absint( $data_before['status'] ) : 1 ),
				);
			}

			update_post_meta( $product_id, '_default_rate_prices', $current );
		}
		// phpcs:enable
	}

	/**
	 * Update/delete room quantity.
	 *
	 * @param array $data Data set to save.
	 *
	 * @return mixed
	 */
	private static function update_room_quantity( $data ) {
		// phpcs:disable WordPress.Security.NonceVerification.Missing
		if ( ! isset( $_POST['post_id'] ) ) {
			wp_die( -1 );
		}

		$product_id = absint( wp_unslash( $_POST['post_id'] ) );
		$is_max     = absint( $data['qty'] ) === absint( $data['max'] );

		$date_ts      = absint( $data['date'] );
		$maybe_update = HBF_WC()->db->get_single_date_entry( $product_id, wp_date( 'Y-m-d', $date_ts ) );

		$dates = [];
		if ( $maybe_update ) {

			$current_qty = $maybe_update->qty;
			if ( 1 > intval($current_qty) || 1 > intval($data['qty']) ) {
				$dates[] = [
					'id'   => $product_id,
					'date' => wp_date('Y-m-d', $date_ts),
				];
			}

			if ( absint( $maybe_update->status ) === 1 && $is_max ) {
				HBF_WC()->db->delete_entry( $maybe_update->id );
				$result = true;
			} else {
				$result = HBF_WC()->db->update(
					$maybe_update->id,
					array(
						'qty' => absint( $data['qty'] ),
					),
					array( '%d' ),
				);
			}

		} else {
			if ( 1 > intval($data['qty']) ) {
				$dates[] = [
					'id'   => $product_id,
				'date' => wp_date('Y-m-d', $date_ts),
			];
			}

			$result = HBF_WC()->db->add_new(
				array(
					'post_id'      => $product_id,
					'qty'          => absint( $data['qty'] ),
					'booking_date' => wp_date( 'Y-m-d', $date_ts ),
				),
				array( '%d', '%d', '%s' ),
			);
		}

		if ( ! $result || null === $result ) {
			wp_die( -1 );
		}
		// phpcs:enable

		if ( ! empty($dates) ) {
			if ( 1 > intval($data['qty']) ) {
				do_action( 'hbfwc_reduced_stock_zero', $dates );
			} else {
				do_action( 'hbfwc_release_stock_zero', $dates );
			}
		}

		return $result;
	}

	/**
	 * Update room status.
	 *
	 * @param array $data Data set to save.
	 *
	 * @return mixed
	 */
	private static function update_room_status_db( $data ) {
		// phpcs:disable WordPress.Security.NonceVerification.Missing
		if ( ! isset( $_POST['post_id'] ) ) {
			wp_die( -1 );
		}

		$product_id    = absint( wp_unslash( $_POST['post_id'] ) );
		$is_on_max     = absint( $data['qty'] ) === absint( $data['max'] );
		$date_ts       = absint( $data['date'] );

		$maybe_update  = HBF_WC()->db->get_single_date_entry( $product_id, wp_date( 'Y-m-d', $date_ts ) );
		$error_message = apply_filters( 'hbfwc_update_room_status_db', '', $product_id, wp_date( 'Y-m-d', $date_ts ) );
		if ( '' !== $error_message ) {
			wp_send_json_error( array( 'error' => $error_message ) );
		}

		if ( $maybe_update ) {
			if ( absint( $data['status'] ) === 1 && $is_on_max ) {
				HBF_WC()->db->delete_entry( $maybe_update->id );
				$result = true;
			} else {

				$result = HBF_WC()->db->update(
					$maybe_update->id,
					array(
						'status' => absint( $data['status'] ),
					),
					array( '%d' ),
				);
			}
		} else {
			$result = HBF_WC()->db->add_new(
				array(
					'post_id'      => $product_id,
					'qty'          => absint( $data['qty'] ),
					'booking_date' => wp_date( 'Y-m-d', $date_ts ),
					'status'       => absint( $data['status'] ),
				),
				array( '%d', '%d', '%s', '%d' ),
			);
		}

		if ( ! $result || null === $result ) {
			wp_die( -1 );
		}
		// phpcs:enable

		$dates = [[
			'id'   => $product_id,
			'date' => wp_date('Y-m-d', $date_ts),
		]];
		
		if ( absint( $data['status'] ) === 1 ) {
			do_action( 'hbfwc_release_stock_zero', $dates );
		} else {
			do_action( 'hbfwc_reduced_stock_zero', $dates );
		}

		return $result;
	}

	/**
	 * Make sure checkin query param is right.
	 */
	public static function checkin_detection() {
		// phpcs:disable WordPress.Security.NonceVerification.Recommended
		$checkin = isset( $_GET['checkin'] ) ? sanitize_text_field( wp_unslash( $_GET['checkin'] ) ) : wp_date( 'm/d/Y', strtotime( 'tomorrow' ) );

		if ( wp_date( 'Y-m-d', strtotime($checkin) ) < wp_date( 'Y-m-d' ) ) {
			global $post;
			$link = get_permalink();
			if ( $link ) {
				wp_safe_redirect( $link );
				exit;
			}
		}
		// phpcs:enable
	}
}

HBFWC_AJAX::init();
