<?php

namespace Simplyin\Simplyin_W_Plugin\Shipping_Mapping;

use Simplyin\Simplyin_W_Plugin\Dto\Order\Order_DTO_Factory;
use Simplyin\Simplyin_W_Plugin\Shipping_Mapping\Checkout\Cart_Delivery;
use Simplyin\Simplyin_W_Plugin\Shipping_Mapping\Checkout\Cart_Delivery_Item;
use WC_Shipping_Method;
use WC_Shipping_Rate;
use WC_Shipping_Zones;
use WC_Tax;

class Checkout {

	private array $shipping_rates_cache = [];
	private array $cart_items_cache = [];
	private array $shipping_packages_cache = [];

	/**
	 * @var WC_Shipping_Method[]
	 */
	private array $shipping_methods_cache = [];


	public function get_available_delivery(): Cart_Delivery {
		$this->shipping_packages_cache = $this->find_shipping_packages();
		$this->shipping_rates_cache    = $this->get_shipping_rates();
		$this->cart_items_cache        = $this->get_cart_items();

		return $this->get_available_cart_delivery_items();
	}

	private function get_cart_items(): array {
		if ( isset( \WC()->cart ) && \WC()->cart && ! \WC()->cart->is_empty() ) {
			return \WC()->cart->get_cart();
		}

		return [];
	}

	private function get_shipping_rates(): array {
		$result = [
			'rates'                => [],
			'shipping_package_key' => '',
		];

		$shipping_packages = $this->shipping_packages_cache;

		foreach ( array_keys( $shipping_packages ) as $key ) {
			if ( $shipping_for_package = \WC()->session->get( 'shipping_for_package_' . $key ) ) {
				if ( isset( $shipping_for_package['rates'] ) ) {
					return [
						'rates'                => $shipping_for_package['rates'],
						'shipping_package_key' => $key,
					];
				}
			}
		}

		// Session doesn't have pre-calculated rates (common on block checkout Store API requests).
		// Force-calculate so we get real rates rather than returning empty.
		if ( ! empty( $shipping_packages ) && \WC()->shipping() ) {
			\WC()->shipping()->calculate_shipping( array_values( $shipping_packages ) );

			foreach ( array_keys( $shipping_packages ) as $key ) {
				if ( $shipping_for_package = \WC()->session->get( 'shipping_for_package_' . $key ) ) {
					if ( isset( $shipping_for_package['rates'] ) ) {
						return [
							'rates'                => $shipping_for_package['rates'],
							'shipping_package_key' => $key,
						];
					}
				}
			}
		}

		return $result;
	}

	private function find_shipping_packages(): array {
		if ( isset( \WC()->cart ) && \WC()->cart && ! \WC()->cart->is_empty() ) {
			return \WC()->cart->get_shipping_packages();
		}

		return [];
	}

	/**
	 * @return Cart_Delivery_Item[]
	 */
	public function get_available_cart_delivery_items(): Cart_Delivery {
		$cart_delivery = new Cart_Delivery();

		$only_virtual_in_cart = false;
		foreach ( $this->cart_items_cache as $cart_item ) {
			if ( $this->is_cart_product_virtual( $cart_item['data']->get_id() ) ) {
				$only_virtual_in_cart = true;
			} else {
				$only_virtual_in_cart = false;
				break;
			}
		}

		if ( $only_virtual_in_cart ) {
			simplyin()->get_simplyin_logger()->log_if_wpdebug_on(
				'[Checkout] [get_available_delivery_parameters] virtual-only cart',
				'shipping_mapping'
			);

			return $cart_delivery;
		}

		if ( empty( $this->shipping_packages_cache ) ) {
			simplyin()->get_simplyin_logger()->log_if_wpdebug_on(
				'[Checkout] [get_available_delivery_parameters] no shippable packages (empty cart)',
				'shipping_mapping'
			);

			return $cart_delivery;
		}

		$shipping_packages    = $this->shipping_packages_cache;
		$shipping_package_key = $this->shipping_rates_cache['shipping_package_key'];


		/**
		 * @var WC_Shipping_Rate $rate
		 */
		foreach ( $this->shipping_rates_cache['rates'] as $rate ) {
			$shipping_method  = WC_Shipping_Zones::get_shipping_method( $rate->get_instance_id() );
			$rate_method      = $rate->get_method_id();
			$rate_instance_id = $rate->get_instance_id();
			$rate_method_id   = $rate_method . ':' . $rate_instance_id;

			if ( $shipping_method instanceof WC_Shipping_Method && $shipping_method->id === $rate_method ) {
				$shipping_method->calculate_shipping( $shipping_packages[ $shipping_package_key ] );

				if ( isset( $shipping_method->rates[ $rate_method_id ] ) ) {

					$cart_delivery_item = new Cart_Delivery_Item();
					$cart_delivery_item->set_rate_method_id( $rate_method . '_' . $rate_instance_id );

					/**
					 * @var WC_Shipping_Rate $found_rate
					 */
					$found_rate = $shipping_method->rates[ $rate_method_id ];
					$add_vat    = $shipping_method->is_taxable();
					$rate_cost  = $found_rate->get_cost();

					$tax_display = get_option( 'woocommerce_tax_display_cart' );
					if ( 'excl' === $tax_display ) {
						$add_vat = false;
					}

					if ( $add_vat ) {
						$taxes = $found_rate->get_taxes();
					}

					$rate_cost_normalized = Order_DTO_Factory::normalize_price( $rate_cost );

					if ( $add_vat ) {
						$tax         = Order_DTO_Factory::normalize_price( array_sum( $taxes ) );
						$found_price = $rate_cost_normalized + $tax;
					} else {
						$found_price = $rate_cost_normalized;
					}

					$cart_delivery_item->set_cost( wc_price( $found_price,
						[ 'in_span' => false ] ) );

					$cart_delivery->add( $cart_delivery_item );

				}
			}


		}

		return $cart_delivery;
	}


	public function is_cart_product_virtual( $productId ): bool {
		$product = wc_get_product( $productId );
		if ( $product instanceof \WC_Product ) {
			if ( $product->is_virtual() ) {
				return true;
			}
		}

		return false;
	}
}
