<?php
/**
 * Class DhlInstanceSettings
 *
 * @package DhlPolska\ShippingMethod
 */

namespace DhlPolska\ShippingMethod;

use DhlPolskaVendor\Octolize\DhlPolska\API\WebApi\Struct\Services\AgeverService;
use DhlPolskaVendor\Octolize\DhlPolska\API\WebApi\Struct\Services\NadSobotaService;
use DhlPolskaVendor\Octolize\DhlPolska\API\WebApi\Struct\Services\NstService;
use DhlPolskaVendor\Octolize\DhlPolska\API\WebApi\Struct\Services\PdiService;
use DhlPolskaVendor\Octolize\DhlPolska\API\WebApi\Struct\Services\PodService;
use DhlPolskaVendor\Octolize\DhlPolska\API\WebApi\Struct\Services\RodService;
use DhlPolskaVendor\Octolize\DhlPolska\API\WebApi\Struct\Services\Service1722;
use DhlPolskaVendor\Octolize\DhlPolska\API\WebApi\Struct\Services\SobotaService;
use DhlPolska\SettingsFields;
use DhlPolska\Shipment\DhlServices;
use DhlPolska\Shipment\ShipmentData;
use DhlPolska\Shipment\ShipmentTypes;
use DhlPolska\WooCommerceSettings\Templates\TemplatesRepository;
use DhlPolska\WooCommerceSettings\WooCommerceDHLPolskaSettings;

/**
 * DHL Instance Settings.
 */
class DhlInstanceSettings implements SettingsFields {
	public const OPTION_TITLE         = 'title';
	public const OPTION_SHOW_LOGO     = 'show_logo';
	public const OPTION_LOGO_VARIANT  = 'logo_variant';
	public const OPTION_TAX_STATUS    = 'tax_status';
	public const OPTION_SERVICE       = 'service';
	public const OPTION_POINT_TYPE    = 'point_type';
	public const OPTION_POINT_TYPE_PL = 'point_type_pl';
	public const OPTION_TEMPLATE      = 'template_id';
	public const OPTION_COST          = 'cost';
	private const SERVICE_CODE_MAP    = [
		ShipmentData::TEMPLATE_SERVICE_1722        => Service1722::TYPE,
		ShipmentData::TEMPLATE_SERVICE_SOBOTA      => SobotaService::TYPE,
		ShipmentData::TEMPLATE_SERVICE_NAD_SOBOTA  => NadSobotaService::TYPE,
		ShipmentData::TEMPLATE_SERVICE_INSURANCE   => 'UBEZP',
		ShipmentData::TEMPLATE_SERVICE_COD         => 'COD',
		ShipmentData::TEMPLATE_SERVICE_PDI         => PdiService::TYPE,
		ShipmentData::TEMPLATE_SERVICE_ROD         => RodService::TYPE,
		ShipmentData::TEMPLATE_SERVICE_POD         => PodService::TYPE,
		ShipmentData::TEMPLATE_SERVICE_AGEVER      => AgeverService::TYPE,
		ShipmentData::TEMPLATE_SERVICE_NST         => NstService::TYPE,
		ShipmentData::TEMPLATE_SERVICE_EURO_RETURN => 'EURO RETURN',
	];

	private TemplatesRepository $templates_repository;

	private ShipmentTypes $shipment_types;

	private ?int $instance_id;

	public function __construct( ?TemplatesRepository $templates_repository = null, ?ShipmentTypes $shipment_types = null, ?int $instance_id = null ) {
		$this->shipment_types       = $shipment_types ?? new ShipmentTypes();
		$this->templates_repository = $templates_repository ?? new TemplatesRepository( new WooCommerceDHLPolskaSettings(), $this->shipment_types );
		$this->instance_id          = $instance_id;
	}

	/**
	 * @return array<int|string, array<string, array<string, float|int|string>|bool|float|int|string>>
	 */
	public function get_settings_fields(): array {
		$fields = [
			'dhl_start' => [
				'type' => 'title',
			],
			self::OPTION_TITLE => [
				'title'    => __( 'Nazwa metody', 'dhl-polska' ),
				'type'     => 'text',
				'desc_tip' => __( 'Wyświetlana w koszyku i kasie.', 'dhl-polska' ),
			],
			self::OPTION_SHOW_LOGO => [
				'title'   => __( 'Logo DHL', 'dhl-polska' ),
				'type'    => 'checkbox',
				'label'   => __( 'Wyświetl logo DHL pod nazwą metody wysyłki.', 'dhl-polska' ),
				'default' => 'no',
			],
			self::OPTION_LOGO_VARIANT => [
				'title'    => __( 'Wariant logo DHL', 'dhl-polska' ),
				'type'     => 'select',
				'options'  => LogoVariants::get_variant_options(),
				'default'  => LogoVariants::get_default_variant(),
				'desc_tip' => __( 'Wybierz wariant logo wyświetlany pod nazwą metody wysyłki.', 'dhl-polska' ),
			],
			self::OPTION_TAX_STATUS => [
				'title'    => __( 'Status podatku', 'dhl-polska' ),
				'type'     => 'select',
				'default'  => 'taxable',
				'options'  => [
					'taxable' => __( 'Opodatkowany', 'dhl-polska' ),
					'none'    => _x( 'Brak', 'Tax status', 'dhl-polska' ),
				],
				'desc_tip' =>
					sprintf(
					// Translators: open strong tag, close strong tag.
						__(
							'Po wybraniu opodatkowania zastosowane będą stawki z %1$sWooCommerce → Ustawienia → Podatki%2$s.',
							'dhl-polska'
						),
						'<strong>',
						'</strong>'
					),
			],
			self::OPTION_SERVICE => [
				'title'   => __( 'Usługa DHL', 'dhl-polska' ),
				'type'    => 'select',
				'options' => ( new DhlServices() )->get_all_services(),
				'class'   => 'js--dhl-polska-service',
			],
		];

		if ( $this->should_show_point_type_field_for_non_pl() ) {
			$fields[ self::OPTION_POINT_TYPE ] = [
				'title'   => __( 'Typ punktu odbioru (zagranica)', 'dhl-polska' ),
				'type'    => 'select',
				'options' => [
					ShipmentData::POINT_TYPE_PACKSTATION => __( 'DHL BOX', 'dhl-polska' ),
					ShipmentData::POINT_TYPE_PARCELSHOP  => __( 'DHL POP', 'dhl-polska' ),
				],
				'default' => ShipmentData::POINT_TYPE_PARCELSHOP,
				'class'   => 'js--dhl-polska-point-type',
			];
		}

		if ( $this->should_show_point_type_field_for_pl() ) {
			$fields[ self::OPTION_POINT_TYPE_PL ] = [
				'title'   => __( 'Typ punktu odbioru (Polska)', 'dhl-polska' ),
				'type'    => 'select',
				'options' => [
					ShipmentData::POINT_TYPE_PL_ALL => __( 'Wszystkie punkty', 'dhl-polska' ),
					ShipmentData::POINT_TYPE_PL_BOX => __( 'DHL BOX', 'dhl-polska' ),
					ShipmentData::POINT_TYPE_PL_POP => __( 'DHL POP', 'dhl-polska' ),
				],
				'default' => ShipmentData::POINT_TYPE_PL_ALL,
				'class'   => 'js--dhl-polska-point-type-pl',
			];
		}

		$fields[ self::OPTION_TEMPLATE ] = [
			'title'    => __( 'Szablon przesyłki', 'dhl-polska' ),
			'type'     => 'select',
			'options'  => $this->get_template_options(),
			'default'  => '',
			'desc_tip' => __( 'Wybierz szablon przesyłki dla tej metody.', 'dhl-polska' ),
		];

		$fields[ self::OPTION_COST ] = [
			'title'       => __( 'Koszt', 'dhl-polska' ),
			'type'        => 'text',
			'placeholder' => '',
			'default'     => 0,
			'desc_tip'    => __( 'Stały koszt przesyłki dla tej metody.', 'dhl-polska' ),
		];
		$fields['dhl_end']           = [
			'type' => 'title',
		];

		return $fields;
	}

	/**
	 * @return array<string, string>
	 */
	private function get_template_options(): array {
		$options = [
			'' => __( 'Brak', 'dhl-polska' ),
		];

		$templates = $this->templates_repository->get_templates();
		foreach ( $templates as $template ) {
			if ( ! isset( $template['id'], $template['name'] ) ) {
				continue;
			}

			$options[ (string) $template['id'] ] = $this->format_template_option_label( $template );
		}

		return $options;
	}

	/**
	 * @param array<string, mixed> $template .
	 */
	private function format_template_option_label( array $template ): string {
		$weight_unit    = get_option( 'woocommerce_weight_unit', 'kg' );
		$dimension_unit = get_option( 'woocommerce_dimension_unit', 'cm' );
		$weight         = wc_format_decimal( (string) ( $template['weight'] ?? '' ) );
		$type_labels    = $this->shipment_types->get_type_labels();
		$type_label     = $type_labels[ (string) ( $template['type'] ?? '' ) ] ?? (string) ( $template['type'] ?? '' );
		$dimensions     = sprintf(
			'%sx%sx%s',
			(string) ( $template['dimensions']['length'] ?? '' ),
			(string) ( $template['dimensions']['width'] ?? '' ),
			(string) ( $template['dimensions']['height'] ?? '' )
		);
		$service_codes  = $this->get_template_service_codes( $template );

		$details = [
			$type_label,
			trim( $weight . ' ' . $weight_unit ),
			trim( $dimensions . ' ' . $dimension_unit ),
		];

		if ( [] !== $service_codes ) {
			$details[] = implode( ', ', $service_codes );
		}

		return sprintf(
			'%s (%s)',
			(string) ( $template['name'] ?? '' ),
			implode( ', ', $details )
		);
	}

	/**
	 * @param array<string, mixed> $template .
	 *
	 * @return string[]
	 */
	private function get_template_service_codes( array $template ): array {
		$services      = is_array( $template['services'] ?? null ) ? $template['services'] : [];
		$service_codes = [];

		foreach ( self::SERVICE_CODE_MAP as $service_key => $service_code ) {
			if ( ! empty( $services[ $service_key ] ) ) {
				$service_codes[] = $service_code;
			}
		}

		return $service_codes;
	}

	private function should_show_point_type_field_for_non_pl(): bool {
		$countries = $this->get_zone_countries();
		if ( null === $countries ) {
			return true;
		}

		foreach ( $countries as $country ) {
			if ( 'PL' !== strtoupper( $country ) ) {
				return true;
			}
		}

		return false;
	}

	private function should_show_point_type_field_for_pl(): bool {
		$countries = $this->get_zone_countries();
		if ( null === $countries ) {
			return true;
		}

		foreach ( $countries as $country ) {
			if ( 'PL' === strtoupper( $country ) ) {
				return true;
			}
		}

		return false;
	}

	/**
	 * @return string[]|null
	 */
	private function get_zone_countries(): ?array {
		if ( null === $this->instance_id || 0 === $this->instance_id ) {
			return null;
		}

		if ( ! class_exists( 'WC_Shipping_Zones' ) ) {
			return null;
		}

		$zone = \WC_Shipping_Zones::get_zone_by( 'instance_id', $this->instance_id );
		if ( ! $zone instanceof \WC_Shipping_Zone ) {
			return null;
		}

		if ( 0 === (int) $zone->get_id() ) {
			return null;
		}

		$locations = $zone->get_zone_locations();
		if ( empty( $locations ) ) {
			return null;
		}

		$countries = [];
		foreach ( $locations as $location ) {
			if ( ! isset( $location->type, $location->code ) ) {
				continue;
			}

			if ( 'continent' === $location->type ) {
				return null;
			}

			if ( 'country' === $location->type ) {
				$countries[] = (string) $location->code;
				continue;
			}

			if ( 'state' === $location->type ) {
				$parts       = explode( ':', (string) $location->code, 2 );
				$countries[] = (string) $parts[0];
			}
		}

		$countries = array_filter( $countries, static fn ( $country ) => '' !== $country );
		if ( empty( $countries ) ) {
			return null;
		}

		return array_values( $countries );
	}
}
