<?php
/**
 * Packing slip print view.
 *
 * @package WPDudeProducts
 */

declare(strict_types=1);

namespace WPDude\Products\Admin;

use WPDude\Products\Orders\Order_Repository;
use WPDude\Products\Orders\Statuses;
use WPDude\Products\Products\Product_Meta;
use WPDude\Products\Products\Stock_Service;

/**
 * Printable packing slip for fulfilment (HTML + browser print).
 */
final class Packing_Slip_Page {

	public const PAGE_SLUG = 'dude-commerce-packing-slip';

	/**
	 * Register hooks.
	 */
	public function register(): void {
		add_action( 'admin_menu', array( $this, 'register_page' ) );
		// Render before admin-header.php so other plugins' admin notices never print.
		add_action( 'admin_init', array( $this, 'maybe_render_early' ), 1 );
		add_action( 'wpdude_dc_picking_order_actions', array( self::class, 'render_picking_button' ), 10, 1 );
		add_action( 'wpdude_dc_order_fulfilment_print_actions', array( self::class, 'render_order_detail_button' ), 10, 1 );
	}

	/**
	 * Take over the request before WP admin chrome / notices load.
	 */
	public function maybe_render_early(): void {
		// phpcs:ignore WordPress.Security.NonceVerification.Recommended -- screen routing only.
		$page = isset( $_GET['page'] ) ? sanitize_key( wp_unslash( (string) $_GET['page'] ) ) : '';
		if ( self::PAGE_SLUG !== $page ) {
			return;
		}
		self::render();
	}

	/**
	 * Hidden admin page (opened from order detail / picking).
	 */
	public function register_page(): void {
		add_submenu_page(
			null,
			__( 'Packing slip', 'dude-commerce' ),
			__( 'Packing slip', 'dude-commerce' ),
			'manage_options',
			self::PAGE_SLUG,
			array( self::class, 'render' )
		);
	}

	/**
	 * Packing slip URL for an order UUID.
	 */
	public static function url( string $uuid, bool $autoprint = false ): string {
		$args = array(
			'page' => self::PAGE_SLUG,
			'uuid' => $uuid,
		);
		if ( $autoprint ) {
			$args['autoprint'] = '1';
		}
		return add_query_arg( $args, admin_url( 'admin.php' ) );
	}

	/**
	 * Button on picking card.
	 *
	 * @param array<string, mixed> $order Order.
	 */
	public static function render_picking_button( array $order ): void {
		self::render_button( $order, 'button wpdude-dc-picking-card__slip' );
	}

	/**
	 * Button on order detail Fulfilment section.
	 *
	 * @param array<string, mixed> $order Order.
	 */
	public static function render_order_detail_button( array $order ): void {
		self::render_button( $order, 'button button-hero wpdude-dc-order-fulfilil__print' );
	}

	/**
	 * @param array<string, mixed> $order      Order.
	 * @param string               $css_class Button classes.
	 */
	private static function render_button( array $order, string $css_class ): void {
		if ( ! current_user_can( 'manage_options' ) ) {
			return;
		}
		$uuid = (string) ( $order['uuid'] ?? '' );
		if ( '' === $uuid ) {
			return;
		}
		?>
		<a class="<?php echo esc_attr( $css_class ); ?>" href="<?php echo esc_url( self::url( $uuid, true ) ); ?>" target="_blank" rel="noopener noreferrer">
			<?php echo esc_html__( 'Print packing slip', 'dude-commerce' ); ?>
		</a>
		<?php
	}

	/**
	 * Render printable HTML and exit.
	 */
	public static function render(): void {
		if ( ! current_user_can( 'manage_options' ) ) {
			wp_die( esc_html__( 'You do not have permission to access this page.', 'dude-commerce' ) );
		}

		// phpcs:ignore WordPress.Security.NonceVerification.Recommended -- read-only print view; manage_options checked above.
		$uuid = isset( $_GET['uuid'] ) ? sanitize_text_field( wp_unslash( (string) $_GET['uuid'] ) ) : '';
		if ( '' === $uuid ) {
			wp_die( esc_html__( 'Missing order.', 'dude-commerce' ) );
		}

		$order = ( new Order_Repository() )->find_by_uuid( $uuid );
		if ( ! $order ) {
			wp_die( esc_html__( 'Order not found.', 'dude-commerce' ) );
		}

		$shop_name = wp_specialchars_decode( get_bloginfo( 'name' ), ENT_QUOTES );
		$line      = is_array( $order['line_item'] ?? null ) ? $order['line_item'] : array();
		$product   = (string) ( $line['name'] ?? '' );
		if ( '' === $product ) {
			$product_id = (int) ( $order['product_id'] ?? 0 );
			$product    = $product_id > 0 ? (string) get_the_title( $product_id ) : __( 'Product', 'dude-commerce' );
		}

		$options = '';
		if ( ! empty( $line['options'] ) && is_array( $line['options'] ) ) {
			$parts = array();
			foreach ( $line['options'] as $opt_name => $opt_value ) {
				$parts[] = sanitize_text_field( (string) $opt_name ) . ': ' . sanitize_text_field( (string) $opt_value );
			}
			$options = implode( ', ', $parts );
		} elseif ( ! empty( $order['combination_key'] ) ) {
			$options = (string) $order['combination_key'];
		}

		$sku     = self::order_sku( $order );
		$address = self::format_address( $order );
		$status  = Statuses::label( (string) ( $order['status'] ?? '' ) );
		$qty     = (int) ( $order['qty'] ?? 1 );

		wp_register_style(
			'wpdude-dc-packing-slip',
			WPDUDE_DC_URL . 'assets/css/packing-slip.css',
			array(),
			WPDUDE_DC_VERSION
		);
		wp_register_script(
			'wpdude-dc-print-autoprint',
			WPDUDE_DC_URL . 'assets/js/print-autoprint.js',
			array(),
			WPDUDE_DC_VERSION,
			true
		);
		wp_enqueue_style( 'wpdude-dc-packing-slip' );
		wp_enqueue_script( 'wpdude-dc-print-autoprint' );
		?>
<!DOCTYPE html>
<html <?php language_attributes(); ?>>
<head>
	<meta charset="<?php bloginfo( 'charset' ); ?>" />
	<title><?php echo esc_html( sprintf( /* translators: %s: order uuid */ __( 'Packing slip — %s', 'dude-commerce' ), (string) $order['uuid'] ) ); ?></title>
	<?php wp_print_styles( 'wpdude-dc-packing-slip' ); ?>
</head>
<body>
	<div class="actions">
		<button type="button" id="wpdude-dc-print"><?php echo esc_html__( 'Print', 'dude-commerce' ); ?></button>
		<a href="<?php echo esc_url( Menu::orders_url() ); ?>"><?php echo esc_html__( 'Back to orders', 'dude-commerce' ); ?></a>
	</div>

	<h1><?php echo esc_html( $shop_name ); ?></h1>
	<p class="meta"><?php echo esc_html__( 'Packing slip', 'dude-commerce' ); ?></p>

	<table>
		<tbody>
			<tr>
				<th><?php echo esc_html__( 'Order', 'dude-commerce' ); ?></th>
				<td><code><?php echo esc_html( (string) $order['uuid'] ); ?></code></td>
			</tr>
			<tr>
				<th><?php echo esc_html__( 'Status', 'dude-commerce' ); ?></th>
				<td><?php echo esc_html( $status ); ?></td>
			</tr>
			<?php if ( '' !== $sku ) : ?>
			<tr>
				<th><?php echo esc_html__( 'SKU', 'dude-commerce' ); ?></th>
				<td><code><?php echo esc_html( $sku ); ?></code></td>
			</tr>
			<?php endif; ?>
			<tr>
				<th><?php echo esc_html__( 'Ship to', 'dude-commerce' ); ?></th>
				<td><?php echo wp_kses_post( nl2br( esc_html( '' !== $address ? $address : '—' ) ) ); ?></td>
			</tr>
			<tr>
				<th><?php echo esc_html__( 'Product', 'dude-commerce' ); ?></th>
				<td><?php echo esc_html( $product ); ?></td>
			</tr>
			<?php if ( '' !== $options ) : ?>
			<tr>
				<th><?php echo esc_html__( 'Options', 'dude-commerce' ); ?></th>
				<td><?php echo esc_html( $options ); ?></td>
			</tr>
			<?php endif; ?>
			<tr>
				<th><?php echo esc_html__( 'Quantity', 'dude-commerce' ); ?></th>
				<td><?php echo esc_html( (string) $qty ); ?></td>
			</tr>
		</tbody>
	</table>

	<?php wp_print_scripts( 'wpdude-dc-print-autoprint' ); ?>
</body>
</html>
		<?php
		exit;
	}

	/**
	 * @param array<string, mixed> $order Order.
	 */
	private static function order_sku( array $order ): string {
		$line = is_array( $order['line_item'] ?? null ) ? $order['line_item'] : array();
		$sku  = isset( $line['sku'] ) ? Product_Meta::normalize_sku( (string) $line['sku'] ) : '';
		if ( '' !== $sku ) {
			return $sku;
		}
		return Stock_Service::line_sku(
			(int) ( $order['product_id'] ?? 0 ),
			(string) ( $order['combination_key'] ?? '' )
		);
	}

	/**
	 * @param array<string, mixed> $order Order.
	 */
	private static function format_address( array $order ): string {
		$shipping = is_array( $order['shipping_address'] ?? null ) ? $order['shipping_address'] : array();
		$lines    = array();
		$name     = trim( (string) ( $shipping['name'] ?? $order['customer_name'] ?? '' ) );
		if ( '' !== $name ) {
			$lines[] = $name;
		}

		$address = is_array( $shipping['address'] ?? null ) ? $shipping['address'] : $shipping;
		foreach ( array( 'line1', 'line2', 'city', 'state', 'postal_code', 'country' ) as $key ) {
			$val = trim( (string) ( $address[ $key ] ?? '' ) );
			if ( '' !== $val ) {
				$lines[] = $val;
			}
		}

		$phone = trim( (string) ( $shipping['phone'] ?? '' ) );
		if ( '' !== $phone ) {
			$lines[] = $phone;
		}

		return implode( "\n", $lines );
	}
}
