<?php

if ( ! defined( 'ABSPATH' ) ) {
	exit;
}
/**
 * Handles Zoho authentication for CommerceBird.
 *
 * Provides methods for obtaining and refreshing Zoho access tokens.
 *
 * @since 1.0.0
 */
class CMBIRD_Auth_Zoho {

	/**
	 * Configuration options for Zoho authentication.
	 *
	 * @var array|array[]
	 */
	private array $config;

	/**
	 * Given a raw domain portion from settings, return the normalized value.
	 *
	 * This ensures the rest of the code only needs to deal with lowercase,
	 * trimmed domain strings. It also protects against unexpected data from
	 * wp_options (users typing spaces or upper‑case characters).
	 *
	 * @param string $domain Raw option value.
	 * @return string Normalized domain (lowercase, trimmed).
	 */
	public static function normalize_domain( string $domain ): string {
		return strtolower( trim( $domain ) );
	}

	/**
	 * Accounts base URL for a given Zoho domain.
	 *
	 * Handles the special "ca" (Canada) case which must use the
	 * zohocloud.ca host instead of the normal zoho.{domain} pattern.
	 *
	 * @param string $domain Domain portion (any case / whitespace allowed).
	 * @return string Base accounts URL without trailing slash.
	 */
	public static function get_accounts_base_url( string $domain ): string {
		$norm = self::normalize_domain( $domain );
		if ( 'ca' === $norm ) {
			return 'https://accounts.zohocloud.ca';
		}
		return 'https://accounts.zoho.' . $norm;
	}

	/**
	 * Full token endpoint for a given domain.
	 *
	 * @param string $domain Domain portion (any case / whitespace allowed).
	 * @return string OAuth2 token URL.
	 */
	public static function get_auth_url_for_domain( string $domain ): string {
		return self::get_accounts_base_url( $domain ) . '/oauth/v2/token';
	}

	/**
	 * Full authorization redirect endpoint for a given domain.
	 *
	 * @param string $domain Domain portion (any case / whitespace allowed).
	 * @return string OAuth2 auth URL.
	 */
	public static function get_auth_redirect_url_for_domain( string $domain ): string {
		return self::get_accounts_base_url( $domain ) . '/oauth/v2/auth';
	}

	/**
	 * Constructor for the CMBIRD_Auth_Zoho class.
	 *
	 * Sets up the object properties from the WordPress options table.
	 *
	 * @since 1.0.0
	 */
	public function __construct() {
		// domain options are normalised via helper so the logic lives in one.
		// place and tests can cover it directly.
		$zi_domain   = self::normalize_domain( (string) get_option( 'cmbird_zoho_inventory_domain', '' ) );
		$zcrm_domain = self::normalize_domain( (string) get_option( 'cmbird_zoho_crm_domain', '' ) );

		$config = array(

			'ServiceZI'   => array(
				'OID'          => get_option( 'cmbird_zoho_inventory_oid' ),
				'CLIENTSECRET' => get_option( 'cmbird_zoho_inventory_cs' ),
				'CLIENTID'     => get_option( 'cmbird_zoho_inventory_cid' ),
				'REDIRECTURL'  => get_option( 'cmbird_authorization_redirect_uri' ),
				'APIURL'       => get_option( 'cmbird_zoho_inventory_url' ),
				'DOMAINNAME'   => $zi_domain,
				'SCOPE'        => 'ZohoInventory.FullAccess.all',
				// 'STATE' => wp_create_nonce('redirect_url'),.
				'AUTHURL'      => self::get_auth_url_for_domain( $zi_domain ),

			),
			'ServiceZCRM' => array(
				'CLIENTSECRET' => get_option( 'cmbird_zoho_crm_cs' ),
				'CLIENTID'     => get_option( 'cmbird_zoho_crm_cid' ),
				'REDIRECTURL'  => get_option( 'cmbird_authorization_redirect_uri' ),
				'APIURL'       => get_option( 'cmbird_zoho_crm_url' ),
				'DOMAINNAME'   => $zcrm_domain,
				'SCOPE'        => 'ZohoCRM.users.ALL,ZohoCRM.bulk.ALL,ZohoCRM.modules.ALL,ZohoCRM.settings.ALL,ZohoCRM.org.ALL,profile.userphoto.READ,ZohoFiles.files.CREATE',
				// 'STATE' => wp_create_nonce('redirect_url'),.
				'AUTHURL'      => self::get_auth_url_for_domain( $zcrm_domain ),
			),

		);

		$this->config = $config;
	}

	/**
	 * Expose configuration for testing or debugging.
	 *
	 * @return array The internal Zoho auth configuration.
	 */
	public function get_config(): array {
		return $this->config;
	}

	/**
	 * Retrieves the access token for the given Zoho application.
	 *
	 * @param string $code The authorization code from Zoho.
	 * @param string $app_name The name of the Zoho application (e.g. 'zoho_inventory', 'zoho_crm').
	 *
	 * @return array|\WP_Error The decoded JSON response from the Zoho API, or a WP_Error object on failure.
	 */
	public function get_zoho_access_token( $code, $app_name ) {

		$headers = array( 'Content-Type: application/x-www-form-urlencoded' );
		switch ( $app_name ) {
			case 'zoho_inventory':
				$params = array(
					'code'          => $code,
					'client_id'     => $this->config['ServiceZI']['CLIENTID'],
					'client_secret' => $this->config['ServiceZI']['CLIENTSECRET'],
					'redirect_uri'  => $this->config['ServiceZI']['REDIRECTURL'],
					'scope'         => $this->config['ServiceZI']['SCOPE'],
					'grant_type'    => 'authorization_code',
				);
				$url    = $this->config['ServiceZI']['AUTHURL'];
				break;
			default:
				$params = array(
					'code'          => $code,
					'client_id'     => $this->config['ServiceZCRM']['CLIENTID'],
					'client_secret' => $this->config['ServiceZCRM']['CLIENTSECRET'],
					'redirect_uri'  => $this->config['ServiceZCRM']['REDIRECTURL'],
					'scope'         => $this->config['ServiceZCRM']['SCOPE'],
					'grant_type'    => 'authorization_code',
				);
				$url    = $this->config['ServiceZCRM']['AUTHURL'];
				break;
		}

		// Set up the request arguments.
		$args = array(
			'headers' => $headers,
			'body'    => $params,
			'method'  => 'POST',
		);

		// Debug: Log the domain and auth URL being used.
		if ( function_exists( 'wc_get_logger' ) ) {
			$logger       = wc_get_logger();
			$domain_label = 'zoho_inventory' === $app_name ? $this->config['ServiceZI']['DOMAINNAME'] : $this->config['ServiceZCRM']['DOMAINNAME'];
			$logger->debug( 'CommerceBird Auth Debug - App: ' . $app_name . ', Domain: ' . $domain_label . ', Auth URL: ' . $url, array( 'source' => 'commercebird' ) );
		}

		// Make the request using wp_remote_post().
		$response = wp_remote_post( $url, $args );

		if ( is_wp_error( $response ) ) {
			if ( function_exists( 'wc_get_logger' ) ) {
				$logger = wc_get_logger();
				$logger->error( 'CommerceBird Access Token Error - App: ' . $app_name . ', Error: ' . $response->get_error_message(), array( 'source' => 'commercebird' ) );
			}

			return $response;
		}

		$body         = wp_remote_retrieve_body( $response );
		$status_code  = wp_remote_retrieve_response_code( $response );
		$decoded_body = json_decode( $body, true );

		if ( 200 === $status_code ) {
			if ( is_array( $decoded_body ) ) {
				return $decoded_body;
			}

			return new \WP_Error( 'zoho_access_token_error', 'Invalid Zoho token response received.' );
		}

		$error_message = 'Unknown error.';
		if ( is_array( $decoded_body ) ) {
			$error_message = $decoded_body['error_description'] ?? $decoded_body['message'] ?? $decoded_body['error'] ?? $error_message;
		}

		if ( function_exists( 'wc_get_logger' ) ) {
			$logger = wc_get_logger();
			$logger->error( 'CommerceBird Access Token Error - App: ' . $app_name . ', Error: ' . $error_message, array( 'source' => 'commercebird' ) );
		}

		return new \WP_Error( 'zoho_access_token_error', $error_message, array( 'status' => $status_code ) );
	}


	/**
	 * Retrieves a new access token for the given app using the refresh token.
	 *
	 * @param string $refresh_token The refresh token to use for the request.
	 * @param string $app_name The name of the app to retrieve the access token for (e.g. 'zoho_inventory', 'zoho_crm').
	 *
	 * @return object|\WP_Error The JSON response from the request, or an error message if there was an error.
	 */
	public function get_zoho_refresh_token( $refresh_token, $app_name ) {
		$headers = array( 'Content-Type: application/x-www-form-urlencoded' );

		$client_id  = 'zoho_inventory' === $app_name ? $this->config['ServiceZI']['CLIENTID'] : $this->config['ServiceZCRM']['CLIENTID'];
		$client_sec = 'zoho_inventory' === $app_name ? $this->config['ServiceZI']['CLIENTSECRET'] : $this->config['ServiceZCRM']['CLIENTSECRET'];
		$params     = array(
			'refresh_token' => $refresh_token,
			'grant_type'    => 'refresh_token',
			'client_id'     => $client_id,
			'client_secret' => $client_sec,
		);
		$url        = 'zoho_inventory' === $app_name ? $this->config['ServiceZI']['AUTHURL'] : $this->config['ServiceZCRM']['AUTHURL'];
		// Set up the request arguments.
		$args = array(
			'headers' => $headers,
			'body'    => $params,
			'method'  => 'POST',
		);

		// Debug: Log the domain and auth URL being used for refresh token.
		if ( function_exists( 'wc_get_logger' ) ) {
			$logger       = wc_get_logger();
			$domain_label = 'zoho_inventory' === $app_name ? $this->config['ServiceZI']['DOMAINNAME'] : $this->config['ServiceZCRM']['DOMAINNAME'];
			$logger->debug( 'CommerceBird Refresh Token Debug - App: ' . $app_name . ', Domain: ' . $domain_label . ', Auth URL: ' . $url, array( 'source' => 'commercebird' ) );
		}

		// Make the request using wp_remote_post().
		$response = wp_remote_post( $url, $args );
		// Check if the request was successful.
		if ( ! is_wp_error( $response ) && wp_remote_retrieve_response_code( $response ) === 200 ) {
			// If successful, get the body of the response.
			$body = wp_remote_retrieve_body( $response );
			// Decode JSON response.
			return json_decode( $body, true );
		} else {
			// If there was an error, handle it.
			$error_message = is_wp_error( $response ) ? $response->get_error_message() : 'Unknown error.';
			if ( function_exists( 'wc_get_logger' ) ) {
				$logger = wc_get_logger();
				$logger->error( 'CommerceBird Refresh Token Error - App: ' . $app_name . ', Error: ' . $error_message, array( 'source' => 'commercebird' ) );
			}
			// return the WP Error object.
			return new \WP_Error( 'zoho_refresh_token_error', $error_message );
		}
	}
}

$cmbird_handlefunction = new CMBIRD_Auth_Zoho();
