<?php
/**
 * Class CheckoutShipmentMetaUpdater
 *
 * @package DhlPolska\Point
 */

namespace DhlPolska\Point;

use DhlPolska\Integration\FlexibleShipping\FlexibleShippingIntegration;
use DhlPolska\Shipment\DhlServices;
use DhlPolska\Shipment\ShipmentData;
use DhlPolskaVendor\WPDesk\PluginBuilder\Plugin\Hookable;
use WPDesk_Flexible_Shipping_Shipment;

/**
 * Updates shipment meta with parcelshop data from checkout.
 */
class CheckoutShipmentMetaUpdater implements Hookable {

	/**
	 * Hooks.
	 */
	public function hooks() {
		add_action( 'flexible_shipping_checkout_shipment_created', [ $this, 'update_shipment_meta' ] );
	}

	/**
	 * @param WPDesk_Flexible_Shipping_Shipment $shipment .
	 *
	 * @return void
	 */
	public function update_shipment_meta( $shipment ): void {
		if ( ! $shipment instanceof WPDesk_Flexible_Shipping_Shipment ) { /** @phpstan-ignore-line */
			return;
		}

		$fs_method = $shipment->get_meta( '_fs_method', [] ); /** @phpstan-ignore-line */
		if ( ! is_array( $fs_method ) ) {
			return;
		}

		$integration = (string) ( $fs_method['method_integration'] ?? '' );
		if ( FlexibleShippingIntegration::INTEGRATION_ID !== $integration ) {
			return;
		}

		$service = (string) ( $fs_method[ ShipmentData::OPTION_SERVICE ] ?? ( $fs_method['dhl_polska_service'] ?? '' ) );
		if ( DhlServices::SERVICE_POINT !== $service ) {
			return;
		}

		$should_save = false;
		if ( $this->maybe_set_point_type_on_shipment( $shipment, $fs_method ) ) {
			$should_save = true;
		}

		$parcelshop_data = $this->get_parcelshop_data( $shipment );
		if ( '' === $parcelshop_data['id'] ) {
			if ( $should_save ) {
				$shipment->save();
			}

			return;
		}

		foreach ( $this->get_fields_map() as $field => $key ) {
			$value = $parcelshop_data[ $key ];
			if ( '' !== $value ) {
				$shipment->set_meta( $field, $value );
				$should_save = true;
			}
		}

		if ( $should_save ) {
			$shipment->save();
		}
	}

	/**
	 * @param WPDesk_Flexible_Shipping_Shipment $shipment .
	 *
	 * @return array<string, string>
	 */
	private function get_parcelshop_data( WPDesk_Flexible_Shipping_Shipment $shipment ): array {
		$session_storage = new SessionStorage();
		$parcelshop_data = $session_storage->get_parcelshop_data();

		if ( '' !== $parcelshop_data['id'] ) {
			return $parcelshop_data;
		}

		$order = wc_get_order( $shipment->get_order_id() );
		if ( ! $order ) {
			return $parcelshop_data;
		}

		foreach ( $this->get_fields_map() as $field => $key ) {
			$order_meta_key          = $this->get_order_meta_key( $field );
			$parcelshop_data[ $key ] = (string) $order->get_meta( $order_meta_key );
		}

		$session_storage->set_parcelshop_data_from_fields( $this->get_fields_for_session( $parcelshop_data ) );

		return $parcelshop_data;
	}

	/**
	 * @return array<string, string>
	 */
	private function get_fields_map(): array {
		return [
			ShipmentData::OPTION_PARCELSHOP_ID         => 'id',
			ShipmentData::OPTION_PARCELSHOP_SAP        => 'sap',
			ShipmentData::OPTION_PARCELSHOP_NAME       => 'name',
			ShipmentData::OPTION_PARCELSHOP_ZIP        => 'zip',
			ShipmentData::OPTION_PARCELSHOP_STREET     => 'street',
			ShipmentData::OPTION_PARCELSHOP_CITY       => 'city',
			ShipmentData::OPTION_PARCELSHOP_STREET_NO  => 'streetNo',
			ShipmentData::OPTION_PARCELSHOP_HOUSE_NO   => 'houseNo',
			ShipmentData::OPTION_PARCELSHOP_POSTNUMMER => 'postnummer',
		];
	}

	/**
	 * @param string $field .
	 *
	 * @return string
	 */
	private function get_order_meta_key( string $field ): string {
		$map = [
			ShipmentData::OPTION_PARCELSHOP_ID         => CheckoutSavePoint::ORDER_META_PARCELSHOP_ID,
			ShipmentData::OPTION_PARCELSHOP_SAP        => CheckoutSavePoint::ORDER_META_PARCELSHOP_SAP,
			ShipmentData::OPTION_PARCELSHOP_NAME       => CheckoutSavePoint::ORDER_META_PARCELSHOP_NAME,
			ShipmentData::OPTION_PARCELSHOP_ZIP        => CheckoutSavePoint::ORDER_META_PARCELSHOP_ZIP,
			ShipmentData::OPTION_PARCELSHOP_STREET     => CheckoutSavePoint::ORDER_META_PARCELSHOP_STREET,
			ShipmentData::OPTION_PARCELSHOP_CITY       => CheckoutSavePoint::ORDER_META_PARCELSHOP_CITY,
			ShipmentData::OPTION_PARCELSHOP_STREET_NO  => CheckoutSavePoint::ORDER_META_PARCELSHOP_STREET_NO,
			ShipmentData::OPTION_PARCELSHOP_HOUSE_NO   => CheckoutSavePoint::ORDER_META_PARCELSHOP_HOUSE_NO,
			ShipmentData::OPTION_PARCELSHOP_POSTNUMMER => CheckoutSavePoint::ORDER_META_PARCELSHOP_POSTNUMMER,
		];

		return $map[ $field ] ?? '';
	}

	/**
	 * @param array<string, string> $parcelshop_data .
	 *
	 * @return array<string, string>
	 */
	private function get_fields_for_session( array $parcelshop_data ): array {
		$session_data = [];

		foreach ( $this->get_fields_map() as $field => $key ) {
			$session_data[ $field ] = $parcelshop_data[ $key ];
		}

		return $session_data;
	}

	/**
	 * @param WPDesk_Flexible_Shipping_Shipment $shipment .
	 * @param array<string, mixed>              $fs_method .
	 *
	 * @return bool
	 */
	private function maybe_set_point_type_on_shipment( WPDesk_Flexible_Shipping_Shipment $shipment, array $fs_method ): bool {
		$order = wc_get_order( $shipment->get_order_id() );
		if ( ! $order ) {
			return false;
		}

		$shipping_country = strtoupper( (string) $order->get_shipping_country() );
		if ( '' === $shipping_country ) {
			$shipping_country = strtoupper( (string) $order->get_billing_country() );
		}

		if ( 'PL' === $shipping_country ) {
			return false;
		}

		$point_type = $fs_method[ ShipmentData::OPTION_POINT_TYPE ] ?? ( $fs_method['dhl_polska_point_type'] ?? ShipmentData::POINT_TYPE_PARCELSHOP );
		$point_type = ShipmentData::normalize_point_type( (string) $point_type );

		$shipment->set_meta( ShipmentData::OPTION_POINT_TYPE, $point_type );

		return true;
	}
}
