<?php
/**
 * Shipment Handler
 *
 * Orchestrates shipment confirmation logic for Amazon orders.
 *
 * @package    MOMCS_Sync
 * @subpackage MOMCS_Sync/includes/common/handlers
 * @author     miniOrange
 */

declare(strict_types=1);

namespace MOMCS_Sync\Includes\Common\Handlers;

use MOMCS_Sync\Includes\Common\Services\Amazon\Shipment_Service;
use MOMCS_Sync\Includes\Common\Utils\Logger;

if ( ! defined( 'ABSPATH' ) ) {
	exit;
}

/**
 * Class for handling shipment confirmation operations.
 */
class Shipment_Handler {

	/**
	 * Shipment Service instance.
	 *
	 * @var Shipment_Service
	 */
	private $shipment_service;

	/**
	 * Logger instance.
	 *
	 * @var Logger
	 */
	private $logger;

	/**
	 * Constructor.
	 */
	public function __construct() {
		$this->shipment_service = new Shipment_Service();
		$this->logger           = new Logger( 'shipment-handler' );
	}

	/**
	 * Confirm shipment for WooCommerce order.
	 *
	 * @param int   $wc_order_id WooCommerce order ID.
	 * @param array $packages    Array of package data.
	 * @return array Result with success status and messages.
	 */
	public function confirm_order_shipment( int $wc_order_id, array $packages ): array {
		try {
			$this->logger->debug( "Processing shipment confirmation for WC Order #{$wc_order_id}" );

			// Get WooCommerce order.
			$order = wc_get_order( $wc_order_id );
			if ( ! $order ) {
				return array(
					'success' => false,
					'message' => __( 'Order not found.', 'multi-channel-for-woocommerce' ),
				);
			}

			// Validate order has Amazon order ID.
			$amazon_order_id = $order->get_meta( '_amazon_order_id' );
			if ( empty( $amazon_order_id ) ) {
				return array(
					'success' => false,
					'message' => __( 'This is not an Amazon order.', 'multi-channel-for-woocommerce' ),
				);
			}

			// Get channel UUID from order meta.
			$channel_uuid = $order->get_meta( '_amazon_channel_uuid' );
			if ( empty( $channel_uuid ) ) {
				return array(
					'success' => false,
					'message' => __( 'Channel UUID not found for this order. Please resync the order.', 'multi-channel-for-woocommerce' ),
				);
			}

			// Get marketplace ID from order meta or data.
			$marketplace_id = $order->get_meta( '_amazon_marketplace_id' );
			if ( empty( $marketplace_id ) ) {
				// Try to get from full order data.
				$amazon_data = $order->get_meta( '_amazon_order_data' );
				if ( ! empty( $amazon_data ) && isset( $amazon_data['MarketplaceId'] ) ) {
					$marketplace_id = $amazon_data['MarketplaceId'];
				} else {
					return array(
						'success' => false,
						'message' => __( 'Marketplace ID not found for this order.', 'multi-channel-for-woocommerce' ),
					);
				}
			}

			// Validate packages.
			$validation_result = $this->validate_packages( $packages );
			if ( ! $validation_result['valid'] ) {
				return array(
					'success' => false,
					'message' => $validation_result['message'],
				);
			}

			// Process each package.
			$results        = array();
			$success_count  = 0;
			$errors         = array();

			foreach ( $packages as $index => $package ) {
				$package_num = $index + 1;
				$this->logger->debug( "Processing package #{$package_num} with reference: {$package['packageReferenceId']}" );

				// Prepare package data for API.
				$package_data = array(
					'packageReferenceId' => sanitize_text_field( $package['packageReferenceId'] ),
					'carrierCode'       => sanitize_text_field( $package['carrierCode'] ),
					'carrierName'       => sanitize_text_field( $package['carrierName'] ),
					'shippingMethod'    => sanitize_text_field( $package['shippingMethod'] ),
					'trackingNumber'    => sanitize_text_field( $package['trackingNumber'] ),
					'shipDate'          => sanitize_text_field( $package['shipDate'] ),
					'orderItems'        => $package['orderItems'],
				);

				// Optional COD collection method.
				if ( ! empty( $package['codCollectionMethod'] ) ) {
					$package_data['codCollectionMethod'] = sanitize_text_field( $package['codCollectionMethod'] );
				}

				// Call shipment service.
				$result = $this->shipment_service->confirm_shipment(
					$channel_uuid,
					$amazon_order_id,
					$marketplace_id,
					$package_data
				);

				if ( is_wp_error( $result ) ) {
					$error_msg = sprintf(
						/* translators: 1: Package number, 2: Error message */
						__( 'Package %1$d: %2$s', 'multi-channel-for-woocommerce' ),
						$package_num,
						$result->get_error_message()
					);
					$errors[] = $error_msg;
					$this->logger->error( $error_msg );
				} else {
					++$success_count;
					$this->logger->debug( "Package #{$package_num} confirmed successfully" );

					// Store shipment tracking info in order meta.
					$this->store_shipment_meta( $order, $package_data, $package_num );
				}
			}

		// Prepare response message.
		if ( count( $packages ) === $success_count ) {
				// Add order note.
				$order->add_order_note(
					sprintf(
						/* translators: %d: Number of packages */
						__( 'Shipment confirmed to Amazon: %d package(s) synced successfully.', 'multi-channel-for-woocommerce' ),
						$success_count
					)
				);

				return array(
					'success' => true,
					'message' => sprintf(
						/* translators: %d: Number of packages */
						__( 'Successfully confirmed %d package(s) to Amazon.', 'multi-channel-for-woocommerce' ),
						$success_count
					),
				);
			} elseif ( $success_count > 0 ) {
				return array(
					'success' => false,
					'message' => sprintf(
						/* translators: 1: Success count, 2: Total count, 3: Error messages */
						__( 'Partially successful: %1$d of %2$d packages confirmed. Errors: %3$s', 'multi-channel-for-woocommerce' ),
						$success_count,
						count( $packages ),
						implode( '; ', $errors )
					),
				);
			} else {
				return array(
					'success' => false,
					'message' => __( 'Failed to confirm shipment: ', 'multi-channel-for-woocommerce' ) . implode( '; ', $errors ),
				);
			}
		} catch ( \Exception $e ) {
			$this->logger->error( 'Exception in confirm_order_shipment: ' . $e->getMessage() );
			return array(
				'success' => false,
				'message' => __( 'An error occurred while confirming shipment: ', 'multi-channel-for-woocommerce' ) . esc_html( $e->getMessage() ),
			);
		}
	}

	/**
	 * Validate package data.
	 *
	 * @param array $packages Array of package data.
	 * @return array Validation result with 'valid' boolean and 'message' string.
	 */
	private function validate_packages( array $packages ): array {
		if ( empty( $packages ) ) {
			return array(
				'valid'   => false,
				'message' => __( 'No packages provided.', 'multi-channel-for-woocommerce' ),
			);
		}

		$required_fields = array(
			'packageReferenceId',
			'carrierCode',
			'carrierName',
			'shippingMethod',
			'trackingNumber',
			'shipDate',
			'orderItems',
		);

		foreach ( $packages as $index => $package ) {
			$package_num = $index + 1;

			// Check required fields.
			foreach ( $required_fields as $field ) {
				if ( empty( $package[ $field ] ) ) {
					return array(
						'valid'   => false,
						'message' => sprintf(
							/* translators: 1: Field name, 2: Package number */
							__( 'Missing required field "%1$s" in package %2$d.', 'multi-channel-for-woocommerce' ),
							$field,
							$package_num
						),
					);
				}
			}

			// Validate order items structure.
			if ( ! is_array( $package['orderItems'] ) || empty( $package['orderItems'] ) ) {
				return array(
					'valid'   => false,
					'message' => sprintf(
						/* translators: %d: Package number */
						__( 'No items selected for package %d.', 'multi-channel-for-woocommerce' ),
						$package_num
					),
				);
			}

			foreach ( $package['orderItems'] as $item ) {
				if ( ! isset( $item['orderItemId'] ) || ! isset( $item['quantity'] ) ) {
					return array(
						'valid'   => false,
						'message' => sprintf(
							/* translators: %d: Package number */
							__( 'Invalid item structure in package %d.', 'multi-channel-for-woocommerce' ),
							$package_num
						),
					);
				}

				if ( (int) $item['quantity'] <= 0 ) {
					return array(
						'valid'   => false,
						'message' => sprintf(
							/* translators: %d: Package number */
							__( 'Item quantity must be greater than 0 in package %d.', 'multi-channel-for-woocommerce' ),
							$package_num
						),
					);
				}
			}

			// Validate ship date format (ISO 8601).
			$timestamp = strtotime( $package['shipDate'] );
			if ( false === $timestamp ) {
				return array(
					'valid'   => false,
					'message' => sprintf(
						/* translators: %d: Package number */
						__( 'Invalid ship date format in package %d.', 'multi-channel-for-woocommerce' ),
						$package_num
					),
				);
			}
		}

		return array(
			'valid'   => true,
			'message' => '',
		);
	}

	/**
	 * Store shipment tracking information in order meta.
	 *
	 * @param \WC_Order $order        WooCommerce order object.
	 * @param array     $package_data Package data.
	 * @param int       $package_num  Package number.
	 * @return void
	 */
	private function store_shipment_meta( \WC_Order $order, array $package_data, int $package_num ): void {
		// Get existing shipments.
		$shipments = $order->get_meta( '_amazon_shipments' );
		if ( ! is_array( $shipments ) ) {
			$shipments = array();
		}

		// Add new shipment.
		$shipments[] = array(
			'package_number'    => $package_num,
			'package_reference' => $package_data['packageReferenceId'],
			'carrier_code'      => $package_data['carrierCode'],
			'carrier_name'      => $package_data['carrierName'],
			'shipping_method'   => $package_data['shippingMethod'],
			'tracking_number'   => $package_data['trackingNumber'],
			'ship_date'         => $package_data['shipDate'],
			'confirmed_at'      => current_time( 'mysql' ),
		);

		$order->update_meta_data( '_amazon_shipments', $shipments );
		$order->save();
	}
}
