<?php
/**
 * Class PnpSubmenu
 *
 * @package DhlPolska\Admin\Menu
 */

namespace DhlPolska\Admin\Menu;

use DhlPolska\Admin\DhlPolskaMenu;
use DhlPolska\API\WebAPI;
use DhlPolskaVendor\WPDesk\PluginBuilder\Plugin\Hookable;

/**
 * Register DHL Polska PNP submenu.
 */
class PnpSubmenu implements Hookable {
	public const PAGE_SLUG = 'dhl-polska-pnp';
	public const ACTION    = 'dhl_polska_generate_pnp';

	private WebAPI $webapi;

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

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

	/**
	 * @return void
	 */
	public function register_submenu() {
		add_submenu_page(
			DhlPolskaMenu::MENU_SLUG,
			__( 'Potwierdzenie nadania', 'dhl-polska' ),
			__( 'Potwierdzenie nadania', 'dhl-polska' ),
			'manage_woocommerce',
			self::PAGE_SLUG,
			[ $this, 'render_page' ],
			2
		);
	}

	/**
	 * @return void
	 */
	public function render_page() {
		$menu_slug     = DhlPolskaMenu::MENU_SLUG;
		$action        = self::ACTION;
		$pnp_types     = $this->get_pnp_types();
		$selected_date = $this->get_pnp_date_from_request();
		$selected_type = $this->get_pnp_type_from_request( $pnp_types );
		$notice        = $this->get_pnp_notice();

		include __DIR__ . '/../views/html-pnp-page.php';
	}

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

		check_admin_referer( self::ACTION );

		$date  = isset( $_POST['shipment_date'] ) ? sanitize_text_field( wp_unslash( $_POST['shipment_date'] ) ) : '';
		$type  = isset( $_POST['shipment_type'] ) ? sanitize_text_field( wp_unslash( $_POST['shipment_type'] ) ) : '';
		$types = $this->get_pnp_types();

		if ( '' === $date || ! $this->is_valid_date( $date ) ) {
			$this->redirect_with_notice( 'error', __( 'Podaj poprawną datę nadania.', 'dhl-polska' ) );
		}

		if ( '' === $type || ! isset( $types[ $type ] ) ) {
			$this->redirect_with_notice( 'error', __( 'Wybierz poprawny typ przesyłki.', 'dhl-polska' ) );
		}

		try {
			$pnp_data = $this->webapi->get_pnp( $date, $type );
			$this->download_pnp_file( $pnp_data, $date, $type );
		} catch ( \Exception $exception ) {
			$this->redirect_with_notice( 'error', $exception->getMessage() );
		}
	}

	/**
	 * @return array<string, string>
	 */
	private function get_pnp_types(): array {
		return [
			'ALL'                 => __( 'ALL - wszystkie rodzaje przesyłek', 'dhl-polska' ),
			'EX'                  => __( 'EX - krajowe ekspresowe do 31,5kg', 'dhl-polska' ),
			'DR'                  => __( 'DR - krajowe drobnicowe', 'dhl-polska' ),
			'2EUROPE'             => __( '2EUROPE - przesyłki eksportowe', 'dhl-polska' ),
			'PR'                  => __( 'PR - przesyłki Premium', 'dhl-polska' ),
		];
	}

	/**
	 * @param string $date .
	 *
	 * @return bool
	 */
	private function is_valid_date( string $date ): bool {
		$date_object = \DateTime::createFromFormat( 'Y-m-d', $date );
		if ( ! $date_object ) {
			return false;
		}

		return $date_object->format( 'Y-m-d' ) === $date;
	}

	/**
	 * @return string
	 */
	private function get_pnp_date_from_request(): string {
		// phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Used for read-only defaults.
		$date = isset( $_GET['shipment_date'] ) ? sanitize_text_field( wp_unslash( $_GET['shipment_date'] ) ) : '';
		if ( '' !== $date ) {
			return $date;
		}

		return (string) current_time( 'Y-m-d' );
	}

	/**
	 * @param array<string, string> $types .
	 *
	 * @return string
	 */
	private function get_pnp_type_from_request( array $types ): string {
		// phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Used for read-only defaults.
		$type = isset( $_GET['shipment_type'] ) ? sanitize_text_field( wp_unslash( $_GET['shipment_type'] ) ) : '';
		if ( '' !== $type && isset( $types[ $type ] ) ) {
			return $type;
		}

		return array_key_first( $types );
	}

	/**
	 * @return array{type: string, message: string}|null
	 */
	private function get_pnp_notice(): ?array {
		$notice_type = isset( $_GET['pnp_notice'] ) ? sanitize_key( wp_unslash( $_GET['pnp_notice'] ) ) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Recommended, WordPress.Security.NonceVerification.NoNonceVerification -- Uses redirect query args for notices.
		$message     = isset( $_GET['pnp_message'] ) ? sanitize_text_field( rawurldecode( wp_unslash( $_GET['pnp_message'] ) ) ) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Recommended, WordPress.Security.NonceVerification.NoNonceVerification, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- Sanitized with sanitize_text_field after decoding.

		if ( '' === $notice_type || '' === $message ) {
			return null;
		}

		return [
			'type'    => $notice_type,
			'message' => $message,
		];
	}

	/**
	 * @param string $type .
	 * @param string $message .
	 *
	 * @return void
	 */
	private function redirect_with_notice( string $type, string $message ): void {
		$url = add_query_arg(
			[
				'page'        => self::PAGE_SLUG,
				'pnp_notice'  => $type,
				'pnp_message' => rawurlencode( $message ),
			],
			admin_url( 'admin.php' )
		);

		wp_safe_redirect( $url );
		exit;
	}

	/**
	 * @param array{file_name: string, file_data: string, mime_type: string} $pnp_data .
	 * @param string $date .
	 * @param string $type .
	 *
	 * @return array{name: string, mime_type: string, content: string}
	 */
	private function prepare_pnp_download( array $pnp_data, string $date, string $type ): array {
		// phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_decode
		$content = base64_decode( $pnp_data['file_data'], true );
		if ( false === $content || '' === $content ) {
			throw new \RuntimeException( __( 'Nie udało się pobrać potwierdzenia nadania.', 'dhl-polska' ) );
		}

		$file_name = sanitize_file_name( $pnp_data['file_name'] );
		if ( '' === $file_name ) {
			$file_name = sprintf( 'pnp-%s-%s.pdf', $date, strtolower( $type ) );
		}

		if ( ! preg_match( '/\\.pdf$/i', $file_name ) ) {
			$file_name .= '.pdf';
		}

		$mime_type = $pnp_data['mime_type'] ?: 'application/pdf';

		return [
			'name'      => $file_name,
			'mime_type' => $mime_type,
			'content'   => $content,
		];
	}

	/**
	 * @param array{file_name: string, file_data: string, mime_type: string} $pnp_data .
	 * @param string $date .
	 * @param string $type .
	 *
	 * @return void
	 */
	private function download_pnp_file( array $pnp_data, string $date, string $type ): void {
		$payload = $this->prepare_pnp_download( $pnp_data, $date, $type );

		while ( ob_get_level() ) {
			ob_end_clean();
		}

		nocache_headers();
		header( 'Content-Type: ' . $payload['mime_type'] );
		header( 'Content-Disposition: attachment; filename="' . $payload['name'] . '"' );
		header( 'Content-Length: ' . (string) strlen( $payload['content'] ) );

		echo $payload['content']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Binary download.
		exit;
	}
}
