<?php
/**
 * Amazon Orders Service
 *
 * @package    MOMCS_Sync
 * @subpackage MOMCS_Sync/includes/common/services/amazon
 * @author     miniOrange
 */

declare(strict_types=1);

namespace MOMCS_Sync\Includes\Common\Services\Amazon;

use MOMCS_Sync\Includes\Common\Models\Multichannels_Model;
use MOMCS_Sync\Includes\Common\Services\Handlers\Api_Handler;
use MOMCS_Sync\Includes\Common\Utils\Logger;
use MOMCS_Sync\Includes\Common\Utils\Marketplace_IDs;

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

/**
 * Class for handling Amazon Orders API operations.
 */
class Orders_Service {

	/**
	 * API Handler instance.
	 *
	 * @var Api_Handler
	 */
	private $api_handler;

	/**
	 * Token Service instance.
	 *
	 * @var Token_Service
	 */
	private $token_service;

	/**
	 * Base API URL.
	 *
	 * @var string
	 */
	private $base_url;

	/**
	 * Debug logger (uploads/multi-channel-for-woocommerce/orders-service-*.log).
	 *
	 * @var Logger
	 */
	private $logger;

	/**
	 * Constructor.
	 */
	public function __construct() {
		$this->api_handler   = new Api_Handler();
		$this->token_service = new Token_Service();
		$this->logger        = new Logger( 'orders-service' );
	}

	/**
	 * Get dynamic base URL for Amazon API based on marketplace
	 *
	 * @param string $marketplace_id Amazon marketplace ID.
	 * @return string Base URL.
	 */
	private function get_base_url( string $marketplace_id ): string {
		// Get dynamic URL based on marketplace.
		return Marketplace_IDs::get_api_base_url( $marketplace_id ) ?? 'https://sellingpartnerapi-na.amazon.com';
	}

	/**
	 * Get orders from Amazon - single page for batch processing.
	 *
	 * @param string      $channel_uuid The channel UUID.
	 * @param string      $date_from Optional. Start date in ISO 8601 format.
	 * @param string      $date_to Optional. End date in ISO 8601 format.
	 * @param string|null $next_token Optional. Pagination token from previous response.
	 * @return array|WP_Error The orders response with NextToken, or error.
	 */
	public function get_orders( $channel_uuid, $date_from = '', $date_to = '', $next_token = null ) {
		try {
			// Get channel details.
			$multichannels_model = new Multichannels_Model();
			$channel             = $multichannels_model->get_channel_by_uuid( $channel_uuid );

			if ( ! $channel ) {
				return new \WP_Error( 'invalid_channel', 'Channel not found.' );
			}

			// Get access token.
			$access_token = $this->token_service->get_access_token( $channel_uuid );
			if ( is_wp_error( $access_token ) ) {
				return $access_token;
			}

			$marketplace_id_for_url = $channel['region'];

			// Fetch single page - batch processing will handle pagination via NextToken.
			return $this->fetch_orders_page( $marketplace_id_for_url, $access_token, $date_from, $date_to, $next_token );

		} catch ( \Exception $e ) {
			return new \WP_Error( 'orders_fetch_error', $e->getMessage() );
		}
	}

	/**
	 * Fetch a single page of orders from Amazon API.
	 *
	 * @param string      $marketplace_id Amazon marketplace ID.
	 * @param string      $access_token Access token.
	 * @param string      $date_from Start date in ISO 8601 format.
	 * @param string      $date_to End date in ISO 8601 format.
	 * @param string|null $next_token Optional. Pagination token from previous response.
	 * @return array|WP_Error The orders response or error.
	 */
	private function fetch_orders_page( string $marketplace_id, string $access_token, string $date_from, string $date_to, $next_token = null ) {
		// Build the URL.
		$url = $this->get_base_url( $marketplace_id ) . '/orders/v0/orders?MarketplaceIds=' . $marketplace_id;

		// Add date filters.
		if ( ! empty( $date_from ) ) {
			$url .= '&CreatedAfter=' . rawurlencode( $date_from );
		} else {
			// Default to a far past date if not specified.
			$url .= '&CreatedAfter=2000-07-01T11:58:28';
		}

		if ( ! empty( $date_to ) ) {
			$url .= '&CreatedBefore=' . rawurlencode( $date_to );
		}

		// Add pagination token if present.
		if ( null !== $next_token ) {
			$url .= '&NextToken=' . rawurlencode( $next_token );
		}

		// Set up headers.
		$headers = array(
			'X-AMZ-Access-Token' => $access_token,
			'Content-Type'       => 'application/json',
		);

		// Make API request.
		$response = $this->api_handler->get( $url, $headers );

		if ( is_wp_error( $response ) ) {
			return $response;
		}

		// Parse response.
		$body = json_decode( wp_remote_retrieve_body( $response ), true );

		// Return only the payload.
		if ( ! isset( $body['payload'] ) ) {
			return new \WP_Error( 'invalid_response', 'Invalid response format from Amazon API' );
		}

		return $body['payload'];
	}

	/**
	 * Get order items for a specific order.
	 *
	 * @param string $channel_uuid The channel UUID.
	 * @param string $order_id The Amazon order ID.
	 * @return array|WP_Error The order items response or error.
	 */
	public function get_order_items( $channel_uuid, $order_id ) {
		try {
			// Get channel details.
			$multichannels_model = new Multichannels_Model();
			$channel             = $multichannels_model->get_channel_by_uuid( $channel_uuid );

			if ( ! $channel ) {
				return new \WP_Error( 'invalid_channel', 'Channel not found.' );
			}

			// Get access token.
			$access_token = $this->token_service->get_access_token( $channel_uuid );
			if ( is_wp_error( $access_token ) ) {
				return $access_token;
			}

			// Build the URL.
			$url = $this->get_base_url( $channel['region'] ) . '/orders/v0/orders/' . $order_id . '/orderItems';

			// Set up headers.
			$headers = array(
				'X-AMZ-Access-Token' => $access_token,
				'Content-Type'       => 'application/json',
			);

			// Make API request.
			$response = $this->api_handler->get( $url, $headers );

			if ( is_wp_error( $response ) ) {
				return $response;
			}

			// Parse response.
			$body = json_decode( wp_remote_retrieve_body( $response ), true );

			// Return only the payload.
			if ( ! isset( $body['payload'] ) ) {
				return new \WP_Error( 'invalid_response', 'Invalid response format from Amazon API' );
			}
			return $body['payload'];

		} catch ( \Exception $e ) {
			return new \WP_Error( 'order_items_fetch_error', $e->getMessage() );
		}
	}

	/**
	 * Get order buyer info.
	 *
	 * @param string $channel_uuid Channel UUID.
	 * @param string $order_id     Amazon order ID.
	 * @return array|WP_Error Buyer info payload or error.
	 */
	public function get_order_buyer_info( string $channel_uuid, string $order_id ) {
		try {
			$multichannels_model = new Multichannels_Model();
			$channel             = $multichannels_model->get_channel_by_uuid( $channel_uuid );
			if ( ! $channel ) {
				return new \WP_Error( 'invalid_channel', 'Channel not found.' );
			}

			$access_token = $this->token_service->get_access_token( $channel_uuid );
			if ( is_wp_error( $access_token ) ) {
				return $access_token;
			}

			$url     = $this->get_base_url( $channel['region'] ) . '/orders/v0/orders/' . $order_id . '/buyerInfo';
			$headers = array(
				'X-AMZ-Access-Token' => $access_token,
				'Content-Type'       => 'application/json',
			);

			$this->logger->debug(
				'get_order_buyer_info API request',
				array(
					'amazon_order_id' => $order_id,
					'channel_uuid'    => $channel_uuid,
					'method'          => 'GET',
					'url'             => $url,
					'headers'         => $this->redact_headers_for_log( $headers ),
				)
			);

			$response = $this->api_handler->get( $url, $headers );
			if ( is_wp_error( $response ) ) {
				$this->logger->debug(
					'get_order_buyer_info API transport error',
					array(
						'amazon_order_id' => $order_id,
						'error_code'      => $response->get_error_code(),
						'error_message'   => $response->get_error_message(),
					)
				);
				return $response;
			}

			$raw_body   = wp_remote_retrieve_body( $response );
			$http_code  = (int) wp_remote_retrieve_response_code( $response );
			$body       = json_decode( $raw_body, true );
			$log_body   = is_array( $body ) ? $body : array( '_raw' => $raw_body );

			$this->logger->debug(
				'get_order_buyer_info API response',
				array(
					'amazon_order_id' => $order_id,
					'http_code'       => $http_code,
					'body'            => $log_body,
				)
			);

			if ( ! is_array( $body ) ) {
				return new \WP_Error( 'invalid_response', 'Invalid JSON in buyer info response.' );
			}
			if ( ! isset( $body['payload'] ) ) {
				return new \WP_Error( 'invalid_response', 'Invalid response format.' );
			}
			return $body['payload'];
		} catch ( \Exception $e ) {
			return new \WP_Error( 'buyer_info_fetch_error', $e->getMessage() );
		}
	}

	/**
	 * Get order shipping address.
	 *
	 * @param string $channel_uuid Channel UUID.
	 * @param string $order_id     Amazon order ID.
	 * @return array|WP_Error Address payload or error.
	 */
	public function get_order_address( string $channel_uuid, string $order_id ) {
		try {
			$multichannels_model = new Multichannels_Model();
			$channel             = $multichannels_model->get_channel_by_uuid( $channel_uuid );
			if ( ! $channel ) {
				return new \WP_Error( 'invalid_channel', 'Channel not found.' );
			}

			$access_token = $this->token_service->get_access_token( $channel_uuid );
			if ( is_wp_error( $access_token ) ) {
				return $access_token;
			}

			$url     = $this->get_base_url( $channel['region'] ) . '/orders/v0/orders/' . $order_id . '/address';
			$headers = array(
				'X-AMZ-Access-Token' => $access_token,
				'Content-Type'       => 'application/json',
			);

			$this->logger->debug(
				'get_order_address API request',
				array(
					'amazon_order_id' => $order_id,
					'channel_uuid'    => $channel_uuid,
					'method'          => 'GET',
					'url'             => $url,
					'headers'         => $this->redact_headers_for_log( $headers ),
				)
			);

			$response = $this->api_handler->get( $url, $headers );
			if ( is_wp_error( $response ) ) {
				$this->logger->debug(
					'get_order_address API transport error',
					array(
						'amazon_order_id' => $order_id,
						'error_code'      => $response->get_error_code(),
						'error_message'   => $response->get_error_message(),
					)
				);
				return $response;
			}

			$raw_body  = wp_remote_retrieve_body( $response );
			$http_code = (int) wp_remote_retrieve_response_code( $response );
			$body      = json_decode( $raw_body, true );
			$log_body  = is_array( $body ) ? $body : array( '_raw' => $raw_body );

			$this->logger->debug(
				'get_order_address API response',
				array(
					'amazon_order_id' => $order_id,
					'http_code'       => $http_code,
					'body'            => $log_body,
				)
			);

			if ( ! is_array( $body ) ) {
				return new \WP_Error( 'invalid_response', 'Invalid JSON in address response.' );
			}
			if ( ! isset( $body['payload'] ) ) {
				return new \WP_Error( 'invalid_response', 'Invalid response format.' );
			}
			return $body['payload'];
		} catch ( \Exception $e ) {
			return new \WP_Error( 'address_fetch_error', $e->getMessage() );
		}
	}

	/**
	 * Return headers safe for debug logs (access token redacted).
	 *
	 * @param array<string,string> $headers Request headers.
	 * @return array<string,string>
	 */
	private function redact_headers_for_log( array $headers ): array {
		$out = $headers;
		if ( isset( $out['X-AMZ-Access-Token'] ) ) {
			$out['X-AMZ-Access-Token'] = '[REDACTED]';
		}
		return $out;
	}
}
