<?php
/**
 * License — remove footer credit (R$ 29,90).
 *
 * Optional public credit: “Powered by Auranet Builder”.
 * A valid license key hides the credit site-wide.
 *
 * @package AuraBuilder
 */

declare(strict_types=1);

namespace AuraBuilder\Licensing;

final class License {

	public const OPTION_KEY       = 'aptb_license_key';
	public const OPTION_STATUS    = 'aptb_license_status';
	public const OPTION_DOMAIN    = 'aptb_license_domain';
	public const OPTION_ACTIVATED = 'aptb_license_activated_at';

	/** Product SKU for key payload. */
	public const PRODUCT = 'ab-credit-remove';

	/**
	 * Price shown in admin (BRL). Payment is handled on Auranet site.
	 */
	public const PRICE_BRL = '29,90';

	/**
	 * Public product / plugin page (credit link + buy).
	 */
	public const PLUGIN_URL = 'https://www.auranet.com.br/aura-builder/';

	/**
	 * Checkout for credit removal (update when store is live).
	 */
	public const BUY_URL = 'https://www.auranet.com.br/aura-builder/remover-credito/';

	/**
	 * Policy page on Auranet (mirror of in-plugin policy).
	 */
	public const POLICY_URL = 'https://www.auranet.com.br/aura-builder/politica-de-uso/';

	/**
	 * HMAC salt for domain-bound keys. Override in wp-config for your key server:
	 * define( 'AURA_BUILDER_LICENSE_SALT', '...' );
	 *
	 * Keys are not high-security DRM — they deter casual removal for a low price.
	 */
	private const DEFAULT_SALT = 'auranet-ab-v1-credit-remove-2026';

	public static function hooks(): void {
		// nothing global yet — SettingsPage handles form.
	}

	public static function salt(): string {
		if ( defined( 'AURA_BUILDER_LICENSE_SALT' ) && is_string( AURA_BUILDER_LICENSE_SALT ) && AURA_BUILDER_LICENSE_SALT !== '' ) {
			return AURA_BUILDER_LICENSE_SALT;
		}
		/**
		 * Filter license salt (use only on your sales key generator, not public sites).
		 *
		 * @param string $salt Salt.
		 */
		return (string) apply_filters( 'aptb_license_salt', self::DEFAULT_SALT );
	}

	/**
	 * Host used for binding keys (lowercase, no www).
	 */
	public static function site_domain( ?string $url = null ): string {
		$home = $url ?? home_url( '/' );
		$host = wp_parse_url( $home, PHP_URL_HOST );
		if ( ! is_string( $host ) || $host === '' ) {
			// phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- sanitized below.
			$raw  = isset( $_SERVER['HTTP_HOST'] ) ? wp_unslash( (string) $_SERVER['HTTP_HOST'] ) : 'localhost';
			$host = sanitize_text_field( $raw );
		}
		$host = strtolower( $host );
		if ( str_starts_with( $host, 'www.' ) ) {
			$host = substr( $host, 4 );
		}
		return $host;
	}

	/**
	 * Expected key for a domain (for generator scripts / admin helper).
	 * Format: AB1-XXXX-XXXX-XXXX (12 hex chars in groups of 4).
	 */
	public static function expected_key_for_domain( string $domain ): string {
		$domain = strtolower( $domain );
		if ( str_starts_with( $domain, 'www.' ) ) {
			$domain = substr( $domain, 4 );
		}
		$raw  = hash_hmac( 'sha256', self::PRODUCT . '|' . $domain, self::salt() );
		$hex  = strtoupper( substr( $raw, 0, 12 ) );
		return 'AB1-' . substr( $hex, 0, 4 ) . '-' . substr( $hex, 4, 4 ) . '-' . substr( $hex, 8, 4 );
	}

	public static function normalize_key( string $key ): string {
		$key = strtoupper( trim( $key ) );
		$key = preg_replace( '/[^A-Z0-9]/', '', $key ) ?? '';
		// Rebuild AB1-XXXX-XXXX-XXXX if body present.
		if ( str_starts_with( $key, 'AB1' ) ) {
			$body = substr( $key, 3 );
		} else {
			$body = $key;
		}
		$body = substr( preg_replace( '/[^A-F0-9]/', '', $body ) ?? '', 0, 12 );
		if ( strlen( $body ) < 12 ) {
			return strtoupper( trim( $key ) ); // keep raw for remote/error display
		}
		return 'AB1-' . substr( $body, 0, 4 ) . '-' . substr( $body, 4, 4 ) . '-' . substr( $body, 8, 4 );
	}

	/**
	 * Whether this installation may hide the public credit.
	 */
	public static function is_licensed(): bool {
		/**
		 * Force licensed (e.g. agency multisite).
		 *
		 * @param bool $licensed Licensed.
		 */
		$forced = apply_filters( 'aptb_is_licensed', null );
		if ( is_bool( $forced ) ) {
			return $forced;
		}

		$key = (string) get_option( self::OPTION_KEY, '' );
		if ( $key === '' ) {
			return false;
		}

		$status = (string) get_option( self::OPTION_STATUS, '' );
		if ( $status === 'valid' && self::validate_key( $key ) ) {
			return true;
		}

		// Re-validate if domain moved or status stale.
		if ( self::validate_key( $key ) ) {
			update_option( self::OPTION_STATUS, 'valid', false );
			update_option( self::OPTION_DOMAIN, self::site_domain(), false );
			return true;
		}

		return false;
	}

	/**
	 * Validate key for current (or given) domain.
	 */
	public static function validate_key( string $key, ?string $domain = null ): bool {
		$key    = self::normalize_key( $key );
		$domain = $domain ?? self::site_domain();
		if ( ! preg_match( '/^AB1-[A-F0-9]{4}-[A-F0-9]{4}-[A-F0-9]{4}$/', $key ) ) {
			return false;
		}
		$expected = self::expected_key_for_domain( $domain );
		$ok       = hash_equals( $expected, $key );

		/**
		 * Allow custom validators (remote license server, etc.).
		 *
		 * @param bool   $ok     Valid.
		 * @param string $key    Normalized key.
		 * @param string $domain Domain.
		 */
		return (bool) apply_filters( 'aptb_validate_license_key', $ok, $key, $domain );
	}

	/**
	 * Activate key: store if valid.
	 *
	 * @return true|\WP_Error
	 */
	public static function activate( string $key ) {
		$key = self::normalize_key( $key );
		if ( $key === '' || $key === 'AB1-' ) {
			return new \WP_Error( 'ab_license_empty', __( 'Informe a chave de licença.', 'auranet-page-theme-builder' ) );
		}
		if ( ! self::validate_key( $key ) ) {
			return new \WP_Error(
				'ab_license_invalid',
				sprintf(
					/* translators: %s: site domain */
					__( 'Chave inválida para o domínio %s. Compre em auranet.com.br e use a chave gerada para este site.', 'auranet-page-theme-builder' ),
					self::site_domain()
				)
			);
		}
		update_option( self::OPTION_KEY, $key, false );
		update_option( self::OPTION_STATUS, 'valid', false );
		update_option( self::OPTION_DOMAIN, self::site_domain(), false );
		update_option( self::OPTION_ACTIVATED, gmdate( 'c' ), false );
		return true;
	}

	public static function deactivate(): void {
		delete_option( self::OPTION_KEY );
		delete_option( self::OPTION_STATUS );
		delete_option( self::OPTION_DOMAIN );
		delete_option( self::OPTION_ACTIVATED );
	}

	public static function stored_key(): string {
		return (string) get_option( self::OPTION_KEY, '' );
	}

	/**
	 * Masked key for display.
	 */
	public static function masked_key(): string {
		$key = self::stored_key();
		if ( $key === '' ) {
			return '';
		}
		// AB1-XXXX-XXXX-YYYY → AB1-••••-••••-YYYY
		$parts = explode( '-', $key );
		if ( count( $parts ) === 4 ) {
			return $parts[0] . '-••••-••••-' . $parts[3];
		}
		return '••••';
	}
}
