<?php
/**
 * Class CancelCourierBookingBulkAction
 *
 * @package DhlPolska\Admin\Shipments\BulkAction
 */

namespace DhlPolska\Admin\Shipments\BulkAction;

use DhlPolska\Exception\CourierCancelFailedException;
use DhlPolska\Exception\ExceptionMessageResolver;
use DhlPolskaVendor\Octolize\DhlPolska\API\WebAPI;
use DhlPolska\Integration\FlexibleShipping\FlexibleShippingIntegration;
use DhlPolska\Shipment\DhlShipment;
use DhlPolska\Shipment\ShipmentData;
use DhlPolskaVendor\Psr\Log\LoggerInterface;

/**
 * Bulk action handler for canceling courier booking.
 */
class CancelCourierBookingBulkAction implements BulkActionInterface {

	private LoggerInterface $logger;

	private WebAPI $webapi;

	public function __construct( LoggerInterface $logger, WebAPI $webapi ) {
		$this->logger = $logger;
		$this->webapi = $webapi;
	}

	public function get_action_name(): string {
		return 'cancel_courier_booking';
	}

	public function get_action_label(): string {
		return __( 'Anuluj zamówienie kuriera', 'dhl-polska' );
	}

	public function handle( array $shipment_ids ): array {
		if ( empty( $shipment_ids ) ) {
			return [
				'type'    => 'error',
				'message' => __( 'Nie wybrano żadnych przesyłek.', 'dhl-polska' ),
			];
		}

		$booking_ids = $this->get_booking_ids_from_shipments( $shipment_ids );
		if ( empty( $booking_ids ) ) {
			return [
				'type'    => 'error',
				'message' => __( 'Brak zamówień kuriera do anulowania.', 'dhl-polska' ),
			];
		}

		try {
			$this->get_webapi()->cancel_courier_booking( $booking_ids );
		} catch ( \Exception $exception ) {
			$this->logger->error( $exception->getMessage() );
			return [
				'type'    => 'error',
				'message' => ExceptionMessageResolver::resolve_throwable( $exception, CourierCancelFailedException::class ),
			];
		}

		$shipments_to_update = $this->get_shipments_for_booking_ids( $booking_ids );
		$updated_count       = $this->clear_booking_ids_on_shipments( $shipments_to_update );

		return [
			'type'    => 'success',
			'message' => sprintf(
				// Translators: number of shipments.
				__( 'Anulowano zamówienie kuriera DHL. Liczba przesyłek: %d.', 'dhl-polska' ),
				$updated_count
			),
		];
	}

	/**
	 * @param int[] $shipment_ids .
	 *
	 * @return string[]
	 */
	private function get_booking_ids_from_shipments( array $shipment_ids ): array {
		$booking_ids = [];

		foreach ( $shipment_ids as $shipment_post_id ) {
			$shipment = fs_get_shipment( $shipment_post_id );
			if ( ! $shipment ) { /** @phpstan-ignore-line */
				continue;
			}

			$booking_id = (string) $shipment->get_meta( ShipmentData::OPTION_COURIER_BOOKING_ID, '' );
			$booking_id = trim( $booking_id );
			if ( '' === $booking_id ) {
				continue;
			}

			$booking_ids[] = $booking_id;
		}

		return array_values( array_unique( $booking_ids ) );
	}

	/**
	 * @param string[] $booking_ids .
	 *
	 * @return int[]
	 */
	private function get_shipments_for_booking_ids( array $booking_ids ): array {
		$shipment_ids = [];

		foreach ( $booking_ids as $booking_id ) {
			$ids = get_posts(
				[
					'post_type'      => 'shipment',
					'post_status'    => 'any',
					'posts_per_page' => -1,
					'fields'         => 'ids',
					// phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query -- Required to find shipments by courier booking id.
					'meta_query'     => [
						[
							'key'   => '_integration',
							'value' => FlexibleShippingIntegration::INTEGRATION_ID,
						],
						[
							'key'   => ShipmentData::OPTION_COURIER_BOOKING_ID,
							'value' => $booking_id,
						],
					],
				]
			);

			if ( empty( $ids ) || ! is_array( $ids ) ) { /** @phpstan-ignore-line */
				continue;
			}

			$shipment_ids = array_merge( $shipment_ids, $ids );
		}

		$shipment_ids = array_map( 'absint', $shipment_ids );

		return array_values( array_unique( array_filter( $shipment_ids ) ) ); /** @phpstan-ignore-line */
	}

	/**
	 * @param int[] $shipment_ids .
	 *
	 * @return int
	 */
	private function clear_booking_ids_on_shipments( array $shipment_ids ): int {
		$updated = 0;

		foreach ( $shipment_ids as $shipment_id ) {
			$shipment = fs_get_shipment( $shipment_id );
			if ( $shipment instanceof DhlShipment ) {
				$shipment->clear_courier_booking_id();
				++$updated;
			}
		}

		return $updated;
	}

	protected function get_webapi(): WebAPI {
		return $this->webapi;
	}
}
