<?php
/**
 * AES-256-GCM authenticated encryption for sensitive settings.
 *
 * The key is derived from wp-config AUTH_KEY + the per-install secret stored in wp_options,
 * never persisted alongside the ciphertext. Tampered ciphertexts fail to decrypt (GCM tag).
 *
 * @package SuiteMkt3k
 */

namespace SuiteMkt3k\Security;

defined( 'ABSPATH' ) || exit;

final class Encryption {

	private const CIPHER       = 'aes-256-gcm';
	private const VERSION_TAG  = 'WMK1';
	private const NONCE_BYTES  = 12;
	private const TAG_BYTES    = 16;

	public static function is_encrypted( string $value ): bool {
		return 0 === strpos( $value, self::VERSION_TAG . '|' );
	}

	public static function encrypt( string $plaintext ): string {
		if ( '' === $plaintext ) {
			return '';
		}
		if ( ! function_exists( 'openssl_encrypt' ) ) {
			return self::fallback_encode( $plaintext );
		}

		$key   = self::derive_key();
		$iv    = random_bytes( self::NONCE_BYTES );
		$tag   = '';
		$cipher = openssl_encrypt(
			$plaintext,
			self::CIPHER,
			$key,
			OPENSSL_RAW_DATA,
			$iv,
			$tag,
			'',
			self::TAG_BYTES
		);
		if ( false === $cipher ) {
			return self::fallback_encode( $plaintext );
		}

		return self::VERSION_TAG . '|' . base64_encode( $iv . $tag . $cipher );
	}

	public static function decrypt( string $payload ): string {
		if ( '' === $payload ) {
			return '';
		}
		if ( ! self::is_encrypted( $payload ) ) {
			return $payload;
		}
		if ( ! function_exists( 'openssl_decrypt' ) ) {
			return '';
		}

		$encoded = substr( $payload, strlen( self::VERSION_TAG ) + 1 );
		$raw     = base64_decode( $encoded, true );
		if ( false === $raw || strlen( $raw ) < self::NONCE_BYTES + self::TAG_BYTES + 1 ) {
			return '';
		}

		$iv     = substr( $raw, 0, self::NONCE_BYTES );
		$tag    = substr( $raw, self::NONCE_BYTES, self::TAG_BYTES );
		$cipher = substr( $raw, self::NONCE_BYTES + self::TAG_BYTES );

		$plain = openssl_decrypt(
			$cipher,
			self::CIPHER,
			self::derive_key(),
			OPENSSL_RAW_DATA,
			$iv,
			$tag
		);
		return false === $plain ? '' : $plain;
	}

	private static function derive_key(): string {
		$auth   = defined( 'AUTH_KEY' ) ? AUTH_KEY : 'suitemkt3k-fallback-auth';
		$secret = (string) get_option( 'suitemkt3k_secret_key', '' );
		return hash( 'sha256', $auth . '|' . $secret . '|suitemkt3k', true );
	}

	private static function fallback_encode( string $plaintext ): string {
		return self::VERSION_TAG . '|legacy|' . base64_encode( $plaintext );
	}

	public static function mask( string $secret, int $visible = 4 ): string {
		$length = strlen( $secret );
		if ( $length <= $visible ) {
			return str_repeat( '*', $length );
		}
		return str_repeat( '*', $length - $visible ) . substr( $secret, -$visible );
	}
}
