<?php
/**
 * PostGate Bridge Signer Class
 *
 * This file contains the bridge communication security class that handles
 * HMAC signing for authenticated requests to the PostGate Bridge server.
 *
 * @package PostGate
 * @subpackage BridgeIntegration
 * @since 1.0.0
 * @author QodeSphere
 * @license GPL-2.0+
 */

defined( 'ABSPATH' ) || exit;

/**
 * PostGate Bridge Signer Class
 *
 * Builds HMAC headers and performs signed POSTs to the relay (bridge) server.
 * Provides secure communication between the WordPress plugin and the
 * PostGate Bridge server using HMAC authentication.
 *
 * All requests to the bridge server are signed with a shared secret
 * to ensure authenticity and prevent unauthorized access.
 *
 * @since 1.0.0
 */
class PostGate_Bridge_Signer {

	/**
	 * Build HMAC headers required by the relay.
	 *
	 * Generates the necessary authentication headers for communicating
	 * with the PostGate Bridge server. Uses HMAC-SHA256 signing with
	 * the shared secret for request authentication.
	 *
	 * @since 1.0.0
	 * @param string $method HTTP method (e.g., 'POST').
	 * @param string $path   Path on the bridge (e.g., '/connect').
	 * @param string $body   Raw JSON body string.
	 * @return array         Associative array of headers to merge into wp_remote_post().
	 */
	public static function headers( string $method, string $path, string $body ): array {
		$site_key = get_option( 'postgate_install_key' );

		if ( ! class_exists( 'PostGate_Bridge_Config' ) ) {
			return [];
		}

		$secret = PostGate_Bridge_Config::shared_secret();

		if ( empty( $site_key ) || empty( $secret ) ) {
			return [];
		}

		$ts = (string) time();
		$msg = $method . "\n" . $path . "\n" . $ts . "\n" . $body;
		$sig = hash_hmac( 'sha256', $msg, $secret );

		return [
			'Content-Type' => 'application/json',
			'X-PG-Key' => $site_key,
			'X-PG-Timestamp' => $ts,
			'X-PG-Signature' => $sig,
		];
	}

	/**
	 * Signed POST to the bridge.
	 *
	 * Performs a signed HTTP POST request to the PostGate Bridge server
	 * with HMAC authentication. Handles the response and returns the
	 * decoded JSON data or a WP_Error on failure.
	 *
	 * @since 1.0.0
	 * @param string $path    The API endpoint path on the bridge server.
	 * @param array  $payload The data payload to send in the request body.
	 * @return array|WP_Error The decoded response data or error object.
	 */
	public static function post( string $path, array $payload ) {
		$base = rtrim( (string) PostGate_Bridge_Config::url(), '/' );
		$body = wp_json_encode( $payload );
		$headers = self::headers( 'POST', $path, $body );

		if ( empty( $headers ) || empty( $base ) ) {
			return new WP_Error( 'bridge_not_configured', __( 'Bridge not configured', 'postgate' ) );
		}

		$response = wp_remote_post( $base . $path, [
			'timeout' => 20,
			'headers' => $headers,
			'body' => $body,
		] );

		if ( is_wp_error( $response ) ) {
			return $response;
		}

		$code = (int) wp_remote_retrieve_response_code( $response );
		$json = json_decode( (string) wp_remote_retrieve_body( $response ), true );

		if ( 200 === $code ) {
			return is_array( $json ) ? $json : [];
		}

		return new WP_Error( 'bridge_http_' . $code, $json['error'] ?? __( 'Bridge error', 'postgate' ), $json );
	}
}