<?php
/**
 * MEM API communication class.
 *
 * Handles all HTTP communication between the WooCommerce plugin
 * and the MEM platform, including store connection, disconnection,
 * and WooCommerce REST API key management.
 *
 * @package Memwc_Connector
 * @since   1.0.0
 */

defined( 'ABSPATH' ) || exit;

/**
 * Class Memwc_Api
 *
 * Static methods for MEM API communication.
 */
class Memwc_Api {

	/**
	 * Verify whether the current store is connected to MEM.
	 *
	 * Calls the MEM API with the store URL to check connection status.
	 * If the API confirms the store is connected it returns the connection
	 * data; otherwise it returns false so the admin UI can show the
	 * "not connected" state.
	 *
	 * @return array|false Connection data array on success, false when not connected.
	 */
	public static function verify_connection() {
		$store_url = esc_url_raw( home_url() );

		$response = wp_remote_post(
			self::get_api_url( '/api/woocommerce/verify-connection' ),
			array(
				'timeout' => 15,
				'headers' => array(
					'Content-Type' => 'application/json',
					'Accept'       => 'application/json',
				),
				'body'    => wp_json_encode( array(
					'storeUrl' => $store_url,
				) ),
			)
		);

		if ( is_wp_error( $response ) ) {
			if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) {
				error_log( 'MEM Connector: verify_connection failed — ' . $response->get_error_message() ); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log
			}
			return false;
		}

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

		if ( $code < 200 || $code >= 300 || empty( $body['data']['isConnected'] ) ) {
			return false;
		}

		// A store secret is required to sign future requests (disconnect,
		// update-store-details). Without it the connection is unusable, so
		// treat the response as "not connected" rather than flipping the
		// local flag into a half-broken state.
		$store_secret = sanitize_text_field( $body['data']['storeSecret'] ?? '' );

		if ( empty( $store_secret ) ) {
			if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) {
				error_log( 'MEM Connector: verify_connection succeeded but no store secret was returned; refusing to mark connected.' ); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log
			}
			return false;
		}

		update_option( 'memwc_connector_connected', true, true );
		update_option( 'memwc_connector_connected_at', current_time( 'mysql' ), false );
		update_option( 'memwc_connector_api_base_url', self::get_api_url( '' ), false );
		update_option( 'memwc_connector_store_secret', $store_secret, false );

		// Restore shop URL if empty (e.g. wiped by a previous bug with the disabled form field).
		if ( empty( get_option( 'memwc_shop_url', '' ) ) ) {
			update_option( 'memwc_shop_url', esc_url_raw( get_site_url() ), false );
		}

		return $body['data'];
	}

	/**
	 * Disconnect the store from MEM.
	 *
	 * Notifies MEM via the uninstall endpoint. Local cleanup (webhooks,
	 * API keys, options) only happens when the API confirms success.
	 *
	 * @return true|WP_Error True on success, WP_Error on failure.
	 */
	public static function disconnect() {
		if ( ! Memwc_Connector::is_connected() ) {
			return new WP_Error(
				'mem_not_connected',
				__( 'Store is not connected.', 'my-easy-monogram' )
			);
		}

		$store_secret = get_option( 'memwc_connector_store_secret', '' );

		if ( empty( $store_secret ) ) {
			return new WP_Error(
				'mem_missing_secret',
				__( 'Store secret not found. Please reconnect your store.', 'my-easy-monogram' )
			);
		}

		$json_body = wp_json_encode( array(
			'storeUrl' => home_url(),
		) );

		$signature = self::sign( $store_secret, $json_body );

		$response = wp_remote_post(
			self::get_api_url( '/api/woocommerce/disconnect' ),
			array(
				'timeout'   => 30,
				'blocking'  => true,
				'sslverify' => true,
				'headers'   => array(
					'Content-Type'    => 'application/json',
					'Accept'          => 'application/json',
					'X-MEM-Signature' => $signature,
					'X-MEM-Store-Url' => home_url(),
				),
				'body'      => $json_body,
			)
		);

		if ( is_wp_error( $response ) ) {
			return new WP_Error(
				'mem_disconnect_failed',
				sprintf(
					// translators: %s is the error message returned by the server.
					__( 'Could not reach My Easy Monogram server: %s', 'my-easy-monogram' ),
					$response->get_error_message()
				)
			);
		}

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

		if ( $code < 200 || $code >= 300 ) {
			$message = ( ! empty( $body['message'] ) && is_string( $body['message'] ) )
				? sanitize_text_field( $body['message'] )
				: __( 'Failed to disconnect store. Please try again or contact support.', 'my-easy-monogram' );

			return new WP_Error( 'mem_disconnect_failed', $message );
		}

		// API confirmed success — safe to clean up locally.
		self::cleanup_local_connection();

		return true;
	}

	/**
	 * Send changed store details to MEM.
	 *
	 * Only the fields that have actually changed should be included
	 * in $fields — the backend ignores null/absent fields.
	 *
	 * @param array $fields Associative array of changed fields (camelCase keys).
	 * @return true|WP_Error True on success, WP_Error on failure.
	 */
	public static function update_store_details( $fields ) {
		if ( ! Memwc_Connector::is_connected() || empty( $fields ) ) {
			return new WP_Error( 'mem_not_ready', 'Not connected or no fields to update.' );
		}

		$store_secret = get_option( 'memwc_connector_store_secret', '' );

		if ( empty( $store_secret ) ) {
			return new WP_Error( 'mem_missing_secret', 'Store secret not found.' );
		}

		$json_body = wp_json_encode( $fields );
		$signature = self::sign( $store_secret, $json_body );

		$response = wp_remote_post(
			self::get_api_url( '/api/woocommerce/update-store-details' ),
			array(
				'timeout'   => 15,
				'blocking'  => false,
				'sslverify' => true,
				'headers'   => array(
					'Content-Type'    => 'application/json',
					'Accept'          => 'application/json',
					'X-MEM-Signature' => $signature,
					'X-MEM-Store-Url' => home_url(),
				),
				'body'      => $json_body,
			)
		);

		if ( is_wp_error( $response ) ) {
			if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) {
				error_log( 'MEM Connector: update_store_details failed — ' . $response->get_error_message() ); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log
			}
			return $response;
		}

		return true;
	}

	/**
	 * Compute an HMAC-SHA256 signature for a request body.
	 *
	 * Matches the backend's generateSignature(secret, rawBody) which
	 * returns Base64-encoded HMAC-SHA256.
	 *
	 * @param string $secret   The store secret.
	 * @param string $raw_body The raw JSON request body.
	 * @return string Base64-encoded HMAC-SHA256 signature.
	 */
	public static function sign( $secret, $raw_body ) {
		$hash = hash_hmac( 'sha256', $raw_body, $secret, true );
		return base64_encode( $hash );
	}

	/**
	 * Remove all local connection data (webhooks, API keys, options).
	 *
	 * Extracted so uninstall.php can also call it independently.
	 */
	public static function cleanup_local_connection() {
		Memwc_Webhooks::remove_all_webhooks();

		$api_key_id = get_option( 'memwc_connector_api_key_id' );
		if ( $api_key_id ) {
			self::revoke_wc_api_keys( $api_key_id );
		}

		delete_option( 'memwc_connector_connected' );
		delete_option( 'memwc_connector_connected_at' );
		delete_option( 'memwc_connector_store_secret' );
		delete_option( 'memwc_connector_store_snapshot' );
		delete_option( 'memwc_connector_webhook_url' );
		delete_option( 'memwc_connector_api_key_id' );
		delete_option( 'memwc_connector_api_base_url' );
	}

	/**
	 * Revoke (delete) a WooCommerce API key.
	 *
	 * @param int $key_id The API key ID to revoke.
	 * @return void
	 */
	private static function revoke_wc_api_keys( $key_id ) {
		global $wpdb;

		$wpdb->delete( // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
			$wpdb->prefix . 'woocommerce_api_keys',
			array( 'key_id' => absint( $key_id ) ),
			array( '%d' )
		);
	}

	/**
	 * Build the full MEM API URL for an endpoint.
	 *
	 * The base URL is controlled by the MEMWC_API_URL constant, which should be
	 * defined in wp-config.php for local or UAT environments. If not defined,
	 * it defaults to the production URL.
	 *
	 * Examples for wp-config.php:
	 *   Local:  define( 'MEMWC_API_URL', 'https://your-ngrok-url.ngrok-free.app' );
	 *   UAT:    define( 'MEMWC_API_URL', 'https://uat.myeasymonogram.com' );
	 *   Prod:   (omit — plugin uses https://app.myeasymonogram.com by default)
	 *
	 * @param string $endpoint API endpoint path (e.g., '/api/woocommerce/connect').
	 * @return string Full URL.
	 */
	public static function get_api_url( $endpoint = '' ) {
		$base_url = defined( 'MEMWC_API_URL' ) ? MEMWC_API_URL : 'https://app.myeasymonogram.com';

		/**
		 * Filter the MEM API base URL.
		 *
		 * @since 1.0.0
		 *
		 * @param string $base_url The base URL for the MEM API.
		 */
		$base_url = apply_filters( 'memwc_connector_api_url', $base_url );

		return esc_url_raw( untrailingslashit( $base_url ) . '/' . ltrim( $endpoint, '/' ) );
	}
}
