<?php
/**
 * Amazon Token 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\Models\Multichannels_Model;
use MOMCS_Sync\Includes\Common\Models\Authentication_Details_Model;
use MOMCS_Sync\Includes\Common\Services\Handlers\Api_Handler;
use MOMCS_Sync\Includes\Common\Constants\Plugin_Constants;
use MOMCS_Sync\Includes\Common\Handlers\Crypto_Handler;

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

/**
 * Class for handling Amazon token operations.
 */
class Token_Service {

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

	/**
	 * Multichannels model instance.
	 *
	 * @var Multichannels_Model
	 */
	private $multichannels_model;

	/**
	 * Authentication Details model instance.
	 *
	 * @var Authentication_Details_Model
	 */
	private $auth_details_model;

	/**
	 * Token endpoint.
	 *
	 * @var string
	 */
	private $token_endpoint = '';

	/**
	 * Constructor.
	 */
	public function __construct() {
		$this->api_handler         = new Api_Handler();
		$this->multichannels_model = new Multichannels_Model();
		$this->auth_details_model  = new Authentication_Details_Model();
		$this->token_endpoint      = rtrim( Plugin_Constants::BROKER_BASE_URL, '/' ) . Plugin_Constants::BROKER_TOKEN_PATH;
	}

	/**
	 * Get access token for Amazon API.
	 *
	 * @param string $channel_id Channel UUID.
	 * @return string|\WP_Error Access token or error.
	 */
	public function get_access_token( $channel_id ) {
		// Attempt to read cached access token (encrypted) from transient.
		$cached_encrypted = get_transient( Plugin_Constants::TRANSIENT_ACCESS_TOKEN . $channel_id );
		if ( is_string( $cached_encrypted ) && '' !== $cached_encrypted ) {
			$cached_decrypted = Crypto_Handler::decrypt( $cached_encrypted );
			if ( '' !== $cached_decrypted ) {
				return $cached_decrypted;
			}
		}

		// Get channel data.
		$channel = $this->multichannels_model->get_channel_by_uuid( $channel_id );
		if ( ! $channel ) {
			return new \WP_Error( 'channel_not_found', 'Channel not found.' );
		}

		// Get authentication details from separate table.
		$auth_details = $this->auth_details_model->get_auth_by_uuid( $channel_id );
		if ( ! $auth_details ) {
			return new \WP_Error( 'auth_not_found', 'Authentication details not found.' );
		}

		$encrypted_refresh_token = $auth_details['authentication'];
		$refresh_token           = Crypto_Handler::decrypt( $encrypted_refresh_token );
		if ( empty( $refresh_token ) ) {
			return new \WP_Error( 'refresh_token_missing', 'Refresh token is missing.' );
		}

		// Prepare request data for broker.
		$request_data = array(
			'grant_type'    => 'refresh_token',
			'refresh_token' => $refresh_token,
		);

		// Make API request.
		$response = $this->api_handler->post(
			$this->token_endpoint,
			$request_data,
			array(
				'Content-Type' => 'application/x-www-form-urlencoded',
			)
		);

		// Check for errors.
		if ( is_wp_error( $response ) ) {
			return $response;
		}

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

		// Cache the token.
		$expires_in       = isset( $body['expires_in'] ) ? (int) $body['expires_in'] : 3600;
		$encrypted_access = Crypto_Handler::encrypt( $body['access_token'] );
		set_transient( Plugin_Constants::TRANSIENT_ACCESS_TOKEN . $channel_id, $encrypted_access, 3540 );

		return $body['access_token'];
	}

	/**
	 * Get client ID.
	 *
	 * @return string Client ID.
	 */
	private function get_client_id() {
		return '';
	}

	/**
	 * Get client secret.
	 *
	 * @return string Client secret.
	 */
	private function get_client_secret() {
		return '';
	}

	/**
	 * Check if a string is valid JSON.
	 *
	 * @param string $string String to check.
	 * @return bool Whether the string is valid JSON.
	 */
	private function is_json( $string ) {
		if ( ! is_string( $string ) || empty( $string ) ) {
			return false;
		}

		json_decode( $string );
		return json_last_error() === JSON_ERROR_NONE;
	}
}
