<?php
declare(strict_types=1);

namespace DMRS\MBS\Api\License;

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

/**
 * File Path: includes/api/license/class-mbs-license-activation.php
 *
 * License Activation Handler
 *
 * Handles license activation and deactivation against the remote API.
 *
 * @package MyBookShowroom
 * @since 1.0.0
 */

use WP_Error;

/** Class MBS_License_Activation */
final class MBS_License_Activation {

	/**
	 * Activate a license key on this domain.
	 *
	 * POST /license/activate — no HMAC required (first-contact endpoint).
	 * On success, stores all canonical credentials via MBS_License_Credentials.
	 *
	 * @return array|WP_Error Activation response or error.
	 */
	public function activate( string $license_key ): array|WP_Error {
		$license_key = trim( $license_key );
		if ( empty( $license_key ) ) {
			return new WP_Error( 'empty_key', __( 'License key cannot be empty.', 'my-book-showroom' ) );
		}

		$request_body = array(
			'license_key'    => $license_key,
			'domain'         => wp_parse_url( home_url(), PHP_URL_HOST ) ?: '',
			'plugin_version' => defined( 'MBS_VERSION' ) ? MBS_VERSION : '1.0.0',
			'wp_version'     => get_bloginfo( 'version' ),
			'php_version'    => PHP_VERSION,
		);

		$start    = microtime( true );
		$response = wp_remote_post( MBS_API_BASE . '/license/activate', array(
			'headers' => array( 'Content-Type' => 'application/json' ),
			'body'    => wp_json_encode( $request_body ),
			'timeout' => 15,
		) );
		MBS_License_Request_Log::log_and_return( 'activate', $request_body, $response, microtime( true ) - $start );

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

		$http_code = wp_remote_retrieve_response_code( $response );
		$data      = json_decode( wp_remote_retrieve_body( $response ), true );

		if ( $http_code !== 200 || empty( $data['success'] ) ) {
			$error_code = $data['error_code'] ?? 'activation_failed';
			$message    = $data['message']    ?? __( 'License activation failed. Please check the key and try again.', 'my-book-showroom' );
			return new WP_Error( $error_code, $message );
		}

		// Store all credentials via the credentials manager, which writes every
		// canonical option key that the rest of the plugin reads.
		// PLG-055: also pass sites_used / sites_allowed so the License tab can
		// display the "x of 3 sites active" counter immediately after activation.
		$credentials = new MBS_License_Credentials();
		$credentials->store( array(
			'license_key'   => $license_key,
			'api_secret'    => $data['api_secret']    ?? '',
			'nonce'         => $data['nonce']         ?? '',
			'tier'          => $data['tier']          ?? 'free',
			'sites_used'    => $data['sites_used']    ?? -1,
			'sites_allowed' => $data['sites_allowed'] ?? -1,
		) );

		do_action( 'mbs_license_activated', $data['tier'] ?? 'free' ); // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound -- mbs_/MBS_ prefix is correct; scanner not configured with plugin prefix

		return $data;
	}

	/**
	 * Deactivate the license on this domain.
	 *
	 * POST /license/deactivate — HMAC required (S-C2: unconditional on this endpoint).
	 *
	 * The server's verifyHmac() checks for the presence of hmac, timestamp, nonce,
	 * and domain — returning HTTP 401 if any are missing. This method signs the
	 * request identically to MBS_License_Ping::validate() using the stored
	 * api_secret and nonce.
	 *
	 * Local credentials are always cleared regardless of server response so the
	 * site is never left in a half-deactivated state.
	 *
	 * @param string $license_key The license key (empty = read from stored credentials).
	 * @return array|WP_Error
	 */
	public function deactivate( string $license_key = '' ): array|WP_Error {
		$credentials = new MBS_License_Credentials();

		// ── Resolve stored credentials ────────────────────────────────────────
		$raw_key    = \MBS_Encryption::decrypt( get_option( 'mbs_license_key_encrypted', '' ) ) ?: ''; // R1-authorized: license credential machinery -- value not logged.
		$api_secret = \MBS_Encryption::decrypt( get_option( 'mbs_api_secret_encrypted', '' ) )  ?: ''; // R1-authorized: license credential machinery -- value not logged.
		$nonce      = get_option( 'mbs_api_nonce', '' );
		$domain     = wp_parse_url( home_url(), PHP_URL_HOST ) ?: '';

		// If caller passed an explicit key use it, otherwise use the stored one.
		if ( ! empty( $license_key ) ) {
			$raw_key = trim( $license_key );
		}

		// ── Attempt HMAC-signed server deactivation ───────────────────────────
		if ( ! empty( $raw_key ) && ! empty( $api_secret ) ) {
			$timestamp = time();
			$hmac      = \MBS_HMAC::sign_request( $raw_key, $domain, $timestamp, $nonce, $api_secret );

			$request_body = array(
				'license_key' => $raw_key,
				'domain'      => $domain,
				'timestamp'   => $timestamp,
				'nonce'       => $nonce,
				'hmac'        => $hmac,
			);

			$start    = microtime( true );
			$response = wp_remote_post( MBS_API_BASE . '/license/deactivate', array(
				'headers' => array( 'Content-Type' => 'application/json' ),
				'body'    => wp_json_encode( $request_body ),
				'timeout' => 15,
			) );
			MBS_License_Request_Log::log_and_return( 'deactivate', $request_body, $response, microtime( true ) - $start );
			// Server response is intentionally not checked — local clear always
			// happens so the admin is never left unable to deactivate.
		}

		// ── Always clear locally ──────────────────────────────────────────────
		$credentials->clear();

		do_action( 'mbs_license_deactivated' ); // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound -- mbs_/MBS_ prefix is correct; scanner not configured with plugin prefix

		return array( 'success' => true );
	}
}
