<?php
/**
 * Class ShipmentData
 *
 * @package DhlPolska\Shipment
 */

namespace DhlPolska\Shipment;

use DhlPolska\SanitizeTrait;
use DhlPolska\WooCommerceSettings\WooCommerceDHLPolskaSettings;
use DhlPolska\Shipment\DhlServices;
use DhlPolska\Shipment\WorkingDayDateCalculator;
use WC_Order;
use WPDesk_Flexible_Shipping_Shipment;

/**
 * Shipment data.
 */
class ShipmentData {
	use SanitizeTrait;

	public const OPTION_SERVICE               = 'service';
	public const OPTION_TEMPLATE              = 'template_id';
	public const OPTION_COD                   = 'cod';
	public const OPTION_COD_AMOUNT            = 'cod_amount';
	public const OPTION_INSURANCE             = 'insurance';
	public const OPTION_INSURANCE_AMOUNT      = 'insurance_amount';
	public const OPTION_REFERENCES            = 'references';
	public const OPTION_NOTES                 = 'notes';
	public const OPTION_PACKAGES              = 'packages';
	public const OPTION_PARCELSHOP_ID         = 'parcelshop_id';
	public const OPTION_PARCELSHOP_SAP        = 'parcelshop_sap';
	public const OPTION_PARCELSHOP_NAME       = 'parcelshop_name';
	public const OPTION_PARCELSHOP_ZIP        = 'parcelshop_zip';
	public const OPTION_PARCELSHOP_STREET     = 'parcelshop_street';
	public const OPTION_PARCELSHOP_CITY       = 'parcelshop_city';
	public const OPTION_PARCELSHOP_STREET_NO  = 'parcelshop_streetNo';
	public const OPTION_PARCELSHOP_HOUSE_NO   = 'parcelshop_houseNo';
	public const OPTION_PARCELSHOP_POSTNUMMER = 'parcelshop_postnummer';
	public const OPTION_POINT_TYPE            = 'point_type';
	public const POINT_TYPE_PARCELSHOP        = 'parcelShop';
	public const POINT_TYPE_PACKSTATION       = 'packStation';
	public const OPTION_SHIPMENT_ID           = 'shipment_id';
	public const OPTION_PARCEL_NUMBER         = 'parcel_number';
	public const OPTION_COURIER_BOOKING_ID    = 'courier_booking_id';
	public const OPTION_SHIPMENT_DATE         = 'shipment_date';
	public const OPTION_RETURN_LABEL_CONTENT  = 'return_label_content';
	public const OPTION_RETURN_LABEL_FORMAT   = 'return_label_format';
	public const OPTION_RETURN_LABEL_TYPE     = 'return_label_type';
	public const OPTION_RETURN_LABEL_NUMBER   = 'return_label_number';
	public const FIELD_ORDER_WEIGHT           = 'order_weight';

	/**
	 * @var WPDesk_Flexible_Shipping_Shipment
	 */
	private $shipment;

	/**
	 * @var WC_Order
	 */
	private $order;

	/**
	 * @var WooCommerceDHLPolskaSettings
	 */
	private $shipping_settings;

	/**
	 * ShipmentData constructor.
	 *
	 * @param WPDesk_Flexible_Shipping_Shipment $shipment .
	 * @param WC_Order                          $order .
	 * @param WooCommerceDHLPolskaSettings      $shipping_settings .
	 */
	public function __construct( $shipment, $order, $shipping_settings ) {
		$this->shipment          = $shipment;
		$this->order             = $order;
		$this->shipping_settings = $shipping_settings;
	}

	/**
	 * @return string
	 */
	public function get_service(): string {
		return (string) $this->shipment->get_meta( self::OPTION_SERVICE, DhlServices::SERVICE_AH ); // AH = DHL Parcel Polska
	}

	/**
	 * @return bool
	 */
	public function get_cod_status(): bool {
		return $this->get_bool_value( $this->shipment->get_meta( self::OPTION_COD, 'no' ) );
	}

	/**
	 * @return float
	 */
	public function get_cod_amount(): float {
		$amount = $this->shipment->get_meta( self::OPTION_COD_AMOUNT );
		if ( empty( $amount ) ) {
			return (float) $this->order->get_total();
		}

		return $this->get_float_value( (string) $amount );
	}

	/**
	 * @return bool
	 */
	public function get_insurance_status(): bool {
		return $this->get_bool_value( $this->shipment->get_meta( self::OPTION_INSURANCE, 'no' ) );
	}

	/**
	 * @return float
	 */
	public function get_insurance_amount(): float {
		$amount = $this->shipment->get_meta( self::OPTION_INSURANCE_AMOUNT );
		if ( empty( $amount ) ) {
			return (float) $this->order->get_total();
		}

		return $this->get_float_value( (string) $amount );
	}

	/**
	 * @return string
	 */
	public function get_references(): string {
		return (string) $this->shipment->get_meta( self::OPTION_REFERENCES, $this->get_default_references() );
	}

	/**
	 * @return string
	 */
	public function get_notes(): string {
		return (string) $this->shipment->get_meta( self::OPTION_NOTES, '' );
	}

	/**
	 * @return string
	 */
	public function get_content(): string {
		return (string) apply_filters( 'dhl_polska_shipment_content', __( 'Przesyłka', 'dhl-polska' ), $this->shipment );
	}

	/**
	 * @return string
	 */
	public function get_service_point(): string {
		$service_point = (string) $this->shipment->get_meta( self::OPTION_PARCELSHOP_SAP, '' );
		if ( '' !== $service_point ) {
			return $service_point;
		}

		return (string) $this->shipment->get_meta( self::OPTION_PARCELSHOP_ID, '' );
	}

	/**
	 * @return array
	 */
	public function get_parcelshop_data(): array {
		return [
			'id'         => (string) $this->shipment->get_meta( self::OPTION_PARCELSHOP_ID, '' ),
			'sap'        => (string) $this->shipment->get_meta( self::OPTION_PARCELSHOP_SAP, '' ),
			'name'       => (string) $this->shipment->get_meta( self::OPTION_PARCELSHOP_NAME, '' ),
			'zip'        => (string) $this->shipment->get_meta( self::OPTION_PARCELSHOP_ZIP, '' ),
			'street'     => (string) $this->shipment->get_meta( self::OPTION_PARCELSHOP_STREET, '' ),
			'city'       => (string) $this->shipment->get_meta( self::OPTION_PARCELSHOP_CITY, '' ),
			'streetNo'   => (string) $this->shipment->get_meta( self::OPTION_PARCELSHOP_STREET_NO, '' ),
			'houseNo'    => (string) $this->shipment->get_meta( self::OPTION_PARCELSHOP_HOUSE_NO, '' ),
			'postnummer' => (string) $this->shipment->get_meta( self::OPTION_PARCELSHOP_POSTNUMMER, '' ),
		];
	}

	public function get_point_type(): string {
		$point_type = (string) $this->shipment->get_meta( self::OPTION_POINT_TYPE, self::POINT_TYPE_PARCELSHOP );

		return self::normalize_point_type( $point_type );
	}

	/**
	 * @param string $point_type .
	 *
	 * @return string
	 */
	public static function normalize_point_type( string $point_type ): string {
		if ( 'parcelshop' === $point_type ) {
			return self::POINT_TYPE_PARCELSHOP;
		}

		if ( 'packstation' === $point_type ) {
			return self::POINT_TYPE_PACKSTATION;
		}

		return $point_type;
	}

	/**
	 * @return string
	 */
	public function get_shipment_id(): string {
		return (string) $this->shipment->get_meta( self::OPTION_SHIPMENT_ID, '' );
	}

	/**
	 * @return string
	 */
	public function get_tracking_number(): string {
		return (string) $this->shipment->get_meta( self::OPTION_PARCEL_NUMBER, '' );
	}

	/**
	 * @return string
	 */
	public function get_courier_booking_id(): string {
		return trim( (string) $this->shipment->get_meta( self::OPTION_COURIER_BOOKING_ID, '' ) );
	}

	public function get_shipment_date(): string {
		return (string) $this->shipment->get_meta( self::OPTION_SHIPMENT_DATE, '' );
	}

	public function get_shipping_country(): string {
		$shipping_country = (string) $this->order->get_shipping_country();
		if ( '' !== $shipping_country ) {
			return $shipping_country;
		}

		return (string) $this->order->get_billing_country();
	}

	public function get_shipment_date_for_metabox(): string {
		$shipment_date = trim( $this->get_shipment_date() );
		if ( '' !== $shipment_date ) {
			return $shipment_date;
		}

		return $this->get_default_shipment_date();
	}

	public function get_default_shipment_date(): string {
		$calculator = new WorkingDayDateCalculator();
		$cutoff     = $this->shipping_settings->get_shipment_date_cutoff_time();
		$date       = $calculator->get_date_after_cutoff( $cutoff );

		if ( null !== $date ) {
			return $date;
		}

		if ( $this->get_service() === DhlServices::SERVICE_POINT ) {
			return date( 'Y-m-d' );
		}

		return date( 'Y-m-d', time() + 60 * 60 * 24 );
	}

	/**
	 * @return array
	 */
	public function get_packages(): array {
		// @phpstan-ignore argument.type
		$order_packages = $this->shipment->get_meta( self::OPTION_PACKAGES, [] );

		if ( empty( $order_packages ) || ! is_array( $order_packages ) ) {
			return [
				[
					'weight' => $this->shipping_settings->get_default_weight(),
					'type'   => 'PACKAGE',
				],
			];
		}

		return $order_packages;
	}

	/**
	 * @return float
	 */
	public function get_weight(): float {
		$weight = 0.0;

		foreach ( $this->get_packages() as $package ) {
			$weight += (float) ( $package['weight'] ?? 0.0 );
		}

		return $weight;
	}

	/**
	 * @return string
	 */
	private function get_default_references(): string {
		$default_references = sprintf(
			// Translators: order number.
			__( 'Zamówienie #%d', 'dhl-polska' ),
			$this->order->get_order_number()
		);

		return (string) apply_filters( 'dhl_polska_shipment_default_references', $default_references, $this->shipment );
	}
}
