<?php
/**
 * Syscom 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\Utils\Utils;

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

/**
 * Class Syscom
 *
 * Handles Syscom supplier app operations (OAuth2 client credentials).
 */
class Syscom extends Base_Supplier_App implements Supplier_App_Interface {

	/**
	 * Constructor
	 */
	public function __construct() {
		parent::__construct( Constants::SUPPLIER_APP_TYPE_SYSCOM );
	}

	/**
	 * Perform Syscom-specific connection test (OAuth2 token).
	 *
	 * @param array $supplier_data Supplier data.
	 * @return array Test result.
	 */
	public function perform_connection_test( $supplier_data ) {
		$details = isset( $supplier_data['details'] ) ? $supplier_data['details'] : $supplier_data;

		$validation_result = $this->validate_supplier_specific_configuration( $details );
		if ( is_wp_error( $validation_result ) ) {
			return $this->get_test_result(
				false,
				sprintf( Constants::SUPPLIER_AUTH_FAILED, $this->supplier_name, $validation_result->get_error_message() ),
			);
		}

		$processed_config = $this->load_and_process_configuration( $details );
		if ( is_wp_error( $processed_config ) ) {
			return $this->get_test_result(
				false,
				sprintf( Constants::SUPPLIER_CONFIG_LOADING_FAILED, $this->supplier_name, $processed_config->get_error_message() ),
			);
		}

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

		$auth_settings     = $authorization['auth_settings'] ?? array();
		$request_settings  = $auth_settings['request_settings'] ?? array();
		$response_settings = $auth_settings['response_settings'] ?? array();

		$access_token_url = $request_settings['access_token_url'] ?? '';
		$client_id        = $details['client_id'] ?? $request_settings['client_id'] ?? '';
		$client_secret    = $details['client_secret'] ?? $request_settings['client_secret'] ?? '';
		$grant_type       = $request_settings['grant_type'] ?? Constants::OAUTH2_GRANT_TYPE_CLIENT_CREDENTIALS;
		$scope            = $request_settings['scope'] ?? '';
		$send_client_cred = $request_settings['send_client_credentials'] ?? Constants::DEFAULT_SEND_CLIENT_CREDENTIALS;

		if ( empty( $access_token_url ) || empty( $client_id ) || empty( $client_secret ) ) {
			return $this->get_test_result(
				false,
				sprintf( Constants::SUPPLIER_AUTH_FAILED, $this->supplier_name, 'Missing OAuth2 client credentials or token URL.' ),
			);
		}

		$request_data = array(
			'grant_type' => $grant_type,
		);

		if ( ! empty( $scope ) ) {
			$request_data['scope'] = $scope;
		}

		$send_in_body   = in_array( 'body', $send_client_cred, true );
		$send_in_header = in_array( 'header', $send_client_cred, true );

		if ( ! $send_in_body && ! $send_in_header ) {
			$send_in_header = true;
		}

		if ( $send_in_body ) {
			$request_data['client_id']     = $client_id;
			$request_data['client_secret'] = $client_secret;
		}

		$auth_headers = array();

		if ( $send_in_header ) {
			$auth_headers[ Constants::DEFAULT_AUTH_HEADER_NAME ] = 'Basic ' . base64_encode( $client_id . ':' . $client_secret ); // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_encode -- OAuth2 Basic scheme per RFC 6749.
		}

		$token_response = API_Service::make_api_call(
			$access_token_url,
			array(
				'method'  => Constants::HTTP_REQUEST_METHOD_POST,
				'headers' => $auth_headers,
				'body'    => $request_data,
				'timeout' => 30,
			)
		);

		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() ),
			);
		}

		$token_body = wp_remote_retrieve_body( $token_response );
		$token_data = json_decode( $token_body, true );
		$token_key  = $response_settings['token_key'] ?? Constants::DEFAULT_TOKEN_KEY;

		if ( ! Utils::is_status_success( $token_response ) ) {
			return $this->get_test_result(
				false,
				sprintf(
					Constants::SUPPLIER_AUTH_FAILED,
					$this->supplier_name,
					wp_remote_retrieve_response_message( $token_response )
				),
				wp_remote_retrieve_response_code( $token_response ),
				$token_data,
			);
		}

		if ( ! $token_data || empty( $token_data[ $token_key ] ) ) {
			return $this->get_test_result(
				false,
				sprintf( Constants::SUPPLIER_AUTH_FAILED, $this->supplier_name, 'Failed to obtain access token. Response: ' . $token_body ),
			);
		}

		return $this->get_test_result(
			true,
			sprintf( Constants::SUPPLIER_AUTH_SUCCESSFUL, $this->supplier_name ),
			wp_remote_retrieve_response_code( $token_response ),
			$token_data,
		);
	}

	/**
	 * Validate Syscom-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 ) {
		if ( empty( $supplier_data['client_id'] ) ) {
			return new WP_Error(
				Constants::ERROR_INVALID_SUPPLIER_CONFIG,
				sprintf( Constants::MSG_MISSING_REQUIRED_FIELD, 'client_id' ),
				array( 'status' => Constants::HTTP_BAD_REQUEST )
			);
		}

		if ( empty( $supplier_data['client_secret'] ) ) {
			return new WP_Error(
				Constants::ERROR_INVALID_SUPPLIER_CONFIG,
				sprintf( Constants::MSG_MISSING_REQUIRED_FIELD, 'client_secret' ),
				array( 'status' => Constants::HTTP_BAD_REQUEST )
			);
		}

		return true;
	}
}
