<?php
/**
 * Default Meta Service
 *
 * Stores and retrieves channel-level defaults such as `marketplace_id` and
 * `language_tag`. These values are injected automatically into every SP-API
 * payload and therefore do not need to be mapped manually by the merchant.
 *
 * @package    MOMCS_Sync
 * @subpackage MOMCS_Sync\includes\common\services
 * @author     miniOrange
 */

declare( strict_types=1 );

namespace MOMCS_Sync\Includes\Common\Services;

use MOMCS_Sync\Includes\Common\Models\Product_Mapping_Model;

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

/**
 * Service class responsible for persisting and retrieving default meta values
 * against a channel. The values are stored in the existing product_mapping
 * table under the special `config` key `default_meta` (JSON-encoded).
 */
class Default_Meta_Service {

	/**
	 * Product mapping model.
	 *
	 * @var Product_Mapping_Model
	 */
	private $product_mapping_model;

	/**
	 * Constructor.
	 */
	public function __construct() {
		$this->product_mapping_model = new Product_Mapping_Model();
		$this->init_hooks();
	}

	/**
	 * Initialize WordPress hooks.
	 */
	private function init_hooks(): void {
		// Auto-populate defaults when a channel is authorized.
		add_action( 'momcs_channel_authorized', array( $this, 'auto_populate_defaults' ), 10, 2 );
	}

	/**
	 * Return defaults for a channel.
	 *
	 * @param string $channel_uuid Channel UUID.
	 * @return array{ marketplace_id:string, language_tag:string } Defaults (empty strings if not set).
	 */
	public function get_defaults( string $channel_uuid ): array {
		$mapping = $this->product_mapping_model->get_mapping_by_channel_and_config( $channel_uuid, 'default_meta' );

		if ( $mapping && ! empty( $mapping['config'] ) ) {
			$meta = json_decode( $mapping['config'], true );
			if ( json_last_error() === JSON_ERROR_NONE && is_array( $meta ) ) {
				return array(
					'marketplace_id' => (string) ( $meta['marketplace_id'] ?? '' ),
					'language_tag'   => (string) ( $meta['language_tag'] ?? '' ),
				);
			}
		}

		return array(
			'marketplace_id' => '',
			'language_tag'   => '',
		);
	}

	/**
	 * Persist defaults for a channel.
	 *
	 * @param string $channel_uuid Channel UUID.
	 * @param array  $meta         Associative array with keys marketplace_id & language_tag.
	 * @return void
	 * @throws \InvalidArgumentException When validation fails.
	 */
	public function set_defaults( string $channel_uuid, array $meta ): void {
		// Validate channel UUID.
		if ( empty( $channel_uuid ) || ! is_string( $channel_uuid ) ) {
			throw new \InvalidArgumentException( 'Invalid channel UUID provided.' );
		}

		// Sanitize and validate meta values.
		$sanitized_meta = $this->sanitize_meta( $meta );
		$this->validate_meta( $sanitized_meta );

		$payload = wp_json_encode( $sanitized_meta );

		// Upsert row in mapping table.
		$this->product_mapping_model->save_mapping( $channel_uuid, 'default_meta', $payload );
	}

	/**
	 * Auto-populate defaults when a channel is authorized.
	 * Hook callback for 'momcs_channel_authorized' action.
	 *
	 * @param string $channel_uuid   Channel UUID.
	 * @param array  $channel_config Channel configuration from authorization.
	 * @return void
	 */
	public function auto_populate_defaults( string $channel_uuid, array $channel_config ): void {
		// Extract marketplace_id and determine language_tag based on marketplace.
		$marketplace_id = $channel_config['marketplace_id'] ?? '';
		$language_tag   = $this->get_default_language_for_marketplace( $marketplace_id );

		if ( ! empty( $marketplace_id ) ) {
			try {
				$this->set_defaults(
					$channel_uuid,
					array(
						'marketplace_id' => $marketplace_id,
						'language_tag'   => $language_tag,
					)
				);
			} catch ( \InvalidArgumentException $e ) {
				return;
			}
		}
	}

	/**
	 * Sanitize meta values.
	 *
	 * @param array $meta Raw meta values.
	 * @return array Sanitized meta values.
	 */
	private function sanitize_meta( array $meta ): array {
		return array(
			'marketplace_id' => sanitize_text_field( (string) ( $meta['marketplace_id'] ?? '' ) ),
			'language_tag'   => sanitize_text_field( (string) ( $meta['language_tag'] ?? '' ) ),
		);
	}

	/**
	 * Validate meta values.
	 *
	 * @param array $meta Sanitized meta values.
	 * @return void
	 * @throws \InvalidArgumentException When validation fails.
	 */
	private function validate_meta( array $meta ): void {
		// Validate marketplace_id format (Amazon marketplace IDs are typically like A21TJRUUN4KGV).
		if ( ! empty( $meta['marketplace_id'] ) && ! preg_match( '/^[A-Z0-9]{10,15}$/', $meta['marketplace_id'] ) ) {
			throw new \InvalidArgumentException( 'Invalid marketplace_id format. Expected alphanumeric string 10-15 characters.' );
		}

		// Validate language_tag format (e.g., en_US, en_IN, de_DE).
		if ( ! empty( $meta['language_tag'] ) && ! preg_match( '/^[a-z]{2}_[A-Z]{2}$/', $meta['language_tag'] ) ) {
			throw new \InvalidArgumentException( 'Invalid language_tag format. Expected format: xx_XX (e.g., en_US).' );
		}
	}

	/**
	 * Get default language tag for a marketplace.
	 *
	 * @param string $marketplace_id Amazon marketplace ID.
	 * @return string Default language tag.
	 */
	private function get_default_language_for_marketplace( string $marketplace_id ): string {
		// Map common Amazon marketplaces to their default languages.
		$marketplace_languages = array(
			'ATVPDKIKX0DER'  => 'en_US', // US.
			'A2EUQ1WTGCTBG2' => 'en_CA', // Canada.
			'A1AM78C64UM0Y8' => 'es_MX', // Mexico.
			'A1RKKUPIHCS9HS' => 'es_ES', // Spain.
			'A13V1IB3VIYZZH' => 'fr_FR', // France.
			'A1PA6795UKMFR9' => 'de_DE', // Germany.
			'APJ6JRA9NG5V4'  => 'it_IT', // Italy.
			'A1F83G8C2ARO7P' => 'en_GB', // UK.
			'A21TJRUUN4KGV'  => 'en_IN', // India.
			'A1VC38T7YXB528' => 'ja_JP', // Japan.
			'AAHKV2X7AFYLW'  => 'zh_CN', // China.
			'A39IBJ37TRP1C6' => 'en_AU', // Australia.
		);

		return $marketplace_languages[ $marketplace_id ] ?? 'en_US';
	}
}
