<?php

namespace Repetito\Web;

// If this file is called directly, abort.
if ( ! defined( 'ABSPATH' ) ) {
	exit;
}


use Repetito\Traits\Singleton;
use const Repetito\NAME;
use const Repetito\NOREPETITO_TAG;
use Repetito\Web\BoxPacker;
use Repetito\Traits\OrderUtils;

class Frontend
{


	use Singleton;
	use OrderUtils;
	const REPETITO_LINK = 'https://www.repetito.sk/';

	const PACKAGES = array(
		array(
			'name'     => 'soft_s',
			'volume'   => 2016,
			'niceName' => 'Soft S',
			'width'    => 21,
			'height'   => 24,
			'length'   => 4,
			'unit'     => 'cm',
		),
		array(
			'name'     => 'soft_m',
			'volume'   => 7980,
			'niceName' => 'Soft M',
			'width'    => 38,
			'height'   => 30,
			'length'   => 7,
			'unit'     => 'cm',
		),
		array(
			'name'     => 'soft_l',
			'volume'   => 20868,
			'niceName' => 'Soft L',
			'width'    => 47,
			'height'   => 37,
			'length'   => 12,
			'unit'     => 'cm',
		),
		array(
			'name'     => 'box_s',
			'volume'   => 2990,
			'niceName' => 'Box S',
			'width'    => 23,
			'height'   => 13,
			'length'   => 10,
			'unit'     => 'cm',
		),
		array(
			'name'     => 'box_m',
			'volume'   => 6468,
			'niceName' => 'Box M',
			'width'    => 28,
			'height'   => 21,
			'length'   => 11,
			'unit'     => 'cm',
		),
	);

	/**
	 * Renders repetito fee checkbox on front-end
	 * `render` methods
	 *
	 * @param array $tags An array of shortcode tags.
	 */
	protected function __construct()
	{
		add_action('woocommerce_review_order_before_payment', array( $this, 'showFeeCheckbox' ), 10 );
		add_action('woocommerce_before_calculate_totals', array($this, 'maybeUnsetFee'), 10);

		add_filter('woocommerce_form_field', array($this, 'formatChecbox'), 10, 4);

		add_action('wp_ajax_nopriv_repetito_apply_fee', array($this, 'applyFee'));
		add_action('wp_ajax_repetito_apply_fee', array($this, 'applyFee'));

		add_action('wp_ajax_nopriv_repetito_apply_reload', array($this, 'reload'));
		add_action('wp_ajax_repetito_apply_reload', array($this, 'reload'));

		add_action('woocommerce_cart_calculate_fees', array($this, 'calculateFee'), 10, 1);
		add_action(
			'woocommerce_init',
			function () {
				if (false === $this->pluginEnabled()) {
					return;
				}
				do_shortcode('[repetito]');
				woocommerce_register_additional_checkout_field(
					[
						'id'            => 'repetito/fee',
						'label'         => 'Repetito',
						'optionalLabel' => sprintf(
							/* translators: 1: Service description text, 2: Fee price, 3: Currency symbol */
							__( '%1$s! (%2$s %3$s)', 'repetito' ),
							__( 'Deliver my order in reusable returnable packaging', 'repetito' ),
							number_format_i18n($this->getFeePriceIncludingTax(), 2),
							html_entity_decode(get_woocommerce_currency_symbol(), ENT_QUOTES, 'UTF-8')
						),
						'location'      => 'order',
						'type'          => 'checkbox',
						'attributes'    => [
							'data-name'      => 'repetito_fee',
						],
					],
				);
			}
		);

		add_action(
			'woocommerce_blocks_loaded',
			function() {
			  $asset_data_registry = \Automattic\WooCommerce\Blocks\Package::container()->get( \Automattic\WooCommerce\Blocks\Assets\AssetDataRegistry::class );
			  $asset_data_registry->add( 'repetito/link', self::REPETITO_LINK );
			  $asset_data_registry->add( 'repetito/div', $this->getRepetitoDiv() );
			}
		);

		add_filter(
			"woocommerce_get_default_value_for_repetito/fee",
			function ($value, $group, $wc_object) {
				$has_fee = $this->cartHasFee(WC()->cart);
				return $has_fee ? 1 : 0;
			},
			10,
			3
		);
	}

	private function getFeeCountry(): string
	{
		$options = get_option('repetito-settings');
		if ($options && array_key_exists('tax_country', $options) && $options['tax_country']) {
			return $options['tax_country'];
		}
		return "";
	}

	private function getFeePrice(): float
	{
		$options = get_option('repetito-settings');
		if ($options && array_key_exists('tax_price', $options) && $options['tax_price']) {
			return (float) $options['tax_price'];
		}
		return 0;
	}

	private function getFeePriceIncludingTax(): float
	{
		// check if tax is enabled
		if (wc_tax_enabled()) {
			$price = $this->getFeePrice();
			$tax   = $this->getFeeTax();
			return round($price + ($price * ($tax / 100)), 2);
		}
		return $this->getFeePrice();
	}

	private function getFeeMaxTreshold(): int
	{
		$options = get_option('repetito-settings');
		if ($options && array_key_exists('tax_weight', $options) && $options['tax_weight']) {
			return (int) $options['tax_weight'];
		}
		return 0;
	}

	private function getFeeTax(): float
	{
		$tax_rate_class = $this->getFeeTaxRateClass();
		$tax_rates = \WC_Tax::get_rates($tax_rate_class);
		foreach ($tax_rates as $tax_rate) {
			return $tax_rate['rate'];
		}
		return 0;
	}
	private function getFeeTaxRateClass(): string
	{
		$options = get_option('repetito-settings');
		if ($options && array_key_exists('tax_class', $options) && $options['tax_class']) {
			return \WC_Tax::format_tax_rate_class($options['tax_class']);
		}
		return "";
	}

	private function getShowImage(): bool
	{
		$options = get_option('repetito-settings');
		if ($options && array_key_exists('general_show_image', $options) && $options['general_show_image']) {
			return (bool) $options['general_show_image'];
		}
		return false;
	}

	private function getDimensionFittingEnabled(): bool
	{
		$options = get_option('repetito-settings');
		if ($options && array_key_exists('packages_dimension_fitting', $options)) {
			return (bool) $options['packages_dimension_fitting'];
		}
		return false;
	}

	private function getSelectedPackages(): array
	{
		$options = get_option('repetito-settings');
		if ($options && array_key_exists('packages_selection', $options) && is_array($options['packages_selection'])) {
			return $options['packages_selection'];
		}
		return array();
	}

	public function pluginEnabled(): bool
	{
		if (! class_exists('woocommerce')) {
			return false;
		}

		if (false === get_option('repetito-settings')) {
			return false;
		}
		return true;
	}

	public function serviceActive(): bool
	{
		$options = get_option('repetito-settings');
		if ($options && array_key_exists('general_service_active', $options) && $options['general_service_active']) {
			return (bool) $options['general_service_active'];
		}
		return false;
	}


	public function feeEnabled(): bool
	{
		if (!$this->pluginEnabled()) {
			return false;
		}

		if (WC()->cart->is_empty()) {
			return false;
		}

		if (!$this->countryEnabled()) {
			return false;
		}

		$cart_weight  = WC()->cart->get_cart_contents_weight();
		$fee_max_treshold = $this->getFeeMaxTreshold();

		if ($cart_weight > $fee_max_treshold) {
			return false;
		}

		// check if any of the cart items has the NOREPETITO_TAG tag
		$cart_items = WC()->cart->get_cart();
		$cart_items_with_norepetito_tag = array_filter($cart_items, function($item) {
			$tags = wc_get_product_tag_list($item['data']->get_id(), ', ', '', '');
			return $tags && !(strpos($tags, NOREPETITO_TAG) === false);
		});

		if (count($cart_items_with_norepetito_tag) > 0) {
			return false;
		}

		// Check if dimension fitting is enabled
		if ($this->getDimensionFittingEnabled()) {
			// Get selected packages from settings
			$selected_package_names = $this->getSelectedPackages();

			// If no packages are selected, dimension fitting cannot work
			if (empty($selected_package_names)) {
				return false;
			}

			// Filter packages to only include selected ones
			$available_packages = array_filter(
				self::PACKAGES,
				function ($p) use ($selected_package_names) {
					return in_array($p['name'], $selected_package_names);
				}
			);

			// sort packages by smallest so we can start with the smallest for economy reasons
			usort(
				$available_packages,
				function ($a, $b) {
					return ($a['volume'] <=> $b['volume']);
				}
			);

			$final_package = '';
			foreach ($available_packages as $package) {
				// if all the sizes fits, set packaging and dont continue the loop
				if (BoxPacker::fitsIntoPackage($cart_items, $package, WC()->cart->get_cart_contents_count()) === false) {
					continue;
				} else {
					$final_package = $package['name'];
					break;
				}
			}

			// if no package found - abort
			if ($final_package === '') {
				return false;
			}
		}
		// If dimension fitting is disabled, skip package checking entirely

		return $this->serviceActive();

	}

	public function countryEnabled()
	{
		$country         = WC()->customer->get_shipping_country() ?: WC()->customer->get_billing_country();
		$enabled_country = $this->getFeeCountry();
		return $country === $enabled_country;
	}

	public function maybeUnsetFee(): void
	{
		if (false === $this->feeEnabled() || false === $this->countryEnabled()) {
			$fees = WC()->cart->get_fees();
			foreach ($fees as $key => $fee) {
				if (in_array(sanitize_title($fee->name), $this->possibleFeeNames())) {
					unset($fees[$key]);
				}
			}
			WC()->cart->fees_api()->set_fees($fees);
			WC()->session->__unset('repetito_fee');
		}
	}

	public function showFeeCheckbox(): void {
		echo do_shortcode( '[repetito]' );

		if ( false === $this->feeEnabled() || false === $this->countryEnabled() ) {
			return;
		}

		woocommerce_form_field(
			'repetito_fee',
			array(
				'type'    => 'checkbox',
				'label'   => sprintf(
					/* translators: 1: Service description text, 2: Fee price, 3: Currency symbol */
					__( '%1$s! (%2$s %3$s)', 'repetito' ),
					__( 'Deliver my order in Repetito reusable returnable packaging', 'repetito' ),
					number_format_i18n($this->getFeePriceIncludingTax(), 2),
					get_woocommerce_currency_symbol()
				),
				'default' => WC()->session->get( 'repetito_fee' ) ? true : false,
			),
			''
		);
	}

	public function applyFee()
	{
		if (check_ajax_referer(NAME, 'nonce')) {
			$fee = isset($_POST['applyFee']) ? filter_var(wp_unslash($_POST['applyFee']), FILTER_SANITIZE_NUMBER_INT) : 0;
			WC()->session->set('repetito_fee', ($fee ? '1' : '0'));

			wp_send_json_success();
		} else {
			wp_send_json_error();
		}
	}

	public function reload()
	{
		if (check_ajax_referer(NAME, 'nonce')) {
			wp_send_json_success(array('show' => ((int) $this->countryEnabled() && (int) $this->feeEnabled())));
		} else {
			wp_send_json_error();
		}
	}

	public function calculateFee($cart)
	{
		if ( false === $this->countryEnabled() ) {
			WC()->session->__unset('repetito_fee');
		}
		if (WC()->session->get('repetito_fee')) {
			$fee_price = $this->getFeePrice();
			$tax_rate = $this->getFeeTaxRateClass();

			$cart->add_fee( __( 'Repetito reusable returnable packaging', 'repetito' ), $fee_price, true, $tax_rate );
		}
	}

	public function formatChecbox( $field, $key, $args, $value ) {
		if ( 'repetito_fee' === $key && is_checkout() ) {
			$field    = '<div id="repetito">' . $field . '</div>';

			$showImage = $this->getShowImage();

			if ( true === $showImage ) {
				$image = \Repetito\PLUGIN_URL . 'assets/website/static/logo.png';
			} else {
				$image = false;
			}

			$name      = __( 'Repetito reusable returnable packaging', 'repetito' );
			$desc      = __( 'Help us reduce waste from online shopping.', 'repetito' );
			$desc_long = __( 'What is reusable returnable packaging?', 'repetito' );

			if ( false !== $image && '' !== $image ) {
				$field = str_replace( 'class="woocommerce-input-wrapper">', 'class="woocommerce-input-wrapper"><img src="' . esc_url( $image ) . '" width="1896" height="531"><span class="inner">', $field );
			} else {
				$field = str_replace( 'class="woocommerce-input-wrapper">', 'class="woocommerce-input-wrapper"><span class="inner">', $field );
			}

			if ( $desc ) {
				$field = str_replace( 'class="inner">', 'class="inner"><span class="desc">' . esc_html( $desc ) . ' </span><a href="' . esc_url( self::REPETITO_LINK ) . '" target="_blank">' . esc_html( $desc_long ) . '</a>', $field );
			}

			if ( $name ) {
				$field = str_replace( 'class="inner">', 'class="inner"><span class="name">' . esc_html( $name ) . '</span>', $field );
			}

			$field = str_replace( '</label>', '</span></label>', $field );

			if ( WC()->session->get( 'repetito_fee' ) ) {
				$field = str_replace( 'id="repetito_fee"', 'id="repetito_fee" checked ', $field );
			}
		}
		return $field;
	}

	public function getRepetitoDiv() {
		$showImage = $this->getShowImage();

		if ( true === $showImage ) {
			$image = \Repetito\PLUGIN_URL . 'assets/website/static/logo.png';
		} else {
			$image = false;
		}
		return
		'<div id="repetito">' .
		'<p class="form-row woocommerce-validated" id="repetito_fee_field" data-priority="">' .
		'<span class="woocommerce-input-wrapper">' .
		( $image ? '<img loading="lazy" decoding="async" src="' . esc_url( $image ) . '" width="1896" height="531">' : '' ) .
		'<span class="inner"><span class="name">{NAME}</span><span class="desc">{DESC}</span>' .
		'<a href="' . esc_url( self::REPETITO_LINK ) . '" target="_blank">{DESC_LONG}</a>' .
		'</span></span></p></div>';
	}
}
