<?php
/**
 * Amazon Category 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\Utils\Logger;
use MOMCS_Sync\Includes\Common\Utils\Marketplace_IDs;
use MOMCS_Sync\Includes\Common\Exceptions\Amazon_Api_Exception;

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

/**
 * Category Service class for managing Amazon categories.
 */
class Category_Service {
	/**
	 * Logger instance.
	 *
	 * @var Logger
	 */
	private $logger;

	/**
	 * Constructor.
	 */
	public function __construct() {
		$this->logger = new Logger( 'category-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';
	}

	/**
	 * Get categories from Amazon API.
	 *
	 * @param string $channel_id Channel UUID.
	 * @param string $marketplace_id Amazon marketplace ID (optional).
	 * @return array|WP_Error Array of categories or WP_Error on failure.
	 */
	public function get_categories( $channel_id = '', $marketplace_id = '' ) {
		// Extract marketplace_id from UUID if not provided.
		if ( empty( $marketplace_id ) && ! empty( $channel_id ) ) {
			$marketplace_id = $this->get_marketplace_id_from_uuid( $channel_id );
		}

		// Simply call get_product_types which will fetch from the API.
		return $this->get_product_types( $channel_id, $marketplace_id );
	}

	/**
	 * Flattens the category hierarchy for use in dropdowns.
	 *
	 * @param array  $categories Array of categories.
	 * @param string $parent_name Parent category name for creating the hierarchical display.
	 * @return array Flattened array of categories.
	 */
	public function flatten_categories( $categories, $parent_name = '' ) {
		$result = array();

		foreach ( $categories as $category ) {
			$display_name              = $parent_name ? $parent_name . ' > ' . $category['name'] : $category['name'];
			$result[ $category['id'] ] = $display_name;

			if ( isset( $category['children'] ) && is_array( $category['children'] ) ) {
				$result = array_merge( $result, $this->flatten_categories( $category['children'], $display_name ) );
			}
		}

		return $result;
	}

	/**
	 * Get a list of product types for Amazon.
	 *
	 * @param string $channel_id Channel UUID.
	 * @param string $marketplace_id Amazon marketplace ID (optional).
	 * @return array|WP_Error Array of product types.
	 * @throws \MOMCS_Sync\Includes\Common\Exceptions\Amazon_Api_Exception If API request fails.
	 */
	public function get_product_types( $channel_id = '', $marketplace_id = '' ) {
		try {
			// Extract marketplace_id from UUID if not provided.
			if ( empty( $marketplace_id ) && ! empty( $channel_id ) ) {
				$marketplace_id = $this->get_marketplace_id_from_uuid( $channel_id );
			}

			// Get dynamic base URL based on marketplace.
			$base_url = $this->get_base_url( $marketplace_id );

			$endpoint = $base_url . '/definitions/2020-09-01/productTypes';
			$url      = add_query_arg( array( 'marketplaceIds' => $marketplace_id ), $endpoint );

			$access_token = '';
			if ( ! empty( $channel_id ) ) {
				$token_service = new \MOMCS_Sync\Includes\Common\Services\Amazon\Token_Service();
				$token_result  = $token_service->get_access_token( $channel_id );
				if ( ! is_wp_error( $token_result ) ) {
					$access_token = $token_result; // already decrypted by service.
				} else {
					// Log the token error.
					$this->logger->error( 'Amazon Token Service Error', array( 'message' => $token_result->get_error_message() ) );
					throw new Amazon_Api_Exception( 'Failed to obtain Amazon access token.' );
				}
			}

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

			// Make the API call.
			$api_handler = new \MOMCS_Sync\Includes\Common\Services\Handlers\Api_Handler();
			$response    = $api_handler->get( $url, $headers );

			if ( ! is_wp_error( $response ) ) {
				$body = json_decode( wp_remote_retrieve_body( $response ), true );

				if ( isset( $body['productTypes'] ) && is_array( $body['productTypes'] ) ) {
					$formatted_types = array();

					foreach ( $body['productTypes'] as $type ) {
						if ( isset( $type['name'] ) && isset( $type['displayName'] ) ) {
							$formatted_types[ $type['name'] ] = $type['displayName'];
						}
					}

					return $formatted_types;
				}
			}

			// Log the error for debugging.
			if ( is_wp_error( $response ) ) {
				$this->logger->error( 'Amazon Product Types API Error', array( 'message' => $response->get_error_message() ) );
				throw new Amazon_Api_Exception( 'Amazon Product Types API request failed.' );
			}
		} catch ( Amazon_Api_Exception $e ) {
			// Log the error and rethrow for upper layers to decide.
			$this->logger->error( $e->getMessage() );
			return array();
		}
	}

	/**
	 * Get marketplace ID by region.
	 *
	 * @param string $region Region code.
	 * @return string Marketplace ID.
	 */
	public function get_marketplace_id_by_region( $region ) {
		// Use the Marketplace_IDs utility class.
		$marketplace_id = Marketplace_IDs::get_marketplace_id( $region );

		// If the region is already a marketplace ID or we can't find a matching ID, return the original value.
		if ( Marketplace_IDs::is_marketplace_id( $region ) || empty( $marketplace_id ) ) {
			return $region;
		}

		return $marketplace_id;
	}

	/**
	 * Get Amazon categories (alias for get_categories for backward compatibility).
	 *
	 * @return array Array of categories.
	 */
	public function get_amazon_categories() {
		// This is a wrapper for backward compatibility.
		// Call get_product_types directly which will return categories from API or fallback.
		return $this->get_product_types();
	}

	/**
	 * Get Amazon product types (alias for get_product_types for backward compatibility).
	 *
	 * @return array Array of product types.
	 */
	public function get_amazon_product_types() {
		// This is a wrapper for backward compatibility.
		return $this->get_product_types();
	}

	/**
	 * Extract marketplace ID from channel UUID.
	 *
	 * @param string $uuid Channel UUID.
	 * @return string Marketplace ID or empty string if not found.
	 */
	private function get_marketplace_id_from_uuid( $uuid ) {
		// Get channel details from database.
		$multichannels_model = new \MOMCS_Sync\Includes\Common\Models\Multichannels_Model();
		$channel             = $multichannels_model->get_channel_by_uuid( $uuid );

		if ( ! $channel ) {
			return '';
		}

		// Check if region is already a marketplace ID.
		if ( isset( $channel['region'] ) ) {
			$region = $channel['region'];

			// If region is already a marketplace ID, return it.
			if ( $this->is_marketplace_id( $region ) ) {
				return $region;
			}

			// Otherwise, convert country code to marketplace ID.
			return $this->get_marketplace_id_by_region( $region );
		}

		return '';
	}

	/**
	 * Check if a string is a valid marketplace ID.
	 *
	 * @param string $str String to check.
	 * @return boolean True if valid marketplace ID.
	 */
	private function is_marketplace_id( $str ) {
		// Simple check for marketplace ID format (typically capital letters and numbers).
		return (bool) preg_match( '/^[A-Z0-9]+$/', $str ) && strlen( $str ) > 5;
	}
}
