<?php
/**
 * Promostandards App
 *
 * @category   WordPress_Plugin
 * @package    Common
 * @subpackage Suppliers
 * @author     miniOrange <info@miniorange.com>
 * @license    MIT/Expat
 * @link       https://plugins.miniorange.com/woocommerce-api-product-sync-with-woocommerce-rest-apis
 */

namespace MOWCPS\Common\Suppliers;

use WP_Error;
use MOWCPS\Common\Abstracts\Base_Supplier_App;
use MOWCPS\Common\Interfaces\Supplier_App_Interface;
use MOWCPS\Common\Constants\Constants;
use MOWCPS\Common\Services\API\API_Service;
use MOWCPS\Common\Constants\Plugin_Filters;
use MOWCPS\Common\Utils\Configuration_Loader;
use MOWCPS\Common\Hooks\Promostandards as Promostandards_hooks_class;
use MOWCPS\Common\Factories\Supplier_App_Factory;

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

/**
 * Class Promostandards
 *
 * Handles Promostandards supplier app operations
 */
class Promostandards extends Base_Supplier_App implements Supplier_App_Interface {
	/**
	 * Constructor
	 */
	public function __construct() {
		parent::__construct( Constants::SUPPLIER_APP_TYPE_PROMOSTANDARDS );
		new Promostandards_hooks_class();
	}

	/**
	 * Perform Promostandards-specific connection test
	 *
	 * @param array $supplier_data Supplier data.
	 * @return array Test result.
	 */
	public function perform_connection_test( $supplier_data ) {
		// Validate supplier-specific configuration using existing validation method.
		$ps_supplier_class = $this->get_first_supplier_class( $supplier_data['selected_suppliers'] );

		// Atleast one supplier is selected.
		if ( is_wp_error( $ps_supplier_class ) ) {
			return $ps_supplier_class;
		}

		// Validate only credentials for test.
		if ( empty( $supplier_data['id'] ) ) {
			return $this->get_test_result(
				false,
				sprintf( Constants::SUPPLIER_AUTH_FAILED, $this->supplier_name, 'ID is required for Promostandards.' ),
			);
		}

		if ( empty( $supplier_data['password'] ) ) {
			return $this->get_test_result(
				false,
				sprintf( Constants::SUPPLIER_AUTH_FAILED, $this->supplier_name, 'Password is required for Promostandards.' ),
			);
		}

		$supplier_class        = Supplier_App_Factory::get_class_name_for_app_type( $ps_supplier_class );
		$supplier_class_object = new $supplier_class();
		$processed_config      = $supplier_class_object->get_supplier_config( $supplier_data );

		// Get authorization configuration from processed config.
		$authorization = $processed_config[ Constants::AUTHORIZATION ] ?? array();
		if ( empty( $authorization ) ) {
			return $this->get_test_result(
				false,
				sprintf( Constants::SUPPLIER_NO_AUTH_CONFIG, $this->supplier_name ),
			);
		}

		// Make token request using API Service.
		$token_response = API_Service::make_api_call(
			$processed_config['connections'][0]['configuration']['endpoint'],
			array(
				'method'  => Constants::HTTP_REQUEST_METHOD_POST,
				'headers' => $processed_config['connections'][0]['configuration']['headers'],
				'body'    => $processed_config['connections'][0]['configuration']['body']['data'],
				'timeout' => 600,
			)
		);

		$response_body  = json_decode( wp_remote_retrieve_body( $token_response ), true );
		$token_response = API_Service::parse_xml( $token_response );
		$token_response = json_decode( $token_response, true );

		$response_code = $token_response[0]['GetProductSellableResponse']['ServiceMessageArray']['ServiceMessage']['code'];

		if ( is_wp_error( $token_response ) ) {
			return $this->get_test_result(
				false,
				sprintf( Constants::SUPPLIER_AUTH_FAILED, $this->supplier_name, $token_response->get_error_message() ),
				$response_code,
				$response_body,
			);
		}

		if ( '200' !== $response_code ) {
			return $this->get_test_result(
				false,
				sprintf( Constants::SUPPLIER_AUTH_FAILED, $this->supplier_name, 'Authentication Credentials failed: Invalid Credentials' ),
				$response_code,
				$response_body,
			);
		}

		return $this->get_test_result(
			true,
			sprintf( Constants::SUPPLIER_AUTH_SUCCESSFUL, $this->supplier_name ),
			$response_code,
			$response_body,
		);
	}

	/**
	 * Validate Promostandards-specific configuration
	 *
	 * @param array $supplier_data Supplier data to validate.
	 * @return bool|WP_Error True if valid, WP_Error if invalid.
	 */
	public function validate_supplier_specific_configuration( $supplier_data ) {
		// Validate required fields for Promostandards.
		if ( empty( $supplier_data['id'] ) ) {
			return new WP_Error(
				Constants::ERROR_INVALID_SUPPLIER_CONFIG,
				sprintf( Constants::SUPPLIER_MISSING_DOMAIN, $this->supplier_name ),
				array( 'status' => Constants::HTTP_BAD_REQUEST )
			);
		}

		if ( empty( $supplier_data['password'] ) ) {
			return new WP_Error(
				Constants::ERROR_INVALID_SUPPLIER_CONFIG,
				sprintf( Constants::SUPPLIER_MISSING_ACCESS_TOKEN, $this->supplier_name ),
				array( 'status' => Constants::HTTP_BAD_REQUEST )
			);
		}

		return true;
	}

	/**
	 * Transform dynamic parameters for Promostandards default apps.
	 *
	 * @param array $arguments Arguments.
	 * @return array Transformed arguments.
	 */
	public static function transform_dynamic_params( $arguments ) {
		if ( Plugin_Filters::EVENT_ALTER_DYNAMIC_PARAMS === $arguments['event_specifier'] ) {
			$params = $arguments['dynamic_params'];
			if ( empty( $params['selected_suppliers'][0] ) ) {
				return $arguments;
			}
			$promostandard_app_type = $params['selected_suppliers'][0];
			$config                 = Configuration_Loader::load_supplier_config( $promostandard_app_type );
			if ( is_wp_error( $config ) ) {
				return $arguments;
			}

			// Extract per-connection SOAP bodies (*_body keys) so they do not leak into placeholder replacement as flat params.
			$connection_body_overrides = array();
			$config_without_bodies     = $config;
			foreach ( $config as $key => $value ) {
				if ( ! is_string( $key ) || strlen( $key ) < 6 ) {
					continue;
				}
				if ( '_body' !== substr( $key, -5 ) ) {
					continue;
				}
				if ( ! is_string( $value ) ) {
					continue;
				}
				$prefix                       = substr( $key, 0, -5 );
				$connection_name              = str_replace( '_', ' ', $prefix );
				$connection_body_overrides[ $connection_name ] = $value;
				unset( $config_without_bodies[ $key ] );
			}

			$params['connection_body_overrides'] = $connection_body_overrides;
			$arguments['dynamic_params']         = $config_without_bodies + $params;
		}
		return $arguments;
	}

	/**
	 * Get first supplier class to test creds.
	 *
	 * @param array $selected_suppliers Selected suppliers.
	 * @return string First supplier class.
	 */
	public function get_first_supplier_class( $selected_suppliers ) {
		if ( empty( $selected_suppliers ) ) {
			return new WP_Error(
				Constants::ERROR_INVALID_SUPPLIER_CONFIG,
				sprintf( Constants::SUPPLIER_MISSING ),
				array( 'status' => Constants::HTTP_BAD_REQUEST )
			);
		}

		return $selected_suppliers[0];
	}

	/**
	 * Create each supplier.
	 *
	 * @param array $data Data.
	 * @return void
	 */
	public function create_supplier( $data ) {
		$suppliers     = $data['details']['selected_suppliers'];
		$supplier_name = $data['name'];
		foreach ( $suppliers as $supplier ) {
			$data['details']['selected_suppliers'][0] = $supplier;
			$data['app_type']                         = $supplier;
			$data['name']                             = $supplier_name . ucwords( str_replace( 'promostandards-', ' ', $supplier ) );
			$this->app_type                           = $supplier;
			parent::create_supplier( $data );
		}
	}
}
