<?php

namespace WeDevs\AppBridge\Integrations\WooCommerce\REST;

use Exception;
use WC_Bookings_Cost_Calculation;
use WC_Bookings_REST_Products_Controller;
use WP_REST_Server;

/**
 * Class BookingsController
 * @package WeDevs\DokanApp\Bookings
 *
 * @author weDevs
 */
class BookingsController extends WC_Bookings_REST_Products_Controller {
    /**
     * Endpoint namespace
     *
     * @var string
     */
    protected $namespace = 'app-bridge/v1';

    /**
     * Route name
     *
     * @var string
     */
    protected $rest_base = 'pocket-store';

    public function __construct() {
        $this->register_routes();
    }

    /**
     * Register routes
     *
     * @since 1.0.0
     *
     * @return void
     */
    public function register_routes() {
        register_rest_route(
            $this->namespace, '/' . $this->rest_base . '/bookings/products/(?P<id>[\d]+)', [
				[
					'methods'             => WP_REST_Server::READABLE,
					'callback'            => [ $this, 'get_item' ],
					'permission_callback' => '__return_true',
					'args'                => [
						'id' => [
							'description' => __( 'Unique identifier for the resource.', 'app-bridge' ),
							'type'        => 'integer',
							'required'    => true,
						],
					],
				],
				[
					'methods'             => WP_REST_Server::CREATABLE,
					'callback'            => [ $this, 'get_item_price' ],
					'permission_callback' => '__return_true',
					'args'                => [
						'id' => [
							'description' => __( 'Unique identifier for the resource.', 'app-bridge' ),
							'type'        => 'integer',
							'required'    => true,
						],
						'start_date_year' => [
							'description' => __( 'Start date year for the booking.', 'app-bridge' ),
							'type'        => 'integer',
							'required'    => true,
							'minimum'     => 1900,
							'maximum'     => 3000,
						],
						'start_date_month' => [
							'description' => __( 'Start date month for the booking.', 'app-bridge' ),
							'type'        => 'integer',
							'required'    => true,
							'minimum'     => 1,
							'maximum'     => 12,
						],
						'start_date_day' => [
							'description' => __( 'Start date day for the booking.', 'app-bridge' ),
							'type'        => 'integer',
							'required'    => true,
							'minimum'     => 1,
							'maximum'     => 31,
						],
						'start_date_time' => [
							'description' => __( 'Start time for the booking (for time-based bookings).', 'app-bridge' ),
							'type'        => 'string',
							'required'    => false,
						],
						'end_date_year' => [
							'description' => __( 'End date year for the booking (for date range bookings).', 'app-bridge' ),
							'type'        => 'integer',
							'required'    => false,
							'minimum'     => 1900,
							'maximum'     => 3000,
						],
						'end_date_month' => [
							'description' => __( 'End date month for the booking (for date range bookings).', 'app-bridge' ),
							'type'        => 'integer',
							'required'    => false,
							'minimum'     => 1,
							'maximum'     => 12,
						],
						'end_date_day' => [
							'description' => __( 'End date day for the booking (for date range bookings).', 'app-bridge' ),
							'type'        => 'integer',
							'required'    => false,
							'minimum'     => 1,
							'maximum'     => 31,
						],
						'end_date_time' => [
							'description' => __( 'End time for the booking (for time-based bookings).', 'app-bridge' ),
							'type'        => 'string',
							'required'    => false,
						],
						'duration' => [
							'description' => __( 'Duration of the booking in the product duration unit.', 'app-bridge' ),
							'type'        => 'integer',
							'required'    => false,
							'minimum'     => 1,
						],
						'resource' => [
							'description' => __( 'Resource ID for the booking (if product has resources).', 'app-bridge' ),
							'type'        => 'integer',
							'required'    => false,
						],
						'persons' => [
							'description' => __( 'Number of persons for the booking (if product has person types).', 'app-bridge' ),
							'type'        => 'integer',
							'required'    => false,
							'minimum'     => 1,
						],
						'person_types' => [
							'description' => __( 'Person types with counts for the booking (if product has multiple person types).', 'app-bridge' ),
							'type'        => 'object',
							'required'    => false,
							'properties'  => [
								'additionalProperties' => [
									'type'    => 'integer',
									'minimum' => 0,
								],
							],
						],
					],
				],
			]
        );
    }

    /**
     * Get bookable product data and added resource name and ids list
     *
     * @param \WC_Product_Booking $product
     * @param string $context
     *
     * @return array
     */
    protected function get_product_data( $product, $context = 'view' ) {
        $is_vaild_rest_type = 'booking' === $product->get_type();
        $is_vaild_rest_type = apply_filters( 'woocommerce_bookings_product_type_rest_check', $is_vaild_rest_type, $product );
        if ( ! $is_vaild_rest_type ) {
            wp_send_json( __( 'Not a bookable product', 'app-bridge' ), 400 );
        }

        $data = parent::get_product_data( $product, $context = 'view' );

        $resource_list_data = [
            'resource_list' => [],
            'booking_resources' => [],
        ];

        // making a list with resource_id and name
        foreach ( $data['resource_ids'] as $key => $resource_id ) {
            $resource = $product->get_resource( absint( $resource_id ) );

            /**
             * The code below is copied from a private method named `resources_field` in `WC_Booking_Form` class to format the resource label.
             *
             * @see \WC_Booking_Form::resources_field()
             */
            $cost_plus_base  = $resource->get_base_cost() + $resource->get_block_cost() + $product->get_cost();
            $additional_cost = array();

            if ( $resource->get_base_cost() && $product->get_block_cost() < $cost_plus_base ) {
                // if display cost price is set, don't calculate the difference
                if ( '' !== $product->get_display_cost() ) {
                    $additional_cost[] = '+' . wp_strip_all_tags( wc_price( $cost_plus_base ) );
                } else {
                    $additional_cost[] = '+' . wp_strip_all_tags( wc_price( (float) $resource->get_base_cost() ) );
                }
            }

            if ( $resource->get_block_cost() && ! $product->get_display_cost() ) {
                $duration      = $product->get_duration();
                $duration_unit = $product->get_duration_unit();

                if ( 'minute' === $duration_unit ) {
                    $duration_unit = _n( 'minute', 'minutes', $duration, 'app-bridge' );
                } elseif ( 'hour' === $duration_unit ) {
                    $duration_unit = _n( 'hour', 'hours', $duration, 'app-bridge' );
                } elseif ( 'day' === $duration_unit ) {
                    $duration_unit = _n( 'day', 'days', $duration, 'app-bridge' );
                } elseif ( 'month' === $duration_unit ) {
                    $duration_unit = _n( 'month', 'months', $duration, 'app-bridge' );
                } else {
                    $duration_unit = _n( 'block', 'blocks', $duration, 'app-bridge' );
                }

                // Check for singular display.
                if ( 1 === $duration ) {
                    $duration_display = sprintf( '%s', $duration_unit );
                } else {
                    // Plural.
                    $duration_display = sprintf( '%d %s', $duration, $duration_unit );
                }

                $duration_display = apply_filters( 'woocommerce_bookings_resource_duration_display_string', $duration_display, $product );

                /* translators: 1: block cost 2: duration unit */
                $additional_cost[] = sprintf( __( '+%1$1s per %2$2s', 'app-bridge' ), wp_strip_all_tags( wc_price( $resource->get_block_cost() ) ), $duration_display );
            }

            if ( $additional_cost ) {
                $additional_cost_string = ' (' . implode( ', ', $additional_cost ) . ')';
            } else {
                $additional_cost_string = '';
            }

            $resource_label = $resource->get_name() . apply_filters( 'woocommerce_bookings_resource_additional_cost_string', $additional_cost_string, $resource );

            $resource_list_data['resource_list'][ $resource_id ]            = $resource->get_name();
            $resource_list_data['booking_resources'][ $key ]['label']       = $resource_label;
            $resource_list_data['booking_resources'][ $key ]['value']       = $resource->get_name() . ' ( ' . $resource->get_base_cost() . ', ' . $resource->get_block_cost() . ' )';
            $resource_list_data['booking_resources'][ $key ]['resource_id'] = $resource_id;
        }

        $person_type_data = [
            'has_person_list' => [],
        ];

        foreach ( $data['person_types'] as $key => $person_type ) {
            $person_type_name  = $product->get_person( absint( $key ) )->get_name();
            $person_min_limit  = $product->get_person( absint( $key ) )->get_min();
            $person_max_limit  = $product->get_person( absint( $key ) )->get_max();
            $person_cost       = $product->get_person( absint( $key ) )->get_cost();
            $person_block_cost = $product->get_person( absint( $key ) )->get_block_cost();

            $person_type_data['has_person_list'][ $key ]['name']       = $person_type_name;
            $person_type_data['has_person_list'][ $key ]['min']        = $person_min_limit;
            $person_type_data['has_person_list'][ $key ]['max']        = $person_max_limit;
            $person_type_data['has_person_list'][ $key ]['base_cost']  = $person_cost;
            $person_type_data['has_person_list'][ $key ]['block_cost'] = $person_block_cost;
        }

        return array_merge( $data, $resource_list_data, $person_type_data );
    }

    /**
     * Calculate booking price for given parameters
     *
     * @param \WP_REST_Request $request Full details about the request.
     * @return \WP_REST_Response|\WP_Error Response object on success, or WP_Error object on failure.
     */
    public function get_item_price( $request ) {
        $booking_id = absint( $request['id'] );
        $product    = wc_get_product( $booking_id );
        $booking    = get_wc_product_booking( $product );

        if ( ! $product ) {
            return new \WP_Error(
                'booking_product_not_found',
                __( 'This booking is unavailable.', 'app-bridge' ),
                array( 'status' => 400 )
            );
        }

        // Get request parameters
        $request_params = $request->get_params();

        // Convert request parameters to format expected by wc_bookings_get_posted_data
        $posted_data = array();
        $posted_data['add-to-cart'] = $booking_id;

        // Map common booking fields from request to posted format
        $field_mappings = array(
            'start_date_year'  => 'wc_bookings_field_start_date_year',
            'start_date_month' => 'wc_bookings_field_start_date_month',
            'start_date_day'   => 'wc_bookings_field_start_date_day',
            'start_date_time'  => 'wc_bookings_field_start_date_time',
            'end_date_year'    => 'wc_bookings_field_end_date_year',
            'end_date_month'   => 'wc_bookings_field_end_date_month',
            'end_date_day'     => 'wc_bookings_field_end_date_day',
            'end_date_time'    => 'wc_bookings_field_end_date_time',
            'duration'         => 'wc_bookings_field_duration',
            'resource'         => 'wc_bookings_field_resource',
            'persons'          => 'wc_bookings_field_persons',
        );

        foreach ( $field_mappings as $request_key => $posted_key ) {
            if ( isset( $request_params[ $request_key ] ) ) {
                $posted_data[ $posted_key ] = $request_params[ $request_key ];
            }
        }

        // Handle person types if they exist
        if ( isset( $request_params['person_types'] ) && is_array( $request_params['person_types'] ) ) {
            foreach ( $request_params['person_types'] as $person_id => $person_count ) {
                $posted_data[ 'wc_bookings_field_persons_' . $person_id ] = absint( $person_count );
            }
        }

        // Handle dynamic person type fields (wc_bookings_field_persons_{PERSON_TYPE_ID})
        foreach ( $request_params as $param_name => $param_value ) {
            if ( preg_match( '/^wc_bookings_field_persons_(\d+)$/', $param_name, $matches ) ) {
                $person_type_id = absint( $matches[1] );
                $person_count = absint( $param_value );

                // Only process if person count is greater than 0 (same validation as WooCommerce Bookings)
                if ( $person_count > 0 ) {
                    $posted_data[ $param_name ] = $person_count;
                }
            }
        }

        try {
            $booking_data = wc_bookings_get_posted_data( $posted_data, $product );
            $cost = WC_Bookings_Cost_Calculation::calculate_booking_cost( $booking_data, $product );

            if ( is_wp_error( $cost ) ) {
                return new \WP_Error(
                    'booking_cost_calculation_error',
                    $cost->get_error_message(),
                    array( 'status' => 400 )
                );
            }

            $tax_display_mode = get_option( 'woocommerce_tax_display_shop' );

            if ( 'incl' === $tax_display_mode ) {
                if ( function_exists( 'wc_get_price_including_tax' ) ) {
                    $display_price = wc_get_price_including_tax( $product, array( 'price' => $cost ) );
                } else {
                    $display_price = $product->get_price_including_tax( 1, $cost );
                }
            } elseif ( function_exists( 'wc_get_price_excluding_tax' ) ) {
                    $display_price = wc_get_price_excluding_tax( $product, array( 'price' => $cost ) );
			} else {
				$display_price = $product->get_price_excluding_tax( 1, $cost );
            }

            $price_suffix = $product->get_price_suffix( $cost, 1 );

            $response_data = array(
                'raw_cost'      => $cost,
                'display_price' => $display_price,
                'formatted_price' => wc_price( $display_price ),
                'price_suffix'  => $price_suffix,
                'currency'      => get_woocommerce_currency(),
                'currency_symbol' => get_woocommerce_currency_symbol(),
            );

            return rest_ensure_response( $response_data );
        } catch ( Exception $e ) {
            return new \WP_Error(
                'booking_calculation_exception',
                $e->getMessage(),
                array( 'status' => 500 )
            );
        }
    }
}
