<?php

namespace Simplyin\Simplyin_W_Plugin\Shipping_Mapping;

use Simplyin\Simplyin_W_Plugin\Admin\Shipping_Mapping_Options;
use Simplyin\Simplyin_W_Plugin\Shipping_Mapping\Integration\Apaczka\Apaczka_Integration_Factory;
use Simplyin\Simplyin_W_Plugin\Shipping_Mapping\Integration\Door_Delivery_Integration_Factory;
use Simplyin\Simplyin_W_Plugin\Shipping_Mapping\Integration\Fs\Fs_Integration_Factory;
use Simplyin\Simplyin_W_Plugin\Shipping_Mapping\Integration\Furgonetka\Furgonetka_Integration_Factory;
use Simplyin\Simplyin_W_Plugin\Shipping_Mapping\Integration\Inpost_Plugin\Inpost_Plugin_Integration_Factory;
use Simplyin\Simplyin_W_Plugin\Shipping_Mapping\Integration\Integration_Factory_Interface;
use Simplyin\Simplyin_W_Plugin\Shipping_Mapping\Integration\Integration_Interface;
use Simplyin\Simplyin_W_Plugin\Shipping_Mapping\Integration\Multi_Integration_Interface;
use Simplyin\Simplyin_W_Plugin\Shipping_Mapping\Simplyin\Simplyin_Method;
use Simplyin\Simplyin_W_Plugin\Shipping_Mapping\Simplyin\Simplyin_Method_Factory;
use Simplyin\Simplyin_W_Plugin\Shipping_Mapping\Simplyin\Simplyin_Method_Interface;
use WC_Shipping_Method;
use WC_Shipping_Zones;

class Mapping {

	/**
	 * @var WC_Shipping_Method[]
	 */
	static protected array $woo_shipping_methods_cache = [];

	/**
	 * @var string[]
	 */
	static protected array $available_providers_cache = [];

	/**
	 * @var Integration_Factory_Interface[]
	 */
	static protected array $integration_factory_cache = [];

	/**
	 * @var Mapping_Item[]
	 */
	private array $mapping_items = [];

	public function get_available_providers( bool $for_api_request = false
	): array {
		if ( ! empty( self::$available_providers_cache ) ) {
			return self::$available_providers_cache;
		}

		$providers = [];
		foreach ( $this->get_available_integrations() as $integration ) {
			if ( $integration instanceof Multi_Integration_Interface ) {
				foreach ( $integration->get_logistic_providers() as $provider ) {
					$providers[] = $provider;
				}
			} else {
				$providers[] = $integration->get_logistic_provider();
			}
		}


		self::$available_providers_cache = $providers;
		$providers                       = array_values( array_unique( $providers ) );

		self::$available_providers_cache = $providers;

		if ( $for_api_request ) {
			$key = array_search( 'door_delivery', $providers );
			if ( false !== $key ) {
				unset( $providers[ $key ] );
				$providers = array_values( $providers );
			}
		}

		return $providers;
	}


	/**
	 * @param Simplyin_Method_Interface[] $simplyin_methods
	 * @param Integration_Interface[] $integrations
	 *
	 * @return Mapping_Item[]
	 */
	public function build_mapping() {
		$result           = [];
		$simplyin_methods = $this->get_available_simplyin_methods();
		$integrations     = $this->get_available_integrations();


		foreach ( $simplyin_methods as $simplyin_method ) {
			$item = new Mapping_Item();
			$item->set_simplyin_method( $simplyin_method );
			/**
			 * @var Integration_Interface $integration
			 */
			foreach ( $integrations as $integration ) {
				if ( $simplyin_method->is_integration_supported( $integration ) ) {

					$item->put_integration( $integration );
				}
			}
			$result[] = $item;

		}

		return $result;
	}

	public function get_cached_integrations(): array {
		$result = get_option( 'SimplyInShippingIntegrations' );

		return ! $result ? [] : (array) $result;
	}

	public function get_mapping_cache(): array {
		$cache = (array) get_option( 'SimplyInShippingMappingCache' );

		return $cache;
	}

	public function handle_checkout() {
		$mapping_options = new Shipping_Mapping_Options( $this );
		$mapping_options->rebuild_mapping();

		$checkout               = new Checkout();
		$available_delivery     = $checkout->get_available_delivery();
		$mapping                = $this->get_mapping_cache();
		$available_integrations = $this->get_cached_integrations();

		$result                      = [];
		$available_providers_in_cart = [];
		$keys                        = [];
		foreach ( $available_integrations as $simplyin_method_id => $integrations ) {
			$simplyin_method = $this->get_simplyin_method( $simplyin_method_id );
			if ( is_array( $integrations ) ) {

				foreach ( $integrations as $k => $integration ) {
					$available_delivery_item_in_cart = $available_delivery->get_item( $k );

					if ( $available_delivery_item_in_cart ) {

						if ( isset( $mapping[ $simplyin_method_id ] ) && $mapping[ $simplyin_method_id ] === $k ) {
							unset( $integration['title'] );
							$integration['cost']                 = $available_delivery_item_in_cart->get_cost();
							$result[ $simplyin_method_id ][ $k ] = $integration;
							$available_providers_in_cart[]       = $simplyin_method->get_logistic_provider();
						}

					}
				}
			}
		}

		$available_providers_in_cart = array_unique( $available_providers_in_cart );
		$available_providers_in_cart = array_values( $available_providers_in_cart );


		simplyin()->get_simplyin_logger()->log_if_wpdebug_on(
			sprintf( "[Checkout] [check_delivery_parameters] %s",
				wp_json_encode(
					[
						'result'                     => $result,
						'mapping'                    => $mapping,
						'simply_available_providers' => $available_providers_in_cart,
					] ),

			),
			'shipping_mapping' );

		if ( ! headers_sent() ) {

			simplyin()->get_simplyin_logger()->log_if_wpdebug_on(
				sprintf( "[Checkout] [check_delivery_parameters] [wc_setcookie] %s",
					wp_json_encode(
						[
							'result'      => $result,
							'result_json' => json_encode( $result ),
						] ),

				),
				'shipping_mapping' );


			wc_setcookie(
				'simply_available_delivery',
				json_encode( $result ),
				$this->get_session_expiration(),
				false,
				false
			);

			wc_setcookie(
				'simply_shipping_mapping',
				json_encode( $mapping ),
				$this->get_session_expiration(),
				false,
				false
			);

			wc_setcookie(
				'simply_available_providers',
				json_encode( $available_providers_in_cart ),
				$this->get_session_expiration(),
				false,
				false
			);
		}


	}

	private function get_session_expiration() {
		if ( isset( WC()->session ) ) {
			$cookie = WC()->session->get_session_cookie();
			if ( isset( $cookie[1] ) ) {
				return WC()->session->get_session_cookie()[1];
			}
		}

		return strtotime( '+2 days' );
	}

	public function get_mapping_items(): array {

		if ( empty( $this->mapping_items ) ) {
			$this->mapping_items = $this->build_mapping();
		}

		return $this->mapping_items;
	}

	private function get_shipping_zones(): array {
		$data_store = \WC_Data_Store::load( 'shipping-zone' );
		$raw_zones  = $data_store->get_zones();
		foreach ( $raw_zones as $raw_zone ) {
			$zones[] = new \WC_Shipping_Zone( $raw_zone );
		}
		$zones[] = new \WC_Shipping_Zone( 0 );

		return $zones;
	}

	private function get_available_shipping_methods(): array {
		if ( ! empty( self::$woo_shipping_methods_cache ) ) {
			return self::$woo_shipping_methods_cache;
		}

		$available = [];

		foreach ( $this->get_shipping_zones() as $zone ) {
			$zone_shipping_methods = $zone->get_shipping_methods();
			foreach ( $zone_shipping_methods as $method ) {
				$available[ $method->get_rate_id() ] = $method;
			}
		}

		self::$woo_shipping_methods_cache = $available;

		return $available;
	}

	/**
	 * @return Simplyin_Method_Interface[]
	 */
	public function get_available_simplyin_methods(): array {
		return ( new Simplyin_Method_Factory() )->get_available_simply_methods();

	}

	public function get_simplyin_method( string $simplyin_method_id
	): ?Simplyin_Method {
		$methods = $this->get_available_simplyin_methods();
		foreach ( $methods as $method ) {
			if ( $method->get_id() === $simplyin_method_id ) {
				return $method;
			}
		}

		return null;
	}

	/**
	 * @return Integration_Interface[]
	 */
	public function get_available_integrations(): array {

		$available_methods = $this->get_available_shipping_methods();
		$result            = [];

		$door_integration_factory = new Door_Delivery_Integration_Factory();


		foreach ( $available_methods as $method ) {
			$found_integrations = 0;
			foreach ( $this->get_available_integration_factories() as $integration_factory ) {

				$instance = $integration_factory->create( $method );
				if ( $instance ) {
					$result[]           = $instance;
					$found_integrations += 1;
				}
			}
			if ( $found_integrations === 0 ) {
				$instance = $door_integration_factory->create( $method );
				$result[] = $instance;
			}

		}

		return $result;
	}


	/**
	 * @return Integration_Factory_Interface[]
	 */
	public function get_available_integration_factories(): array {
		if ( empty( self::$integration_factory_cache ) ) {
			$this->setup_available_integration_factories();
		}

		return self::$integration_factory_cache;

	}

	private function setup_available_integration_factories(): void {
		self::$integration_factory_cache[] = new Inpost_Plugin_Integration_Factory();
		self::$integration_factory_cache[] = new Fs_Integration_Factory();
		self::$integration_factory_cache[] = new Apaczka_Integration_Factory();
		self::$integration_factory_cache[] = new Furgonetka_Integration_Factory();

		//self::$integration_factory_cache[] = new Default_Integration_Factory();
	}
}
