<?php

namespace Prodigy\Includes\Frontend\Pages;

use Prodigy\Includes\Content\Prodigy_Order_Parser;
use Prodigy\Includes\Content\Prodigy_Request_Maker;
use Prodigy\Includes\Frontend\Cart_Error_Handler;
use Prodigy\Includes\Frontend\Traits\Prodigy_Mlc_Charge_Trait;
use Prodigy\Includes\Helpers\Prodigy_Cookies;
use Prodigy\Includes\Helpers\Prodigy_Template;
use Prodigy\Includes\Helpers\Prodigy_Widget_Options;
use Prodigy\includes\models\Prodigy_Order;
use Prodigy\Includes\Models\Prodigy_Products;
use Prodigy\Includes\Prodigy;
use Prodigy\Includes\Prodigy_Callback_Api_Listener;
use Prodigy\Includes\Prodigy_Cart;
use Prodigy\Includes\Prodigy_User;

if ( ! defined( 'ABSPATH' ) ) {
	exit;
}

/**
 * Class Prodigy_Cart_Page
 */
class Prodigy_Cart_Page extends Prodigy_Page {

	use Prodigy_Mlc_Charge_Trait;

	public const PAGE_NAME = 'Cart';

	public const FLATSOME_CART_URL = 'shopping-cart';

	public const DEFAULT_CART_URL = 'cart';

	/** @var Prodigy_Cart $cart */
	protected Prodigy_Cart $cart;

	/** @var Cart_Error_Handler */
	private Cart_Error_Handler $cart_error_handler;

	/** @var Prodigy_Order_Parser */
	private Prodigy_Order_Parser $order;

	/**
	 * @param   Prodigy_Order                 $order_model
	 * @param   Prodigy_Request_Maker         $request_maker
	 * @param   Prodigy_Cart                  $cart
	 * @param   Cart_Error_Handler            $cart_error_handler
	 * @param   Prodigy_Callback_Api_Listener $callback_api_listener
	 *
	 * @throws \Exception
	 */
	public function __construct(
		Prodigy_Order $order_model,
		Prodigy_Request_Maker $request_maker,
		Prodigy_Cart $cart,
		Cart_Error_Handler $cart_error_handler,
		Prodigy_Callback_Api_Listener $callback_api_listener
	) {
		parent::__construct( $order_model, $request_maker, $cart, $callback_api_listener );

		$this->cart               = $cart;
		$this->cart_error_handler = $cart_error_handler;

		if ( isset( $this->order_token ) && is_front_page() ) {
			$this->order = new Prodigy_Order_Parser( $this->request_maker->do_order_request( $this->order_token ) );
		}

		add_action( 'wp_ajax_prodigy-remote-get-template-cart', array( $this, 'prodigy_remote_get_template_cart' ) );
		add_action(
			'wp_ajax_nopriv_prodigy-remote-get-template-cart',
			array(
				$this,
				'prodigy_remote_get_template_cart',
			)
		);

		add_action( 'wp_head', array( $this, 'myplugin_ajaxurl' ) );
		add_action( 'wp_ajax_prodigy-add-product-to-cart', array( $this, 'prodigy_add_product_to_cart' ) );
		add_action( 'wp_ajax_nopriv_prodigy-add-product-to-cart', array( $this, 'prodigy_add_product_to_cart' ) );
		add_action( 'wp_ajax_prodigy-load-cart-data', array( $this, 'prodigy_get_cart_data_ajax' ) );
		add_action( 'wp_ajax_nopriv_prodigy-load-cart-data', array( $this, 'prodigy_get_cart_data_ajax' ) );
		add_action( 'wp_ajax_prodigy-remove-item-cart', array( $this, 'prodigy_ajax_remove_item_from_cart' ) );
		add_action( 'wp_ajax_nopriv_prodigy-remove-item-cart', array( $this, 'prodigy_ajax_remove_item_from_cart' ) );
		add_action( 'wp_ajax_prodigy-update-item-cart', array( $this, 'prodigy_update_cart' ) );
		add_action( 'wp_ajax_nopriv_prodigy-update-item-cart', array( $this, 'prodigy_update_cart' ) );
		add_action(
			'wp_ajax_prodigy-is-replace-subscription-item',
			array(
				$this,
				'is_need_replace_subscription_item',
			)
		);
		add_action(
			'wp_ajax_nopriv_prodigy-is-replace-subscription-item',
			array(
				$this,
				'is_need_replace_subscription_item',
			)
		);
	}

	/**
	 * Check if the cart is empty.
	 */
	private function is_cart_empty(): bool {
		return empty( $this->is_line_items() );
	}

	/**
	 * check subscription popup
	 */
	public function is_need_replace_subscription_item(): void {
		$result['show_subscription_popup'] = false;
		$remote_product_id                 = $this->get_sanitized_post_value( 'remote_product_id', FILTER_VALIDATE_INT );
		$subscription_id                   = $this->get_sanitized_post_value( 'subscription_id', FILTER_VALIDATE_INT );
		$one_time_order                    = $this->get_sanitized_post_value( 'one_time_order' );

		if ( isset( $this->order_token ) ) {
			$exist_items = $this->order->get_line_items();

			foreach ( $exist_items as $item ) {
				if ( $remote_product_id && (int) $remote_product_id === (int) $item['attributes']['variant-id'] ) {
					$result['show_subscription_popup'] = $this->should_show_subscription_popup( $item, $subscription_id, $one_time_order );
					echo wp_json_encode( $result );
					wp_die();
				}
			}
		}

		echo wp_json_encode( $result );
		wp_die();
	}

	/**
	 * @param   string $key
	 * @param   int    $filter
	 *
	 * @return mixed|null
	 */
	private function get_sanitized_post_value( string $key, int $filter = FILTER_DEFAULT ) {
		if ( isset( $_POST[ $key ] ) ) {
			return filter_var( sanitize_text_field( wp_unslash( $_POST[ $key ] ) ), $filter );
		}

		return null;
	}

	/**
	 * @param   array  $item
	 * @param   int    $subscription_id
	 * @param   string $one_time_order
	 *
	 * @return bool
	 */
	private function should_show_subscription_popup( array $item, int $subscription_id, string $one_time_order ): bool {
		if ( isset( $item['subscriptions']['id'] ) ) {
			if ( $subscription_id !== $item['subscriptions']['id'] && $one_time_order !== 'true' ) {
				return true;
			}
			if ( (int) $subscription_id === (int) $item['subscriptions']['id'] ) {
				return false;
			}
		} elseif ( ! empty( $subscription_id ) && Prodigy_Widget_Options::$bool_mapper[ $one_time_order ] ) {
			return true;
		}

		return Prodigy_Widget_Options::$bool_mapper[ $one_time_order ];
	}

	/**
	 * Update cart
	 */
	public function prodigy_update_cart(): void {
		if (
			isset( $_POST['_wpnonce'] ) &&
			! wp_verify_nonce( sanitize_key( wp_unslash( $_POST['_wpnonce'] ) ), 'store-nonce' )
		) {
			return;
		}
		$line_item_id = isset( $_POST['line_item_id'] ) ? sanitize_key( wp_unslash( $_POST['line_item_id'] ) ) : '';
		$remote_id    = isset( $_POST['remote_id'] ) ? sanitize_key( wp_unslash( $_POST['remote_id'] ) ) : '';
		$count        = isset( $_POST['count'] ) ? sanitize_key( wp_unslash( $_POST['count'] ) ) : '';

		$result                                   = null;
		$remote_product_data['remote_product_id'] = $remote_id;
		$remote_product_data['token']             = $this->order_token;
		$remote_product_data['count']             = $count;

		update_option( 'current_order', $this->order_token );

		$line_item_request  = $this->cart->prepare_line_item_request( $remote_product_data, $count );
		$line_item_response = $this->request_maker->do_update_line_items_request( $line_item_id, $line_item_request );

		if ( $line_item_response['code'] === \WP_Http::NO_CONTENT ) {
			$update_order = $this->cart->refresh_order_data( $this->order_token, $line_item_response );
			if ( ! $update_order ) {
				/* translators: %s: product remote ID */
				$this->cart_error_handler->log_error( sprintf( __( 'Order is not updated for product %s', 'prodigy-commerce' ), $remote_id ) );
				$result['error'] = $this->cart_error_handler->get_error_message_for_response( Cart_Error_Handler::ERROR_ORDER_NOT_UPDATED );
			}
			wp_send_json_success();
		} elseif ( $line_item_response['code'] === \WP_Http::UNPROCESSABLE_ENTITY ) {
			$result['error']   = \WP_Http::UNPROCESSABLE_ENTITY;
			$result['message'] = $line_item_response['errors'][0]['detail'] ?? $line_item_response['error'];
			wp_send_json_error( $result );
		} else {
			$this->cart_error_handler->log_error( $line_item_response['error'] . __( 'Line item:', 'prodigy-commerce' ) . $line_item_id );
			$result['error'] = $this->cart_error_handler->get_error_message_for_response( Cart_Error_Handler::ERROR_SEND_PRODUCT_TO_API );
			wp_send_json_error( $result, \WP_Http::INTERNAL_SERVER_ERROR );
		}

		wp_die();
	}

	/**
	 * Ajax Remove item from cart
	 */
	public function prodigy_ajax_remove_item_from_cart(): ?bool {
		if ( ! isset( $_POST['nonce'] ) || ! wp_verify_nonce( sanitize_key( wp_unslash( $_POST['nonce'] ) ), 'store-nonce' ) ) {
			return false;
		}

		$line_item_id = filter_var( wp_unslash( $_POST['line_item_id'] ), FILTER_VALIDATE_INT );
		$this->remove_line_item_from_cart( $line_item_id );
	}

	/**
	 * @param   int $line_item_id
	 */
	private function remove_line_item_from_cart( int $line_item_id ): void {
		if ( ! isset( $this->order_token ) ) {
			wp_send_json_error( 'No order token provided.', \WP_Http::NOT_FOUND );
		}

		if ( isset( $this->order_token, $line_item_id ) ) {
			$delete_remote_product = $this->request_maker->do_delete_line_item_request( $line_item_id, $this->order_token );
			if ( isset( $delete_remote_product['errors'] ) ) {
				wp_send_json_error( $delete_remote_product['errors'], $delete_remote_product['code'] );
			}

			$is_empty_cart = $this->is_line_items();
			if ( empty( $is_empty_cart ) ) {
				$this->cart->clear_order( $this->order_token );
				wp_send_json_success();
			}
			wp_send_json_success();
		}
	}

	/**
	 * check empty cart
	 *
	 * @return array
	 * @version 2.0.0
	 */
	public function is_line_items(): array {
		$items = array();
		if ( $this->order_token ) {
			$order_data = $this->request_maker->do_order_request( $this->order_token );
			$order      = new Prodigy_Order_Parser( $order_data );
			$items      = $order->get_line_items();
		}

		return $items;
	}

	/**
	 * @return void
	 */
	public function prodigy_get_cart_data_ajax(): void {
		$order_token = $this->order_token;
		if ( ! $order_token && Prodigy_Cookies::get_user_cart_cookie() ) {
			$order_token = $this->order_model->get_order_token( Prodigy_Cookies::get_user_cart_cookie() );
		}

		if ( $order_token ) {
			$order_data        = Prodigy_Request_Maker::get_instance()->do_order_request( $order_token );
			$remote_order_info = new Prodigy_Order_Parser( $order_data );
			$cart_items        = $remote_order_info->get_line_items();
			$order_attributes  = $remote_order_info->get_attributes();
		}

		$cart_products = array();
		if ( ! empty( $cart_items ) ) {
			$cart_products = $this->prepare_cart_data_for_frontend( $cart_items );
		}
		$cart_total = $this->resolve_cart_total_amount( $order_attributes ?? array(), $cart_items ?? array() );

		$items_count = $cart_products['count_items'] ?? 0;
		unset( $cart_products['count_items'] );

		$cart_content = Prodigy_Template::prodigy_get_template_html(
			'cart-items.php',
			array(
				'cart_products' => $cart_products,
				'is_dropdown'   => true,
				'total_price'   => $cart_total,
			)
		);
		$result       = array(
			'cart_items'       => $cart_content,
			'cart_items_count' => $items_count,
			'total_price'      => $cart_total,
			'status'           => 'success',
		);

		echo wp_json_encode( $result );
		wp_die();
	}

	/**
	 * @param   array $cart_items
	 *
	 * @return array
	 */
	private function prepare_cart_data_for_frontend( array $cart_items ): array {
		$cart_products     = array();
		$total_count_items = 0;

		$remote_product_ids = array_column(
			array_column( $cart_items, 'attributes' ),
			'product-id'
		);
		$local_meta_map = Prodigy_Products::get_products_meta_by_remote_ids(
			Prodigy::PRODIGY_REMOTE_PRODUCT_ID,
			$remote_product_ids
		);

		foreach ( $cart_items as $key => $item ) {
			$remote_product_id = $item['attributes']['variant-id'];
			$quantity          = $item['attributes']['quantity'];
			$actual_price      = $item['attributes']['price'];
			$image_url         = $item['attributes']['image-url'];
			$name              = $item['attributes']['name'];

			$local_parent_product_info = $local_meta_map[ (int) $item['attributes']['product-id'] ] ?? null;
			$local_parent_product_id   = $local_parent_product_info->post_id ?? 0;
			$option_variants           = $item['attributes']['options'];

			$cart_products[ $key ]                            = $item;
			$cart_products[ $key ]['remote_product_id']       = $remote_product_id;
			$cart_products[ $key ]['count_items']             = $quantity;
			$cart_products[ $key ]['actual_price']            = $actual_price;
			$cart_products[ $key ]['image_url']               = $image_url;
			$cart_products[ $key ]['name']                    = $name;
			$cart_products[ $key ]['local_parent_product_id'] = $local_parent_product_id;
			$cart_products[ $key ]['option_variants']         = $option_variants;
			$cart_products[ $key ]['logo_options']            = $this->apply_mlc_extra_charges_to_logos(
				$item['attributes']['logos'] ?? array(),
				(int) ( $item['attributes']['product-id'] ?? 0 )
			);

			$total_count_items += $quantity;
		}

		$cart_products['count_items'] = $total_count_items;

		return $cart_products;
	}

	/**
	 * Resolve cart total for widget response.
	 * Falls back to line item totals when order attributes do not include total.
	 *
	 * @param array $order_attributes
	 * @param array $cart_items
	 *
	 * @return float
	 */
	private function resolve_cart_total_amount( array $order_attributes, array $cart_items ): float {
		$order_total = $this->get_amount_from_candidates(
			$order_attributes,
			array( 'total', 'total-price', 'subtotal', 'sub-total' )
		);
		if ( $order_total > 0 ) {
			return $order_total;
		}

		$items_total = 0.0;
		foreach ( $cart_items as $item ) {
			$item_attributes = $item['attributes'] ?? array();
			$line_total      = $this->get_amount_from_candidates(
				$item_attributes,
				array( 'total', 'total-price', 'subtotal', 'sub-total', 'amount' )
			);
			if ( $line_total <= 0 ) {
				$line_price = $this->get_amount_from_candidates(
					$item_attributes,
					array( 'price', 'unit-price', 'item-price' )
				);
				$quantity   = isset( $item_attributes['quantity'] ) && is_numeric( $item_attributes['quantity'] )
					? (float) $item_attributes['quantity']
					: 0.0;
				$line_total = $line_price * $quantity;
			}

			$items_total += $line_total;
		}

		return $items_total;
	}

	/**
	 * Return first positive amount from candidate keys.
	 *
	 * @param array $source
	 * @param array $keys
	 *
	 * @return float
	 */
	private function get_amount_from_candidates( array $source, array $keys ): float {
		foreach ( $keys as $key ) {
			if ( ! array_key_exists( $key, $source ) ) {
				continue;
			}

			$amount = $this->to_float_amount( $source[ $key ] );
			if ( $amount > 0 ) {
				return $amount;
			}
		}

		return 0.0;
	}

	/**
	 * Normalize numeric amount values from API payloads.
	 *
	 * @param mixed $value
	 *
	 * @return float
	 */
	private function to_float_amount( $value ): float {
		if ( is_numeric( $value ) ) {
			return (float) $value;
		}

		if ( ! is_string( $value ) ) {
			return 0.0;
		}

		$normalized = preg_replace( '/[^0-9.\-]/', '', str_replace( ',', '.', $value ) );

		return is_numeric( $normalized ) ? (float) $normalized : 0.0;
	}

	/**
	 * Send query to hosted system.
	 */
	public function prodigy_add_product_to_cart(): ?bool {
		if ( ! isset( $_POST['nonce'] ) || ! wp_verify_nonce( sanitize_key( wp_unslash( $_POST['nonce'] ) ), 'store-nonce' ) ) {
			return false;
		}

		// For Guest without cookie: generate session so order is saved with it and cookie can be set.
		if ( ! Prodigy_User::is_logged_in() && empty( $this->user_session ) ) {
			$this->user_session = $this->cart->generate_uuid();
		}

		$is_bulk                  = $this->get_boolean_from_post( 'is_bulk' );
		$is_subscription_replaced = $this->get_boolean_from_post( 'is_subscription_replaced' );

		$variants = $_POST['variants'] ?? array();

		if ( $is_subscription_replaced && isset( $this->order_token ) ) {
			$this->process_subscription_replacement( $variants );
		}

		$is_single_variant = ! empty( $_POST['variants']['remote_variant_id'] );

		if ( isset( $this->user_session ) && $is_single_variant ) {
			$request = $this->prepare_cart_request( $_POST, $this->order_token );
			$this->log_action( 'cart_request', $request );

			if ( ! empty( $this->order_token ) && $this->is_cart_empty() ) {
				unset( $request['order_token'] );
				$this->order_model->delete_local_order( $this->order_token );
			}

			$cart_response = Prodigy_Request_Maker::get_instance()->do_init_order_request( $request );
			$this->handle_cart_response( $cart_response, $request );
		} elseif ( $is_bulk ) {
			$request       = $this->prepare_cart_request( $_POST, $this->order_token );
			$cart_response = Prodigy_Request_Maker::get_instance()->do_init_order_request( $request );
			$this->handle_cart_response( $cart_response, $request );
		} else {
			$this->cart_error_handler->log_error(
				/* translators: %1$s: user session identifier */
				sprintf( __( 'Do not set item in user_session %1$s', 'prodigy-commerce' ), $this->user_session )
			);
			$result['error'] = $this->cart_error_handler->get_error_message_for_response( Cart_Error_Handler::ERROR_ADD_ITEM_TO_ORDER );
		}

		if ( ! isset( $result['error'] ) ) {
			$result['status'] = 'success';
			// Create/update cart cookie for Guest when product is added to cart.
			if ( ! Prodigy_User::is_logged_in() && ! empty( $this->user_session ) ) {
				$this->cart->set_cart_user_session( $this->user_session );
			}
		}

		echo wp_json_encode( $result );
		wp_die();
	}

	/**
	 * @param   array $cart_response
	 * @param   array $request
	 *
	 * @return void
	 */
	public function handle_cart_response( array $cart_response, array $request ): void {
		if ( isset( $cart_response['error'] ) ) {
			$message = $cart_response['errors'][0]['detail'] ?? $cart_response['error'];
			if ( ! empty( $message ) ) {
				wp_send_json_error( $message, $cart_response['code'] );
				$this->cart_error_handler->log_error(
					$message . ' ' . __( 'Token:', 'prodigy-commerce' ) . $this->order_token
				);
			}
		} elseif ( empty( $cart_response ) ) {
			$this->cart_error_handler->log_error( __( 'Init order error for token:', 'prodigy-commerce' ) . $this->order_token );
			wp_send_json_error( $cart_response['error'] ?? '', $cart_response['code'] ?? '' );
		} else {
			$this->update_order( $cart_response, $request );
		}
	}
	/**
	 * @param   string $key
	 *
	 * @return false|mixed
	 */
	private function get_boolean_from_post( string $key ) {
		if ( isset( $_POST[ $key ] ) ) {
			return filter_var( sanitize_key( wp_unslash( $_POST[ $key ] ) ), FILTER_VALIDATE_BOOLEAN );
		}

		return false;
	}

	/**
	 * @param   array $variants
	 *
	 * @return void
	 */
	private function process_subscription_replacement( array $variants ): void {
		$cart_items = $this->order->get_line_items();

		foreach ( $variants as $variant ) {
			foreach ( $cart_items as $line_item ) {
				if ( (int) $line_item['attributes']['variant-id'] === (int) $variant['remote_variant_id'] ) {
					$this->remove_line_item_from_cart( $line_item['id'] );
				}
			}
		}
	}

	/**
	 * @param   array       $post_data
	 * @param   string|null $order_token
	 *
	 * @return array
	 */
	private function prepare_cart_request( array $post_data, ?string $order_token = null ): array {
		if ( isset( $order_token ) ) {
			return $this->cart->set_cart_prepare_request( $post_data, $order_token );
		}

		return $this->cart->set_cart_prepare_request( $post_data );
	}

	/**
	 * Log an informational action.
	 */
	private function log_action( $key, $data ): void {
		do_action(
			'logger',
			array(
				'path' => __LINE__ . __METHOD__ . __CLASS__,
				$key   => $data,
			),
			'info'
		);
	}


	/**
	 * @param   array $cart_response
	 *
	 * @return void
	 */
	public function update_order( array $cart_response, array $request ): void {
		if ( isset( $this->order_token ) ) {
			$is_order_deleted = $this->order_model->is_deleted_order( $this->order_token );
			if ( $is_order_deleted ) {
				$save_order = $this->order_model->create_order( $cart_response, $this->user_session );
				if ( ! $save_order ) {
					$error = $this->cart_error_handler->get_error_message_for_response( Cart_Error_Handler::ERROR_SET_ORDER );
					/* translators: %s: error message */
					$this->cart_error_handler->log_error( sprintf( __( 'Do not add product to the cart, empty user session %s', 'prodigy-commerce' ), $error ) . $this->cart->order_data_table );
				}
			}
		}

		if ( ! isset( $this->order_token ) && ! empty( $cart_response ) ) {
			$token = $this->order_model->create_order( $cart_response, $this->user_session );
			if ( empty( $token ) ) {
				$error = $this->cart_error_handler->get_error_message_for_response( Cart_Error_Handler::ERROR_SET_ORDER );
				/* translators: %s: error message */
				$this->cart_error_handler->log_error( sprintf( __( 'Do not add product to the cart, empty user session %s', 'prodigy-commerce' ), $error ) . $this->cart->order_data_table );
			} else {
				$this->order_token = $token;
			}
		}

		if ( isset( $this->order_token ) ) {
			$this->cart->refresh_order_data( $this->order_token, $cart_response );
		}
	}

	/**
	 *  Set ajaxurl path
	 */
	public function myplugin_ajaxurl() {
		echo '<script type="text/javascript">
           var ajaxurl = "' . esc_url( admin_url( 'admin-ajax.php' ) ) . '";
         </script>';
	}

	/**
	 * Cart page generate html
	 *
	 * @version 2.0.0
	 */
	public function prodigy_remote_get_template_cart(): void {
		$cart_cookie = Prodigy_Cookies::get_user_cart_cookie();
		$order_token = $this->order_model->get_order_token( $cart_cookie );

		if ( $order_token ) {
			$order_data          = $this->request_maker->do_order_request( $order_token );
			$remote_order_info   = new Prodigy_Order_Parser( $order_data );
			$rr                  = $remote_order_info->get_line_items();
			$up_sell_product_ids = $remote_order_info->get_cross_sell_products();
			$up_sell_product_ids = get_format_related_products( $up_sell_product_ids );
		}
		/**
		 * empty cart
		 */
		if ( ! isset( $rr ) ) {
			wp_send_json_error();
		}

		$params['display']  = 'slider';
		$params['products'] = $up_sell_product_ids ?? '';

		/**
		 * get template for ajax render container cart
		 */
		$result = array(
			'cart'                   => Prodigy_Template::prodigy_get_template_html( 'shortcode/pages/cart/item.php', array( $params ) ),
			'cross_products'         => Prodigy_Template::prodigy_get_template_html( 'shortcode/related-slider-products.php', $params ),
			'is_show_cross_products' => (bool) $up_sell_product_ids ?? '',
		);

		wp_send_json_success( $result );
	}
}
