<?php
/**
 * Fulfillment Order Service
 *
 * Sends createFulfillmentOrder requests to Amazon SP-API.
 *
 * @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\Services\Handlers\Api_Handler;
use MOMCS_Sync\Includes\Common\Models\Multichannels_Model;
use MOMCS_Sync\Includes\Common\Utils\Marketplace_IDs;
use MOMCS_Sync\Includes\Common\Utils\Logger;

if ( ! defined( 'ABSPATH' ) ) {
	exit;
}
/**
 * Amazon fulfillment outbound service.
 */
class Fulfillment_Order_Service {

	/**
	 * API handler.
	 *
	 * @var Api_Handler
	 */
	private Api_Handler $api_handler;

	/**
	 * Token service.
	 *
	 * @var Token_Service
	 */
	private Token_Service $token_service;

	/**
	 * Multichannel model.
	 *
	 * @var Multichannels_Model
	 */
	private Multichannels_Model $multichannels_model;

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

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

	/**
	 * Create Amazon fulfillment order.
	 *
	 * @param string $channel_uuid Channel UUID.
	 * @param array  $payload Fulfillment payload.
	 * @return array|\WP_Error
	 */
	public function create_fulfillment_order( string $channel_uuid, array $payload ) {
		$channel = $this->multichannels_model->get_channel_by_uuid( $channel_uuid );
		if ( ! $channel ) {
			return new \WP_Error( 'channel_not_found', __( 'Channel not found.', 'multi-channel-for-woocommerce' ) );
		}

		$marketplace_id = (string) ( $channel['region'] ?? '' );
		if ( '' === $marketplace_id ) {
			return new \WP_Error( 'marketplace_not_found', __( 'Marketplace ID not found for channel.', 'multi-channel-for-woocommerce' ) );
		}

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

		$base_url = Marketplace_IDs::get_api_base_url( $marketplace_id );
		if ( ! $base_url ) {
			return new \WP_Error( 'invalid_marketplace', __( 'Unable to resolve Amazon API endpoint for marketplace.', 'multi-channel-for-woocommerce' ) );
		}

		$url      = rtrim( $base_url, '/' ) . '/fba/outbound/2020-07-01/fulfillmentOrders';
		$response = $this->api_handler->post(
			$url,
			$payload,
			array(
				'X-AMZ-Access-Token' => $access_token,
				'Content-Type'       => 'application/json',
				'User-Agent'         => 'MOMCS-WC/' . ( defined( 'MOMCS_VERSION' ) ? MOMCS_VERSION : '1.0.0' ),
			),
			20
		);

		if ( is_wp_error( $response ) ) {
			$error = $this->map_api_error( $response );
			$this->logger->error(
				'Amazon fulfillment API request failed',
				array(
					'channel_uuid' => $channel_uuid,
					'error_code'   => $error->get_error_code(),
					'error'        => $error->get_error_message(),
					'error_data'   => $error->get_error_data(),
				)
			);
			return $error;
		}

		$body_raw = wp_remote_retrieve_body( $response );
		$body     = json_decode( $body_raw, true );
		if ( ! is_array( $body ) ) {
			$body = array();
		}

		if ( isset( $body['errors'][0] ) ) {
			$error_code    = (string) ( $body['errors'][0]['code'] ?? 'amazon_api_error' );
			$error_message = (string) ( $body['errors'][0]['message'] ?? __( 'Amazon API returned an error.', 'multi-channel-for-woocommerce' ) );
			return new \WP_Error(
				'amazon_' . sanitize_key( strtolower( $error_code ) ),
				$error_message,
				array(
					'status'       => wp_remote_retrieve_response_code( $response ),
					'amazon_code'  => $error_code,
					'responseBody' => $body,
				)
			);
		}

		$result = array(
			'sellerFulfillmentOrderId' => (string) ( $payload['sellerFulfillmentOrderId'] ?? '' ),
			'response'                 => $body,
			'status'                   => wp_remote_retrieve_response_code( $response ),
		);

		if ( isset( $body['payload']['sellerFulfillmentOrderId'] ) ) {
			$result['sellerFulfillmentOrderId'] = (string) $body['payload']['sellerFulfillmentOrderId'];
		}

		return $result;
	}

	/**
	 * Map generic API handler error to Amazon fulfillment error.
	 *
	 * @param \WP_Error $error Error from API handler.
	 * @return \WP_Error
	 */
	private function map_api_error( \WP_Error $error ): \WP_Error {
		$data        = $error->get_error_data();
		$status_code = is_array( $data ) && isset( $data['status'] ) ? (int) $data['status'] : 0;
		$body_raw    = is_array( $data ) && isset( $data['body'] ) ? (string) $data['body'] : '';
		$body        = json_decode( $body_raw, true );
		$amazon_code = '';
		$message     = $error->get_error_message();

		if ( is_array( $body ) && isset( $body['errors'][0] ) ) {
			$amazon_code = (string) ( $body['errors'][0]['code'] ?? '' );
			$message     = (string) ( $body['errors'][0]['message'] ?? $message );
		}

		$mapped_code = 'amazon_api_error';
		if ( 429 === $status_code || 'QuotaExceeded' === $amazon_code ) {
			$mapped_code = 'amazon_rate_limited';
		} elseif ( in_array( $status_code, array( 500, 502, 503, 504 ), true ) || 'InternalFailure' === $amazon_code ) {
			$mapped_code = 'amazon_internal_failure';
		} elseif ( 400 === $status_code && 'InvalidInput' === $amazon_code ) {
			$mapped_code = 'amazon_invalid_input';
		}

		return new \WP_Error(
			$mapped_code,
			$message,
			array(
				'status'       => $status_code,
				'amazon_code'  => $amazon_code,
				'responseBody' => is_array( $body ) ? $body : array(),
			)
		);
	}
}

