<?php

namespace WeDevs\DokanPro\Modules\TableRate\REST;

use WeDevs\Dokan\REST\DokanBaseVendorController;
use WeDevs\DokanPro\Modules\TableRate\Hooks;
use WP_Error;
use WP_REST_Server;
use WP_REST_Request;
use WP_REST_Response;

/**
 * Class DistanceRateController
 *
 * @package WeDevs\DokanPro\Modules\TableRate\REST
 *
 * @since 4.1.3
 */
class DistanceRateController extends DokanBaseVendorController {

	/**
	 * Route base.
	 *
	 * @var string
	 */
	protected $rest_base = 'shipping/distance-rate/rates';

	/**
	 * Register routes.
	 *
	 * @since 4.1.3
	 *
	 * @return void
	 */
	public function register_routes() {
		register_rest_route(
			$this->namespace,
			'/' . $this->rest_base . '/zone/(?P<zone_id>[\d]+)/instance/(?P<instance_id>[\d]+)',
			[
				[
					'methods'             => WP_REST_Server::READABLE,
					'callback'            => [ $this, 'get_shipping_rates' ],
					'permission_callback' => [ $this, 'check_permission' ],
					'args'                => $this->get_collection_params(),
				],
				[
					'methods'             => WP_REST_Server::EDITABLE,
					'callback'            => [ $this, 'save_shipping_rates' ],
					'permission_callback' => [ $this, 'check_permission' ],
					'args'                => $this->get_endpoint_args_for_item_schema( WP_REST_Server::EDITABLE ),
				],
				[
					'methods'             => WP_REST_Server::DELETABLE,
					'callback'            => [ $this, 'delete_shipping_rates' ],
					'permission_callback' => [ $this, 'check_permission' ],
					'args'                => $this->get_endpoint_args_for_item_schema( WP_REST_Server::DELETABLE ),
				],
				'schema' => [ $this, 'get_item_schema' ],
			]
		);
	}

	/**
	 * Prepares the item for the REST response.
	 *
	 * @since 4.1.3
	 *
	 * @param array           $item    WordPress representation of the item.
	 * @param WP_REST_Request $request Request object.
	 *
	 * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure.
	 */
	public function prepare_item_for_response( $item, $request ) {
		// Get zone ID and instance ID from the request.
		$zone_id     = $request['zone_id'] ?? 0;
		$instance_id = $request['instance_id'] ?? 0;

		$data = [
			'rate_id'        => $item['rate_id'] ?? 0,
			'zone_id'        => $zone_id,
			'instance_id'    => $instance_id,
			'vendor_id'      => $item['vendor_id'] ?? dokan_get_current_user_id(),
			'rate_condition' => $item['rate_condition'] ?? '',
			'rate_min'       => $item['rate_min'] ?? '',
			'rate_max'       => $item['rate_max'] ?? '',
			'rate_cost'      => $item['rate_cost'] ?? '',
			'rate_cost_unit' => $item['rate_cost_unit'] ?? '',
			'rate_fee'       => $item['rate_fee'] ?? '',
			'rate_break'     => $item['rate_break'] ?? 0,
			'rate_abort'     => $item['rate_abort'] ?? 0,
			'rate_order'     => $item['rate_order'] ?? 0,
		];

		/**
		 * Filter the distance rate shipping rate data.
		 *
		 * @since 4.1.3
		 *
		 * @param array           $data        The formatted shipping rate data.
		 * @param array           $item        The original item data.
		 * @param WP_REST_Request $request     Full details about the request.
		 * @param int             $zone_id     The shipping zone ID.
		 * @param int             $instance_id The shipping method instance ID.
		 */
		$data = apply_filters( 'dokan_distance_rate_prepare_shipping_rate_response', $data, $item, $request, $zone_id, $instance_id );

		return rest_ensure_response( $data );
	}

	/**
	 * Get distance rates
	 *
	 * @since 4.1.3
	 *
	 * @param WP_REST_Request $request
	 *
	 * @return WP_REST_Response|WP_Error
	 */
	public function get_shipping_rates( $request ) {
		$instance_id = $request['instance_id'] ?? 0;

		if ( ! $instance_id ) {
			return new WP_Error(
				'dokan_distance_rate_invalid_instance',
				esc_html__( 'Invalid instance ID', 'dokan' ),
				[ 'status' => 404 ]
			);
		}

		try {
			$prepared_rates = [];
			$zone_id        = $request['zone_id'] ?? 0;
			$shipping_rates = dokan_pro()->module->table_rate_shipping->get_normalized_shipping_distance_rates( $instance_id );

			foreach ( $shipping_rates as $rate ) {
				$prepared_response = $this->prepare_item_for_response( $rate, $request );
				$prepared_rates[]  = $prepared_response->get_data();
			}

			/**
			 * Filters for the collection of distance rate shipping rates.
			 *
			 * @since 4.1.3
			 *
			 * @param array           $prepared_rates The prepared shipping rates.
			 * @param array           $shipping_rates The original shipping rates.
			 * @param WP_REST_Request $request        Full details about the request.
			 * @param int             $zone_id        The shipping zone ID.
			 * @param int             $instance_id    The shipping method instance ID.
			 */
			$prepared_rates = apply_filters(
				'dokan_distance_rate_prepare_shipping_rates_collection',
				$prepared_rates,
				$shipping_rates,
				$request,
				$zone_id,
				$instance_id
			);

			return rest_ensure_response( $prepared_rates );
		} catch ( \Exception $e ) {
			return new WP_Error(
				'dokan_distance_rate_error',
				$e->getMessage(),
				[ 'status' => 404 ]
			);
		}
	}

	/**
	 * Save distance rates
	 *
	 * @since 4.1.3
	 *
	 * @param WP_REST_Request $request
	 *
	 * @return WP_REST_Response|WP_Error
	 */
	public function save_shipping_rates( $request ) {
		$instance_id = $request['instance_id'] ?? 0;
		if ( ! $instance_id ) {
			return new WP_Error(
				'dokan_distance_rate_invalid_instance',
				esc_html__( 'Invalid instance ID', 'dokan' ),
				[ 'status' => 400 ]
			);
		}

		$rate_data = $request['preparedData'] ?? [];
		if ( empty( $rate_data ) ) {
			return new WP_Error(
				'dokan_distance_rate_empty_data',
				esc_html__( 'No shipping rate data provided', 'dokan' ),
				[ 'status' => 400 ]
			);
		}

		$zone_id       = $request['zone_id'] ?? 0;
		$prepared_data = [
			'zone_id'        => $zone_id,
			'instance_id'    => $instance_id,
			'rate_ids'       => array_map( 'intval', $rate_data['rate_ids'] ?? [] ),
			'rate_condition' => array_map( 'wc_clean', $rate_data['rate_condition'] ?? [] ),
			'rate_min'       => array_map( 'wc_clean', $rate_data['rate_min'] ?? [] ),
			'rate_max'       => array_map( 'wc_clean', $rate_data['rate_max'] ?? [] ),
			'rate_cost'      => array_map( 'wc_clean', $rate_data['rate_cost'] ?? [] ),
			'rate_cost_unit' => array_map( 'wc_clean', $rate_data['rate_cost_unit'] ?? [] ),
			'rate_fee'       => array_map( 'wc_clean', $rate_data['rate_fee'] ?? [] ),
			'rate_break'     => array_map( 'wc_clean', $rate_data['rate_break'] ?? [] ),
			'rate_abort'     => array_map( 'wc_clean', $rate_data['rate_abort'] ?? [] ),
		];

		try {
			Hooks::save_distance_rate_data( $prepared_data );
			return rest_ensure_response(
				[
					'message' => esc_html__( 'Distance rates saved successfully', 'dokan' ),
					'rates'   => $this->get_shipping_rates( $request ),
				]
			);
		} catch ( \Exception $e ) {
			return new WP_Error(
				'dokan_distance_rate_save_error',
				$e->getMessage(),
				[ 'status' => 400 ]
			);
		}
	}

	/**
	 * Delete distance rates
	 *
	 * @since 4.1.3
	 *
	 * @param WP_REST_Request $request
	 *
	 * @return WP_REST_Response|WP_Error
	 */
	public function delete_shipping_rates( $request ) {
		$instance_id = $request['instance_id'] ?? 0;
		if ( ! $instance_id ) {
			return new WP_Error(
				'dokan_distance_rate_invalid_instance',
				esc_html__( 'Invalid instance ID', 'dokan' ),
				[ 'status' => 400 ]
			);
		}

		$zone_id  = $request['zone_id'] ?? 0;
		$rate_ids = $request['rate_ids'] ?? [];
		if ( empty( $rate_ids ) ) {
			return new WP_Error(
				'dokan_distance_rate_empty_rates',
				esc_html__( 'No rate IDs provided for deletion', 'dokan' ),
				[ 'status' => 400 ]
			);
		}

		try {
			$delete_rates = dokan_pro()->module->table_rate_shipping->delete_distance_rates( $rate_ids, $zone_id, $instance_id );
			if ( ! $delete_rates ) {
				throw new \Exception( esc_html__( 'Failed to delete distance rates', 'dokan' ) );
			}
		} catch ( \Exception $e ) {
			return new WP_Error(
				'dokan_distance_rate_delete_error',
				$e->getMessage(),
				[ 'status' => 400 ]
			);
		}

		return rest_ensure_response( $delete_rates );
	}

	/**
	 * Check permission
	 *
	 * @since 4.1.3
	 *
	 * @return bool
	 */
	public function check_permission(): bool {
		return current_user_can( 'dokan_view_store_shipping_menu' );
	}

	/**
	 * Get collection params
	 *
	 * @since 4.1.3
	 *
	 * @return array
	 */
	public function get_collection_params(): array {
		return [
			'zone_id'     => [
				'description'       => esc_html__( 'Shipping Zone ID.', 'dokan' ),
				'type'              => 'integer',
				'required'          => true,
				'validate_callback' => 'rest_validate_request_arg',
			],
			'instance_id' => [
				'description'       => esc_html__( 'Shipping Method Instance ID.', 'dokan' ),
				'type'              => 'integer',
				'required'          => true,
				'validate_callback' => 'rest_validate_request_arg',
			],
		];
	}

	/**
	 * Get item schema
	 *
	 * @since 4.1.3
	 *
	 * @return array
	 */
	public function get_item_schema(): array {
		return [
			'$schema'    => 'http://json-schema.org/draft-04/schema#',
			'title'      => 'distance_rate_shipping',
			'type'       => 'object',
			'properties' => [
				'rate_condition' => [
					'description' => esc_html__( 'Rate condition', 'dokan' ),
					'type'        => 'string',
					'enum'        => [ 'distance', 'time', 'weight', 'total', 'quantity' ],
					'context'     => [ 'view', 'edit' ],
				],
				'rate_min'       => [
					'description' => esc_html__( 'Minimum rate', 'dokan' ),
					'type'        => 'number',
					'context'     => [ 'view', 'edit' ],
				],
				'rate_max'       => [
					'description' => esc_html__( 'Maximum rate', 'dokan' ),
					'type'        => 'number',
					'context'     => [ 'view', 'edit' ],
				],
				'rate_cost'      => [
					'description' => esc_html__( 'Rate cost', 'dokan' ),
					'type'        => 'number',
					'context'     => [ 'view', 'edit' ],
				],
				'rate_cost_unit' => [
					'description' => esc_html__( 'Rate cost per unit', 'dokan' ),
					'type'        => 'number',
					'context'     => [ 'view', 'edit' ],
				],
				'rate_fee'       => [
					'description' => esc_html__( 'Rate fee', 'dokan' ),
					'type'        => 'number',
					'context'     => [ 'view', 'edit' ],
				],
				'rate_break'     => [
					'description' => esc_html__( 'Rate break', 'dokan' ),
					'type'        => 'boolean',
					'context'     => [ 'view', 'edit' ],
				],
				'rate_abort'     => [
					'description' => esc_html__( 'Rate abort', 'dokan' ),
					'type'        => 'boolean',
					'context'     => [ 'view', 'edit' ],
				],
				'rate_order'     => [
					'description' => esc_html__( 'Rate order', 'dokan' ),
					'type'        => 'integer',
					'context'     => [ 'view', 'edit' ],
				],
			],
		];
	}
}
