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

namespace DhlPolska\Shipment;

use DhlPolska\Download\BinaryDownloadResponse;
use DhlPolska\Exception\ExceptionMessageResolver;
use DhlPolska\Exception\ReturnLabelDownloadFailedException;
use DhlPolskaVendor\WPDesk\PluginBuilder\Plugin\Hookable;

/**
 * Dispatch return label downloads.
 */
class ReturnLabelDispatcher implements Hookable {
	public const ACTION = 'dhl_polska_get_return_label';

	private BinaryDownloadResponse $binary_download_response;

	public function __construct(
		?BinaryDownloadResponse $binary_download_response = null
	) {
		$this->binary_download_response = $binary_download_response ?? new BinaryDownloadResponse();
	}

	/**
	 * Hooks.
	 */
	public function hooks() {
		add_action( 'admin_post_' . self::ACTION, [ $this, 'dispatch_return_label' ] );
	}

	/**
	 * @return void
	 */
	public function dispatch_return_label(): void {
		if ( ! current_user_can( 'manage_woocommerce' ) ) {
			wp_die( esc_html__( 'Brak uprawnień.', 'dhl-polska' ) );
		}

		check_admin_referer( self::ACTION );

		$shipment_id = filter_input( INPUT_GET, 'shipment_id', FILTER_VALIDATE_INT );
		if ( ! $shipment_id ) {
			wp_die( esc_html__( 'Brak identyfikatora przesyłki.', 'dhl-polska' ) );
		}

		$shipment = fs_get_shipment( $shipment_id );
		if ( ! $shipment || ! method_exists( $shipment, 'get_return_label' ) ) { /** @phpstan-ignore-line */
			wp_die( esc_html__( 'Nie udało się pobrać etykiety zwrotnej.', 'dhl-polska' ) );
		}

		try {
			/** @var array{label_format: string, content: string, file_name: string} $label_data */
			$label_data = $shipment->get_return_label();
			$payload    = $this->prepare_download_payload( $label_data );
		} catch ( \Exception $exception ) {
			wp_die(
				esc_html( ExceptionMessageResolver::resolve_throwable( $exception, ReturnLabelDownloadFailedException::class ) ),
				esc_html__( 'Błąd etykiety zwrotnej', 'dhl-polska' )
			);
		}

		$this->binary_download_response->send( $payload['name'], $payload['mime_type'], $payload['content'] );
	}

	/**
	 * @param array<string, string> $label_data .
	 *
	 * @return string
	 */
	private function prepare_content_type( array $label_data ): string {
		$label_format = strtolower( (string) ( $label_data['label_format'] ?? '' ) );
		if ( '' === $label_format || 'html' === $label_format ) {
			return 'application/octet-stream';
		}

		if ( 1 !== preg_match( '/^[a-z0-9.+-]+$/', $label_format ) ) {
			return 'application/octet-stream';
		}

		return 'application/' . $label_format;
	}

	/**
	 * @param array<string, string> $label_data .
	 *
	 * @return array{name: string, mime_type: string, content: string}
	 */
	private function prepare_download_payload( array $label_data ): array {
		$content = (string) ( $label_data['content'] ?? '' );
		if ( '' === $content ) {
			throw new ReturnLabelDownloadFailedException();
		}

		$file_name = $this->binary_download_response->sanitize_file_name( (string) ( $label_data['file_name'] ?? '' ), 'return-label.bin' );

		return [
			'name'      => $file_name,
			'mime_type' => $this->prepare_content_type( $label_data ),
			'content'   => $content,
		];
	}
}
