<?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_Blocks_Mapper {

	private static array $type_names_cache = [];

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

	/**
	 * @var AvailablePaymentMethod[]
	 */
	private array $methods_deserialized;

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


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

		$items = [];


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

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


			$paymentProvider = $channel->getPaymentProvider();
			$isBlik          = $channel->getType() === 'blik';
			$isCard          = $channel->getType() === 'card';
			$isAddCard       = $channel->getType() === 'add_card';

			$channelId = $channel->getPaymentMethodId();

			if ( $isBlik ) {
				$label            = __( 'BLIK', 'simplyin' );
				$icon             = $channel->getLogoThumbnailUrl();
				$blockDescription = __( 'Enter BLIK code',
					'simplyin' );
			} elseif ( $isCard ) {
				$cardData = $channel->getCard();
				if ( $cardData ) {
					$label = sprintf( '%s (**%s)',
						$channel->getName(),
						$cardData->getLastDigitsOfCardNumber()
					);
					$icon  = $channel->getLogoThumbnailUrl();
					/* translators: %s: last 4 digits of the card number. */
					$blockDescription = sprintf( __( 'Saved card ending with %s',
						'simplyin' ),
						$cardData->getLastDigitsOfCardNumber()
					);
				} else {
					$label            = $paymentProvider ? $paymentProvider->getName() : $channel->getName();
					$icon             = $paymentProvider ? $paymentProvider->getLogoUrl() : $channel->getLogoThumbnailUrl();
					$blockDescription = $channel->getTypeName() ?? '';
				}
			} elseif ( $isAddCard ) {
				$addCardData      = $channel->getAddCard();
				$label            = $channel->getName();
				$icon             = $paymentProvider ? $paymentProvider->getLogoUrl() : $channel->getLogoThumbnailUrl();
				$blockDescription = __( 'Add and save a new payment card',
					'simplyin' );
			} else {
				$label            = $paymentProvider ? $paymentProvider->getName() : $channel->getName();
				$icon             = $paymentProvider ? $paymentProvider->getLogoUrl() : $channel->getLogoThumbnailUrl();
				$blockDescription = $channel->getTypeName() ?? '';
			}

			$addCardInfo = null;
			if ( $isAddCard ) {
				$addCardData = $channel->getAddCard();
				if ( $addCardData ) {
					$addCardInfo = [
						'integratorId'   => $addCardData->getIntegratorId(),
						'iframeUrl'      => $addCardData->getIframeUrl(),
						'enableSaveCard' => $addCardData->getEnableSaveCard(),
					];
				}
			}

			$items[] = [
				'simplyinPaymentOptionId' => $channelId,
				'id'                      => $channelId,
				'value'                   => $channelId,
				'name'                    => 'simplyin_payment_method',
				'label'                   => $label,
				'icon'                    => $icon,
				'block_description'       => $blockDescription,
				'items'                   => [],
				'data'                    => [
					'blik'            => $isBlik,
					'isCard'          => $isCard,
					'isAddCard'       => $isAddCard,
					'paymentMethodId' => $channel->getPaymentMethodId(),
					'addCard'         => $addCardInfo,
				],
			];
		}


		return $items;
	}


	/**
	 * @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 ];
	}

}
