<?php

namespace Simplyin\Simplyin_W_Plugin\Payments\Mappers\View_Model;

use Exception;
use Simplyin\Simplyin_W_Plugin\Lib\Remote\SimplyInApi\Model\PaymentsGetAvailablePaymentMethods200ResponseInner as AvailablePaymentMethod;
use Simplyin\Simplyin_W_Plugin\Payments\View_Model\Classic_Checkout\Payment_Method_Expandable_Group;
use Simplyin\Simplyin_W_Plugin\Payments\View_Model\Classic_Checkout\Payment_Method_Item_Add_Card;
use Simplyin\Simplyin_W_Plugin\Payments\View_Model\Classic_Checkout\Payment_Method_Item_Card;
use Simplyin\Simplyin_W_Plugin\Payments\View_Model\Classic_Checkout\Payment_Method_Group;
use Simplyin\Simplyin_W_Plugin\Payments\View_Model\Classic_Checkout\Payment_Method_Item;
use Simplyin\Simplyin_W_Plugin\Payments\View_Model\Classic_Checkout\Payment_Method_Item_Provider;
use Simplyin\Simplyin_W_Plugin\Payments\View_Model\Classic_Checkout\Payment_Method_Provider_Group;

class Payment_Methods_Group_Mapper {

	private static array $type_names_cache = [];

	/**
	 * @var array<Payment_Method_Item_Provider>
	 */
	private static array $providers_cache = [];

	/**
	 * @var AvailablePaymentMethod[]
	 */
	private $methods_desaralised;

	/**
	 * @param AvailablePaymentMethod[]
	 */
	public function __construct( array $raw_channels_from_simplyin_api ) {
		$this->methods_desaralised = $raw_channels_from_simplyin_api;
	}


	/**
	 * @return Payment_Method_Provider_Group
	 * @throws Exception
	 */
	public function map(): Payment_Method_Provider_Group {
		$providers = [];

		foreach ( $this->methods_desaralised as $raw_channel ) {
			$provider_raw = $raw_channel->getPaymentProvider();
			$provider     = new Payment_Method_Item_Provider(
				$provider_raw->getId(),
				$provider_raw->getName(),
				$provider_raw->getLogoUrl(),
				$provider_raw->getRegulationsUrl(),
				$provider_raw->getGdprUrl()
			);

			if ( ! isset( $providers[ $provider_raw->getId() ] ) ) {
				$providers[ $provider_raw->getId() ] = [];
			}
			$types = $providers[ $provider_raw->getId() ];

			$card_raw = $raw_channel->getCard();
			$add_card_raw = $raw_channel->getAddCard();

			$card = $add_card = null;

			if ( $card_raw ) {
				$card = new Payment_Method_Item_Card(
					$card_raw->getProvider(),
					$card_raw->getLastDigitsOfCardNumber(),
				);
			}
			if ( $add_card_raw ) {
				$add_card = new Payment_Method_Item_Add_Card(
					$add_card_raw->getIframeUrl(),
					$add_card_raw->getIntegratorId(),
					$add_card_raw->getEnableSaveCard(),
				);
			}


			if ( 'card' === $raw_channel->getType() && ! $card ) {
				continue;
			}

			if ( 'add_card' === $raw_channel->getType() && ! $add_card ) {
				continue;
			}


			if ( 'add_card' === $raw_channel->getType() && ! key_exists( 'card',
					$types ) ) {

			}

			$types[ $raw_channel->getType() ][] = ( new Payment_Method_Item(
				$raw_channel->getName(),
				$raw_channel->getPaymentMethodId(),
				$raw_channel->getType(),
				$raw_channel->getTypeName(),
				$raw_channel->getSlug(),
				$raw_channel->getLogoThumbnailUrl(),
				'',
				'',
				'',
				$provider,
				$card,
				$add_card ) );


			self::cache_type_name( $raw_channel->getType(),
				$raw_channel->getTypeName() );

			self::cache_provider( $provider_raw->getId(),
				$provider );

			$providers[ $provider_raw->getId() ] = $types;

		}

		/*if ( isset( $providers[ $provider_raw->getId() ]['add_card'] )
		     && isset( $providers[ $provider_raw->getId() ]['card'] ) ) {
			$providers[ $provider_raw->getId() ]['card'] = array_merge( $providers[ $provider_raw->getId() ]['card'],
				$providers[ $provider_raw->getId() ]['add_card'] );
			unset( $providers[ $provider_raw->getId() ]['add_card'] );
		}*/


		$provider_groups = [];

		foreach ( $providers as $provider_id => $types ) {

			$types = self::sort_types_for_checkout( $types );

			$provider_group = new Payment_Method_Provider_Group(
				self::$providers_cache[ $provider_id ],
				[],
				'' );

			foreach ( $types as $k => $type_items ) {

				/*
				 * array $items,
			string $name,
			string $slug,
			string $icon,
			string $subtitle
				 */
				if ( count( $type_items ) > 1 && 'card' !== $k ) {
					$sub_group = new Payment_Method_Expandable_Group(
						$type_items,
						self::get_type_name( $k ),
						$k,
						'',
						$k

					);
					$provider_group->push_group( $sub_group );
				} else {
					$provider_group->set_items( array_merge( $provider_group->get_items(),
						$type_items ) );
				}


			}

			$provider_groups[ $provider_group->get_provider()
			                                 ->get_id() ] = $provider_group;

		}

		if ( empty( $provider_groups ) ) {
			throw new Exception( "Empty provider groups" );
		}

		if ( count( $provider_groups ) > 1 ) {
			throw new Exception( "Unsupported provider_groups qty" );
		}


		return $provider_groups[ array_key_first( $provider_groups ) ];
	}


	/**
	 * @param array<string, array<int, Payment_Method_Item>> $types
	 *
	 * @return array<string, array<int, Payment_Method_Item>>
	 */
	private static function sort_types_for_checkout( array $types ): array {
		$type_priority_map = [ 'card' => 0, 'add_card' => 1 ];

		uksort(
			$types,
			static function ( string $typeA, string $typeB ) use (
				$type_priority_map
			): int {
				$weightA = $type_priority_map[ $typeA ] ?? 100;
				$weightB = $type_priority_map[ $typeB ] ?? 100;

				if ( $weightA === $weightB ) {
					return strcmp( $typeA, $typeB );
				}

				return $weightA <=> $weightB;
			}
		);

		return $types;
	}

	private static function cache_type_name( string $key, string $name ) {
		if ( ! key_exists( $key,
			self::$type_names_cache,
		) ) {
			self::$type_names_cache[ $key ] = $name;
		}
	}

	private static function cache_provider(
		string $provider_id,
		Payment_Method_Item_Provider $provider
	) {
		if ( ! key_exists( $provider_id,
			self::$providers_cache,
		) ) {
			self::$providers_cache[ $provider_id ] = $provider;
		}
	}

	private static function get_type_name( string $key ): string {
		return self::$type_names_cache[ $key ];
	}

}
