<?php
/**
 * Order Handler – centralises order-related business logic and orchestrates
 * interaction between low-level services (Orders_Service) and domain helpers
 * (Order_Manager).
 *
 * @package    MOMCS_Sync
 * @subpackage MOMCS_Sync\includes\common\handlers
 */

declare(strict_types=1);

namespace MOMCS_Sync\Includes\Common\Handlers;

use MOMCS_Sync\Includes\Common\Services\Amazon\Orders_Service;
use MOMCS_Sync\Includes\Common\Services\Amazon\Order_Manager;
use MOMCS_Sync\Includes\Common\Utils\Logger;
use MOMCS_Sync\Includes\Common\Models\Multichannels_Model;
use WP_Error;

if ( ! defined( 'ABSPATH' ) ) {
	exit; // Exit if accessed directly.
}

/**
 * Class Order_Handler
 *
 * Responsibilities:
 * 1. Fetch fresh orders from Amazon and import them into WooCommerce.
 * 2. Provide paginated listings for previously imported Amazon orders.
 * 3. Act as the single point of contact for controllers / AJAX endpoints.
 */
class Order_Handler {

	/**
	 * Orders service instance.
	 *
	 * @var Orders_Service
	 */
	private Orders_Service $orders_service;
	/**
	 * Order manager instance.
	 *
	 * @var Order_Manager
	 */
	private Order_Manager $order_manager;
	/**
	 * Logger instance.
	 *
	 * @var Logger
	 */
	private Logger $logger;

	/**
	 * Constructor.
	 */
	public function __construct() {
		$this->orders_service = new Orders_Service();
		$this->order_manager  = new Order_Manager();
		$this->logger         = new Logger( 'order-handler' );
	}

	/**
	 * Paginated listing of already-imported Amazon orders.
	 *
	 * @param int    $page              Page number (1-indexed).
	 * @param int    $per_page          Items per page.
	 * @param string $status_filter     Amazon status filter (optional).
	 * @param string $fulfillment_filter Fulfillment channel filter (optional).
	 * @param string $search            Search term (optional).
	 * @param string $date_from         Date from (YYYY-MM-DD) optional.
	 * @param string $date_to           Date to (YYYY-MM-DD) optional.
	 *
	 * @return array<string,mixed>
	 */
	public function get_orders( int $page, int $per_page, string $status_filter = '', string $fulfillment_filter = '', string $search = '', string $date_from = '', string $date_to = '' ): array {
		$args = array(
			'posts_per_page'      => $per_page,
			'paged'               => $page,
			'amazon_status'       => $status_filter,
			'fulfillment_channel' => $fulfillment_filter,
			'search'              => $search,
			'date_from'           => $date_from,
			'date_to'             => $date_to,
		);

		return $this->order_manager->get_amazon_orders( $args );
	}

	/**
	 * Fetch new orders for a given channel from Amazon and import them.
	 *
	 * NOTE: This method now fetches only ONE PAGE of orders for free tier users.
	 * Premium users should use the background handler for paginated fetching.
	 *
	 * @param array  $channel   DB record representing the channel (expects 'uuid').
	 * @param string $date_from Optional start date (YYYY-MM-DD).
	 * @param string $date_to   Optional end date (YYYY-MM-DD).
	 *
	 * @return array{created:int,failed:int} Results.
	 */
	public function fetch_new_orders_by_channel( array $channel, string $date_from = '', string $date_to = '' ): array {
		$created = 0;
		$failed  = 0;

		if ( ! isset( $channel['uuid'] ) ) {
			$this->logger->error( 'Channel record missing uuid column.' );
			return array(
				'created' => 0,
				'failed'  => 1,
			);
		}

		$this->logger->debug( 'Fetching new orders for channel ' . $channel['uuid'] );

		// Fetch one page of orders (no NextToken = first page only).
		$orders = $this->orders_service->get_orders( $channel['uuid'], $date_from, $date_to, null );
		if ( is_wp_error( $orders ) ) {
			$this->logger->error( 'Failed to fetch orders list: ' . $orders->get_error_message() );
			return array(
				'created' => 0,
				'failed'  => 1,
			);
		}

		$orders_list = $orders['Orders'] ?? array();

		foreach ( $orders_list as $order_summary ) {
			try {
				$amazon_order_id = $order_summary['AmazonOrderId'] ?? '';
				if ( ! $amazon_order_id ) {
					$this->logger->warning( 'Skipping order with missing AmazonOrderId.' );
					++$failed;
					continue;
				}

				// Retrieve order items, buyer info & address in parallel (no built-in async – sequential).
				$order_items = $this->orders_service->get_order_items( $channel['uuid'], $amazon_order_id );
				if ( is_wp_error( $order_items ) ) {
					$this->logger->error( 'Failed to fetch order items for ' . $amazon_order_id . ': ' . $order_items->get_error_message() );
					++$failed;
					continue;
				}

				$buyer_info = $this->orders_service->get_order_buyer_info( $channel['uuid'], $amazon_order_id );
				if ( is_wp_error( $buyer_info ) ) {
					$this->logger->error( 'Failed to fetch buyer info for ' . $amazon_order_id . ': ' . $buyer_info->get_error_message() );
					++$failed;
					continue;
				}

				$address = $this->orders_service->get_order_address( $channel['uuid'], $amazon_order_id );
				if ( is_wp_error( $address ) ) {
					$this->logger->error( 'Failed to fetch address for ' . $amazon_order_id . ': ' . $address->get_error_message() );
					++$failed;
					continue;
				}

			// Merge datasets (normalize API payloads: buyer fields live on payload root per SP-API).
			$full_order                    = $order_summary;
			$full_order['OrderItems']      = $order_items['OrderItems'] ?? array();
			$full_order['BuyerInfo']       = Order_Manager::normalize_buyer_info_from_api_response( is_array( $buyer_info ) ? $buyer_info : array() );
			$full_order['ShippingAddress'] = Order_Manager::normalize_shipping_address_from_api_response( is_array( $address ) ? $address : array() );
			if ( is_array( $address ) && ! empty( $address['BuyerCompanyName'] ) ) {
				$full_order['BuyerCompanyName'] = sanitize_text_field( (string) $address['BuyerCompanyName'] );
			}

			// Delegate Woo import to Order_Manager with channel UUID.
			$this->order_manager->create_woocommerce_order( $full_order, $channel['uuid'] );
			++$created;
			} catch ( \Throwable $e ) {
				$this->logger->error( 'Failed to import order: ' . $e->getMessage() );
				++$failed;
			}
		}

		return array(
			'created' => $created,
			'failed'  => $failed,
		);
	}

	/**
	 * Convenience helper – Iterate over all active channels and pull orders.
	 *
	 * @param string $date_from Optional date range start.
	 * @param string $date_to   Optional date range end.
	 *
	 * @return array{created:int,failed:int} Results.
	 */
	public function fetch_new_orders_for_all_channels( string $date_from = '', string $date_to = '' ): array {
		$multichannels_model = new Multichannels_Model();
		$channels            = $multichannels_model->get_all_channels();

		$created = 0;
		$failed  = 0;

		foreach ( $channels as $channel ) {
			$result   = $this->fetch_new_orders_by_channel( $channel, $date_from, $date_to );
			$created += $result['created'];
			$failed  += $result['failed'];
		}

		return array(
			'created' => $created,
			'failed'  => $failed,
		);
	}
}
