<?php
defined( 'ABSPATH' ) || exit;

/**
 * License manager for Woocom-Pay Pro.
 *
 * Validates license keys server-side via an n8n webhook that checks
 * a Google Sheet of sold keys. Result is cached for 24 hours.
 *
 * Key format: WCPP-XXXXXXXX-XXXXXXXX
 */
class WCP_License {

	const OPTION        = 'wcp_license_key';
	const TRANSIENT     = 'wcp_license_valid';
	const CACHE_HOURS   = 24;
	const WEBHOOK_URL   = 'https://n8n.srv1578560.hstgr.cloud/webhook/wcp-license-validate';

	/**
	 * Returns true when a valid Pro key is saved and confirmed by the server.
	 */
	public static function is_pro(): bool {
		static $result = null;
		if ( $result !== null ) {
			return $result;
		}

		$key = get_option( self::OPTION, '' );
		if ( empty( $key ) || ! self::is_valid_format( $key ) ) {
			$result = false;
			return false;
		}

		// Check transient cache first.
		$cache_key = 'wcp_lv_' . substr( md5( $key ), 0, 12 );
		$cached    = get_transient( $cache_key );
		if ( $cached !== false ) {
			$result = ( $cached === 'yes' );
			return $result;
		}

		// Call the n8n validation webhook.
		$valid  = self::validate_remote( $key );
		$result = $valid;

		// Cache for 24 hours.
		set_transient( $cache_key, $valid ? 'yes' : 'no', self::CACHE_HOURS * HOUR_IN_SECONDS );

		return $result;
	}

	/**
	 * Call the n8n webhook to validate the key server-side.
	 * Returns false on any error or timeout (fail closed).
	 */
	private static function validate_remote( string $key ): bool {
		$response = wp_remote_post(
			self::WEBHOOK_URL,
			[
				'timeout'     => 8,
				'headers'     => [ 'Content-Type' => 'application/json' ],
				'body'        => wp_json_encode( [
					'key'  => strtoupper( trim( $key ) ),
					'site' => home_url(),
				] ),
				'data_format' => 'body',
			]
		);

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

		if ( wp_remote_retrieve_response_code( $response ) !== 200 ) {
			return false;
		}

		$body = json_decode( wp_remote_retrieve_body( $response ), true );
		return ! empty( $body['valid'] ) && $body['valid'] === true;
	}

	/**
	 * Basic format check before hitting the server.
	 * WCPP-XXXXXXXX-XXXXXXXX (8 hex chars each segment).
	 */
	public static function is_valid_format( string $key ): bool {
		return (bool) preg_match( '/^WCPP-[A-F0-9]{8}-[A-F0-9]{8}$/i', trim( $key ) );
	}

	/**
	 * Save and activate a license key. Hits server to confirm before saving.
	 * Returns true on success.
	 */
	public static function activate( string $key ): bool {
		$key = strtoupper( trim( $key ) );

		if ( ! self::is_valid_format( $key ) ) {
			return false;
		}

		if ( ! self::validate_remote( $key ) ) {
			return false;
		}

		update_option( self::OPTION, $key );

		// Seed the cache immediately so the next page load is instant.
		$cache_key = 'wcp_lv_' . substr( md5( $key ), 0, 12 );
		set_transient( $cache_key, 'yes', self::CACHE_HOURS * HOUR_IN_SECONDS );

		return true;
	}

	/**
	 * Remove the stored license key and clear its cache.
	 */
	public static function deactivate(): void {
		$key = get_option( self::OPTION, '' );
		if ( $key ) {
			$cache_key = 'wcp_lv_' . substr( md5( $key ), 0, 12 );
			delete_transient( $cache_key );
		}
		delete_option( self::OPTION );
	}

	/**
	 * Return the currently stored key (masked for display).
	 * e.g. WCPP-****-ABCD1234
	 */
	public static function masked_key(): string {
		$key = get_option( self::OPTION, '' );
		if ( empty( $key ) ) {
			return '';
		}
		$parts    = explode( '-', $key );
		$parts[1] = '********';
		return implode( '-', $parts );
	}

	/**
	 * Generate a valid key (for the CLI generator script).
	 * Still uses HMAC locally for key generation — only validation is server-side.
	 */
	public static function generate(): string {
		$part1 = strtoupper( bin2hex( random_bytes( 4 ) ) );
		$part2 = strtoupper( substr( hash_hmac( 'sha256', $part1, self::generator_secret() ), 0, 8 ) );
		return "WCPP-{$part1}-{$part2}";
	}

	private static function generator_secret(): string {
		return implode( '', [ 'T2M', chr( 35 ), 'wCp', chr( 64 ), '2O26', chr( 36 ), 'pRo', chr( 33 ), 'Key' ] );
	}
}
