<?php
/**
 * Amazon Catalog Service
 *
 * This class handles catalog operations with Amazon API including
 * searching for existing products by identifiers.
 *
 * @package    MOMCS_Sync
 * @subpackage MOMCS_Sync/includes/common/services/amazon
 * @author     miniOrange
 * @license    Expat
 * @link       https://miniorange.com
 */

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\Utils\Logger;
use MOMCS_Sync\Includes\Common\Utils\Marketplace_IDs;

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

/**
 * Class for handling Amazon catalog operations.
 */
class Catalog_Service {

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

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

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

	/**
	 * Catalog endpoint.
	 *
	 * @var string
	 */
	private $catalog_endpoint = '/catalog/2022-04-01/items';

	/**
	 * Constructor.
	 */
	public function __construct() {
		$this->api_handler   = new Api_Handler();
		$this->token_service = new Token_Service();
		$this->logger        = new Logger( 'amazon-catalog-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-eu.amazon.com';
	}

	/**
	 * Search for products in Amazon catalog by identifier.
	 *
	 * @param string $channel_id      Channel UUID.
	 * @param string $identifier      Product identifier (UPC, EAN, ISBN, etc.).
	 * @param string $identifier_type Type of identifier (UPC, EAN, ISBN, etc.).
	 * @param string $marketplace_id  Amazon marketplace ID.
	 * @param array  $included_data   Data to include in response (default: summaries,identifiers).
	 * @param int    $log_action_id   Optional. Action Scheduler job ID for logging.
	 * @return array|WP_Error Search results or error.
	 */
	public function search_catalog_by_identifier( $channel_id, $identifier, $identifier_type = 'UPC', $marketplace_id = '', $included_data = array( 'summaries', 'identifiers' ), $log_action_id = null ) {
		$this->logger->debug(
			'Searching catalog by identifier',
			array(
				'identifier'      => $identifier,
				'identifier_type' => $identifier_type,
				'marketplace_id'  => $marketplace_id,
			)
		);

		// Get access token.
		$access_token = $this->token_service->get_access_token( $channel_id );
		if ( is_wp_error( $access_token ) ) {
			$this->logger->error(
				'Failed to get access token',
				array(
					'error' => $access_token->get_error_message(),
				)
			);
			if ( $log_action_id ) {
				$this->log_to_action_scheduler(
					$log_action_id,
					'error',
					$identifier,
					array(
						'message'         => 'Failed to get access token: ' . $access_token->get_error_message(),
						'identifier_type' => $identifier_type,
						'marketplace_id'  => $marketplace_id,
					),
					'catalog_search'
				);
			}
			return $access_token;
		}

		// Fix multi-line assignments.
		$query_params = array(
			'identifiers'     => $identifier,
			'identifiersType' => $identifier_type,
			'marketplaceIds'  => $marketplace_id,
		);

		// Build the URL with query parameters.
		$url = $this->get_base_url( $marketplace_id ) . $this->catalog_endpoint . '?' . http_build_query( $query_params );

		$this->logger->debug(
			'Catalog API request URL.',
			array(
				'url' => $url,
			)
		);

		// Make API request.
		$context  = array(
			'log_action_id' => $log_action_id,
			'product_id'    => 0,
			'stage'         => 'catalog_search',
		);
		$response = $this->api_handler->get(
			$url,
			array(
				'X-AMZ-Access-Token' => $access_token,
			),
			null,
			$context
		);

		// Check for errors.
		if ( is_wp_error( $response ) ) {
			$this->logger->error(
				'Error searching catalog',
				array(
					'error' => $response->get_error_message(),
				)
			);
			if ( $log_action_id ) {
				$this->log_to_action_scheduler(
					$log_action_id,
					'error',
					$identifier,
					array(
						'message'         => 'Error searching catalog: ' . $response->get_error_message(),
						'identifier_type' => $identifier_type,
						'marketplace_id'  => $marketplace_id,
						'url'             => $url,
					),
					'catalog_search'
				);
			}
			return $response;
		}

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

		// Log the response.
		$this->logger->debug(
			'Catalog API response',
			array(
				'status_code' => $status_code,
				'body'        => $body,
			)
		);

		// Handle 404 for products not found.
		if ( 404 === $status_code ) {
			$this->logger->debug( 'Product not found in catalog' );
			if ( $log_action_id ) {
				$this->log_to_action_scheduler(
					$log_action_id,
					'error',
					$identifier,
					array(
						'message'         => 'Product not found in Amazon catalog',
						'identifier_type' => $identifier_type,
						'identifier'      => $identifier,
						'marketplace_id'  => $marketplace_id,
					),
					'catalog_search'
				);
			}
			return array(
				'found' => false,
				'items' => array(),
			);
		}

		// Process results.
		$found = false;
		$items = array();

		if ( isset( $body['items'] ) && is_array( $body['items'] ) ) {
			$found = count( $body['items'] ) > 0;
			$items = $body['items'];
		}

		return array(
			'found'           => $found,
			'items'           => $items,
			'numberOfResults' => $body['numberOfResults'] ?? 0,
		);
	}

	/**
	 * Get product details from Amazon catalog by ASIN.
	 *
	 * @param string $channel_id     Channel UUID.
	 * @param string $asin           Amazon ASIN.
	 * @param string $marketplace_id Amazon marketplace ID.
	 * @param array  $included_data  Data to include in response.
	 * @return array|WP_Error Product details or error.
	 */
	public function get_catalog_item( $channel_id, $asin, $marketplace_id, $included_data = array( 'attributes', 'dimensions', 'identifiers', 'images', 'productTypes', 'relationships', 'salesRanks', 'summaries', 'vendorDetails' ) ) {
		$this->logger->debug(
			'Getting catalog item',
			array(
				'asin'           => $asin,
				'marketplace_id' => $marketplace_id,
			)
		);

		// Get access token.
		$access_token = $this->token_service->get_access_token( $channel_id );
		if ( is_wp_error( $access_token ) ) {
			$this->logger->error(
				'Failed to get access token',
				array(
					'error' => $access_token->get_error_message(),
				)
			);
			return $access_token;
		}

		// Prepare query parameters.
		$query_params = array(
			'marketplaceIds' => $marketplace_id,
		);

		// Add included data.
		$query_params['includedData'] = implode( ',', $included_data );

		// Build the URL with query parameters.
		$url = $this->get_base_url( $marketplace_id ) . $this->catalog_endpoint . '/' . $asin . '?' . http_build_query( $query_params );

		$this->logger->debug(
			'Catalog item API request URL.',
			array(
				'url' => $url,
			)
		);

		// Make API request.
		$response = $this->api_handler->get(
			$url,
			array(
				'X-AMZ-Access-Token' => $access_token,
			)
		);

		// Check for errors.
		if ( is_wp_error( $response ) ) {
			$this->logger->error(
				'Error getting catalog item',
				array(
					'error' => $response->get_error_message(),
				)
			);
			return $response;
		}

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

		// Log the response.
		$this->logger->debug(
			'Catalog item API response',
			array(
				'status_code' => $status_code,
				'body'        => $body,
			)
		);

		// Handle 404 for product not found.
		if ( 404 === $status_code ) {
			$this->logger->debug( 'Product not found in catalog' );
			return array(
				'found' => false,
				'item'  => array(),
			);
		}

		return array(
			'found' => true,
			'item'  => $body,
		);
	}

	/**
	 * Extract identifiers from catalog item.
	 *
	 * @param array $item Catalog item.
	 * @return array Extracted identifiers.
	 */
	public function extract_identifiers( $item ) {
		$identifiers = array();

		if ( isset( $item['identifiers'] ) ) {
			foreach ( $item['identifiers'] as $type => $values ) {
				foreach ( $values as $value ) {
					$identifiers[ $type ] = $value['identifier'];
				}
			}
		}

		return $identifiers;
	}
}
