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

namespace DhlPolska\Point;

use DhlPolska\Shipment\ShipmentData;
use DhlPolskaVendor\WPDesk\PluginBuilder\Plugin\Hookable;
use WC_Order;

/**
 * Save order point.
 */
class CheckoutSavePoint implements Hookable {
	public const ORDER_META_PARCELSHOP_ID         = '_' . ShipmentData::OPTION_PARCELSHOP_ID;
	public const ORDER_META_PARCELSHOP_SAP        = '_' . ShipmentData::OPTION_PARCELSHOP_SAP;
	public const ORDER_META_PARCELSHOP_NAME       = '_' . ShipmentData::OPTION_PARCELSHOP_NAME;
	public const ORDER_META_PARCELSHOP_ZIP        = '_' . ShipmentData::OPTION_PARCELSHOP_ZIP;
	public const ORDER_META_PARCELSHOP_STREET     = '_' . ShipmentData::OPTION_PARCELSHOP_STREET;
	public const ORDER_META_PARCELSHOP_CITY       = '_' . ShipmentData::OPTION_PARCELSHOP_CITY;
	public const ORDER_META_PARCELSHOP_STREET_NO  = '_' . ShipmentData::OPTION_PARCELSHOP_STREET_NO;
	public const ORDER_META_PARCELSHOP_HOUSE_NO   = '_' . ShipmentData::OPTION_PARCELSHOP_HOUSE_NO;
	public const ORDER_META_PARCELSHOP_POSTNUMMER = '_' . ShipmentData::OPTION_PARCELSHOP_POSTNUMMER;

	/**
	 * Hooks.
	 */
	public function hooks() {
		add_action( 'woocommerce_checkout_update_order_meta', [ $this, 'checkout_update_order_meta' ], 10, 2 );
		add_action( 'woocommerce_store_api_checkout_update_order_from_request', [ $this, 'checkout_update_order_meta_from_request' ] );
	}

	/**
	 * @param int                   $order_id .
	 * @param array<string, string> $data     .
	 *
	 * @return void
	 */
	public function checkout_update_order_meta( $order_id, $data ): void {
		$order = wc_get_order( $order_id );

		if ( $order instanceof WC_Order ) {
			$session_storage = new SessionStorage();
			$session_data    = $session_storage->get_parcelshop_data();
			$parcelshop_id   = $this->get_field_value( $data, CheckoutChoosePointField::FIELD_PARCELSHOP_ID, $session_data );
			if ( '' === $parcelshop_id ) {
				return;
			}

			foreach ( $this->get_order_meta_fields_map() as $field => $meta_key ) {
				$value = $this->get_field_value( $data, $field, $session_data );
				if ( '' !== $value ) {
					$order->update_meta_data( $meta_key, $value );
				}
			}

			$order->save();
		}
	}

	/**
	 * @param WC_Order $order .
	 *
	 * @return void
	 */
	public function checkout_update_order_meta_from_request( $order ): void {
		$session_storage = new SessionStorage();

		foreach ( $this->get_order_meta_fields_map() as $field => $meta_key ) {
			$value = $order->get_meta( $meta_key );
			if ( '' !== (string) $value ) {
				$session_storage->set_parcelshop_data_from_fields( [ $field => (string) $value ] );
			}
		}
	}

	/**
	 * @return array<string, string>
	 */
	private function get_order_meta_fields_map(): array {
		return [
			CheckoutChoosePointField::FIELD_PARCELSHOP_ID  => self::ORDER_META_PARCELSHOP_ID,
			CheckoutChoosePointField::FIELD_PARCELSHOP_SAP => self::ORDER_META_PARCELSHOP_SAP,
			CheckoutChoosePointField::FIELD_PARCELSHOP_NAME => self::ORDER_META_PARCELSHOP_NAME,
			CheckoutChoosePointField::FIELD_PARCELSHOP_ZIP => self::ORDER_META_PARCELSHOP_ZIP,
			CheckoutChoosePointField::FIELD_PARCELSHOP_STREET => self::ORDER_META_PARCELSHOP_STREET,
			CheckoutChoosePointField::FIELD_PARCELSHOP_CITY => self::ORDER_META_PARCELSHOP_CITY,
			CheckoutChoosePointField::FIELD_PARCELSHOP_STREET_NO => self::ORDER_META_PARCELSHOP_STREET_NO,
			CheckoutChoosePointField::FIELD_PARCELSHOP_HOUSE_NO => self::ORDER_META_PARCELSHOP_HOUSE_NO,
			CheckoutChoosePointField::FIELD_PARCELSHOP_POSTNUMMER => self::ORDER_META_PARCELSHOP_POSTNUMMER,
		];
	}

	/**
	 * @param array<string, string> $data         .
	 * @param string                $field        .
	 * @param array<string, string> $session_data .
	 *
	 * @return string
	 */
	private function get_field_value( array $data, string $field, array $session_data ): string {
		if ( isset( $data[ $field ] ) ) {
			return $this->sanitize_field_value( $data[ $field ] );
		}

		$posted_value = $this->filter_input( INPUT_POST, $field );
		if ( null !== $posted_value && '' !== (string) $posted_value ) {
			return $this->sanitize_field_value( $posted_value );
		}

		$session_key = str_replace( 'parcelshop_', '', $field );

		return $this->sanitize_field_value( $session_data[ $session_key ] ?? '' );
	}

	/**
	 * @param mixed $value .
	 */
	private function sanitize_field_value( $value ): string {
		if ( ! is_scalar( $value ) ) {
			return '';
		}

		return (string) wc_clean( $value );
	}

	/**
	 * @param int    $type     .
	 * @param string $var_name .
	 *
	 * @return mixed
	 * @codeCoverageIgnore
	 */
	protected function filter_input( int $type, string $var_name ) {
		return filter_input( $type, $var_name );
	}
}
