<?php

namespace PostenBringCheckout\admin\bring\shipping;
use PostenBringCheckout\admin\bring\CheckoutApi;
use PostenBringCheckout\admin\WeightUtils;
use PostenBringCheckout\checkout\integrations\dintero\DinteroIntegration;
use WC_Coupon;
use WC_Shipping_Method;
use WC_Tax;

defined( 'ABSPATH' ) || exit;

class PostenBringCheckoutShippingOption extends WC_Shipping_Method {
	public $supports = array();

	public function __construct($instance_id = 0) {
		parent::__construct($instance_id);

		$this->id                 = 'posten-bring-checkout';
		$this->title              = 'Posten/Bring';
		$this->method_title       = 'Posten/Bring';
		$this->method_description = 'Posten/Bring';
		$this->enabled            = 'yes';

		$this->init_form_fields();
		$this->init_settings();

		DinteroIntegration::add_shipping_rate_settings($this->id, $this->instance_id);
	}

	/**
	 * Is shipping option available
	 *
	 * This function will call Bring APIs to check eligibility of this shipping option for the provided route
	 *
	 * @param array $package Package.
	 * @since 0.0.1
	 */
	public function is_available($package): bool {
		if (get_class($this) === "PostenBringCheckoutShippingOption") {
			return false;
		}

		$exclude_mailbox = false;
		$exclude_lockers = false;

		foreach ( WC()->cart->get_cart() as $cart_item ) {
			$product = wc_get_product( $cart_item[ 'product_id'] );

			$is_disabled_for_product = $product->get_meta( '_posten_bring_checkout_disable_all' );
			$too_large_for_mailbox = $product->get_meta( '_posten_bring_checkout_too_large_for_mailbox' );
			$too_large_for_parcel_locker = $product->get_meta( '_posten_bring_checkout_too_large_for_parcel_locker' );

			if ( !$exclude_mailbox ) {
				$exclude_mailbox = $too_large_for_mailbox === 'yes';
			}

			if ( !$exclude_lockers ) {
				$exclude_lockers = $too_large_for_parcel_locker === 'yes';
			}

			if ( $is_disabled_for_product === 'yes' ) {
				return false;
			}
		}

		$from_country     = get_option( 'woocommerce_default_country' );
		$from_country     = explode( ':', $from_country )[0];
		$from_postal_code = get_option( 'woocommerce_store_postcode' );
		$to_country       = $package['destination']['country'];
		$to_postal_code   = $package['destination']['postcode'];

		if ( empty( $to_postal_code ) ) {
			return false;
		}

		$total_weight     = WeightUtils::getWeightInGrams(WC()->cart->get_cart_contents_weight() ?? 0);

		$checkoutApi = CheckoutApi::get_instance();

		try {
			return $checkoutApi->checkServiceAvailability(
				$from_country,
				$from_postal_code,
				$to_country,
				$to_postal_code,
				$total_weight,
				$exclude_mailbox,
				$exclude_lockers);
		} catch (\Exception $e) {
			wc_get_logger()->warning("Failed to check service availability: " . esc_html($e->getMessage()), array ( 'source' => 'posten-bring-checkout' ) );
			return false;
		}
	}

	/**
	 * Fetch rates and texts
	 *
	 * This function will call Bring APIs to get texts and rates applying to this shipping option for the provided route
	 *
	 * @param array $package Package.
	 * @since 0.0.1
	 */
	public function calculate_shipping( $package = array() ): void {
		$from_country      = get_option( 'woocommerce_default_country' );
		$from_country      = explode( ':', $from_country )[0];
		$from_postal_code  = get_option( 'woocommerce_store_postcode' );
		$to_country        = $package['destination']['country'];
		$to_postal_code    = $package['destination']['postcode'];
		$address           = $package['destination']['address'];
		$cart_total_amount = $package['cart_subtotal'];
		$cart_total_with_discounts = $cart_total_amount - WC()->cart->get_discount_total();
		$current_locale    = get_locale(); // Default to WP locale.
		$currency          = get_woocommerce_currency();
		$items = [];
		$exclude_lockers = false;
		$exclude_mailbox = false;
		$include_groupage_pallet = false;

		foreach ($package['contents'] as $values) {
			$product = $values['data'];

			if ( !$exclude_lockers ) {
				$too_large_for_parcel_locker = $product->get_meta( '_posten_bring_checkout_too_large_for_parcel_locker' );
				$exclude_lockers = $too_large_for_parcel_locker === 'yes';
			}

			if ( !$exclude_mailbox ) {
				$too_large_for_mailbox = $product->get_meta( '_posten_bring_checkout_too_large_for_mailbox' );
				$exclude_mailbox = $too_large_for_mailbox === 'yes';
			}

			if (!$include_groupage_pallet) {
				$requires_groupage_pallet = $product->get_meta( '_posten_bring_checkout_always_show_groupage_pallet' );
				$include_groupage_pallet = $requires_groupage_pallet === 'yes';
			}

			$product_weight = $product->get_weight();

			$quantity = $values['quantity'];
			$in_stock = $product->is_in_stock() && (!$product->managing_stock() || $product->get_stock_quantity() >= $quantity);

			if (empty($product_weight) || !is_numeric($product_weight)) {
				$product_weight = 0;
			}

			$item = [
				'weight' => WeightUtils::getWeightInGrams($product_weight),
				'quantity' => $quantity,
				'inStock' => $in_stock
			];

			$items[] = $item;
		}

		if ( function_exists( 'icl_get_languages' ) ) { // If WPML is installed.
			$current_locale = apply_filters( 'wpml_current_language', NULL );
		} elseif ( function_exists( 'pll_current_language' ) ) { // If Polylang is installed.
			$current_locale = pll_current_language();
		}

		$coupon_codes = WC()->cart->get_applied_coupons();
		foreach ($coupon_codes as $coupon_code) {
			$coupon = new WC_Coupon($coupon_code);
			if ($coupon->get_free_shipping()) {
				$free_shipping_from_coupon = true;
			}
		}

		$checkoutApi = CheckoutApi::get_instance();
		try {
			$rates = $checkoutApi->getShippingRates(
				$from_country,
				$from_postal_code,
				$to_country,
				$to_postal_code,
				$address,
				$cart_total_with_discounts,
				$items,
				$current_locale,
				$currency,
				$exclude_lockers,
				$exclude_mailbox,
				$free_shipping_from_coupon ?? false,
				$include_groupage_pallet
			);
			if ( !empty( $rates['rates'] ) ) {
				foreach ($rates['rates'] as $r) {
					$shipping_rate_id = $this->get_shipping_rate_id( $r['shippingRateType'] );

					if ( !empty( $shipping_rate_id ) ) {
						$displayName = $r['displayName'];
						$brand = $r['brand'];
						$price = $r['price'];

						$vat = array();
						if (wc_tax_enabled()) {
							$vat = WC_Tax::calc_inclusive_tax( $price, WC_Tax::get_shipping_tax_rates());
						}

						$vat_value = !empty( $vat ) ? array_values( $vat )[0] : 0.0;
						$price_excl_vat = $price - $vat_value;

						$rate = array(
							'id' => $shipping_rate_id,
							'label' => str_starts_with($displayName, 'Bring') ?
								$displayName :
								$brand . " • " . $displayName,
							'cost'  => $price_excl_vat,
							'taxes' => $vat,
							'delivery_time_summary' => $r['leadTimeSummary'] ?? null,
							'meta_data' => array(
								'service_id' => $r['serviceId'],
								'pickup_points' => $r['pickupPoints'],
								'third_party_shipping_provider' => $r['thirdPartyShippingProvider'],
								'lead_time' => $r['leadTime'],
								'brand' => $brand,
								'service_name' => $displayName,
								'environmental_data' => $r['environmentalData'],
								'service_description' => $r['serviceDescription']
							)
						);

						$rate = DinteroIntegration::add_dintero_meta_data( $rate, $r, $to_country );

						$this->add_rate( $rate );
					}
				}
			}
		} catch ( \Exception $e) {
			wc_get_logger()->warning("Failed to calculate shipping rates: " . esc_html($e->getMessage()), array ( 'source' => 'posten-bring-checkout' ) );
		}
	}

	private static function get_shipping_rate_id( $shipping_rate_type ): ?string {
		$ids = array(
			'PARCEL_LOCKER' => 'posten-bring-checkout-parcel-locker',
			'PICKUP_POINT' => 'posten-bring-checkout-pickup-point',
			'MAILBOX' => 'posten-bring-checkout-mailbox',
			'MAILBOX_ABROAD' => 'posten-bring-checkout-mailbox',
			'DOOR' => 'posten-bring-checkout-home-delivery',
			'PARCEL_TO_BUSINESS' => 'posten-bring-checkout-parcel-to-business',
			'GROUPAGE' => 'posten-bring-checkout-groupage',
			'PALLET' => 'posten-bring-checkout-pallet'
		);

		return $ids[$shipping_rate_type] ?? null;
	}
}
