<?php
/**
 * HappyFenceNG Total Enterprise Security Plugin
 * HAPPYWPRESS is a RazorVue Trademark.
 *
 * @package     HappyFenceNG
 * @developer   Simonluca Scillitani
 * @copyright   2025 RazorVue di Scillitani Simonluca
 * @link        https://razorvue.it
 * @author      RazorVue di Scillitani Simonluca
 * @brand       HappyWPress
 * @uri         https://happywpress.com
 * @set all
 */

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



/**PHPCS -> code compliance: we put useful comments where needed.. */
abstract class HappyFenceNGAStore extends HappyFenceNGRuntimeExceptions {

	/**PHPCS -> code compliance: we put useful comments where needed..
	 *
	 * @param string $table ...table name.
	 * @param string $query ... to execute.
	 */
	public static function aInit( $table, $query ) {
			require_once ABSPATH . 'wp-admin/includes/upgrade.php';

			$a_query = 'CREATE TABLE IF NOT EXISTS ' . $table . $query
			. HAPPYFENCENG_DB->get_charset_collate() . ';';
			dbDelta( $a_query );
	}

	/**PHPCS -> code compliance: we put useful comments where needed..
	 *
	 * @param string $module ... the name.
	 * @param string $prop .. the name.
	 * @param string $a_default ... guess what?.
	 */
	abstract public static function get( string $module, string $prop, $a_default = HappyFenceNGPlaceholder::NOT_INITIALIZED );

	/**PHPCS -> code compliance: we put useful comments where needed..
	 *
	 * @param string $module ... the name.
	 * @param string $prop .. the name.
	 * @param string $value ... guess what?.
	 */
	abstract public static function set( string $module, string $prop, $value );

	/**PHPCS -> code compliance: we put useful comments where needed.. */
	abstract public static function uninstall();

	/**PHPCS -> code compliance: we put useful comments where needed..
	 *
	 * @param string $table ... the name.
	 * @param string $query .. to execute.
	 * @param array  $values ... guess what?.
	 */
	protected static function toUnencryptedDb( string $table, string $query, array $values ) {

			HAPPYFENCENG_DB->query( HAPPYFENCENG_DB->prepare( 'INSERT INTO ' . $table . $query, ...$values ) );
	}

	/**PHPCS -> code compliance: we put useful comments where needed..
	 *
	 * @param string $table ... the name.
	 * @param string $preamble .. the name.
	 * @param string $query ... guess what?.
	 * @param array  $values ... again.
	 */
	protected static function fromUnencryptedDb( string $table, string $preamble, string $query = HappyFenceNGPlaceholder::EMPTY_STRING, array $values = HappyFenceNGPlaceholder::EMPTY_ARRAY ) {

		$sql = HappyFenceNGPlaceholder::EMPTY_STRING;
		if ( HappyFenceNGPROC::not_equals( $query, HappyFenceNGPlaceholder::EMPTY_STRING ) ) {
			$sql = HAPPYFENCENG_DB->prepare( $preamble . ' ' . $table . ' ' . $query, ...$values );
		} else {
			$sql = "$preamble $table";
		}

			return HAPPYFENCENG_DB->get_results( $sql, ARRAY_A );
	}

	/**PHPCS -> code compliance: we put useful comments where needed..
	 *
	 * @param string $table ... the name.
	 * @param string $module ... the name.
	 * @param string $prop .. the name.
	 * @param string $a_default ... guess what?.
	 * @throws \InvalidArgumentException .
	 */
	protected static function fromEncryptedDb( string $table, string $module, string $prop, $a_default = HappyFenceNGPlaceholder::NOT_INITIALIZED ) {
		try {

			if ( empty( $prop ) || ( HappyFenceNGPROC::equals( $prop, HappyFenceNGPlaceholder::EMPTY_STRING ) ) ) {
				throw new InvalidArgumentException( 'STORE->Property key (prop) must not be empty' );
			}

			if ( empty( $module ) || ( HappyFenceNGPROC::equals( $module, HappyFenceNGPlaceholder::EMPTY_STRING ) ) ) {
				throw new InvalidArgumentException( "STORE->Module key must not be empty $prop" );
			}

			$a_prop   = self::opt_key( $prop );
			$a_module = self::mov( $module );
			$val      = HAPPYFENCENG_DB->get_var( HAPPYFENCENG_DB->prepare( 'SELECT value FROM ' . $table . ' WHERE module = %s AND prop = %s LIMIT 1', $a_module, $a_prop ) );
			$record   = null;
			if ( HappyFenceNGPROC::not_equals( $val, null ) ) {
				$record = self::exp( $val );
			} else {
				return $a_default;
			}

			if ( ( HappyFenceNGPROC::not_equals( $record, null ) ) ) {
				if ( hash_equals( $a_prop, $record['prop'] ) ) {
					if ( ( HappyFenceNGPROC::not_equals( $record['data'], null ) ) ) {
						return $record['data'];
					} else {
						return $a_default;
					}
				} else {
					HappyFenceNGLOGCORE::logcore(
						static::class . "<$prop><$a_prop> hash does not match <" . $record['prop'] . '>',
						HappyFenceNGSyslogFacility::ZTV,
						HappyFenceNGSyslogSeverity::ERROR
					);
											HappyFenceNGRuntimeExceptions::tampered_die(
												esc_html__(
													'SECURITY ALERT[DH100]: The HappyFenceNG Database key hash does not match. ',
													'happyfenceng-total-enterprise-security'
												)
											);
				}
			}

			return $a_default;

		} catch ( Throwable $e ) {
			HappyFenceNGLOGCORE::logcore(
				static::class . ' (GET) database error ' . $e->getMessage(),
				HappyFenceNGSyslogFacility::DB,
				HappyFenceNGSyslogSeverity::CRITICAL
			);

			return $a_default;
		}
	}

	/**PHPCS -> code compliance: we put useful comments where needed..
	 *
	 * @param string $table ... the name.
	 * @param string $module ... the name.
	 * @param string $prop .. the name.
	 * @param string $value ... guess what?.
	 * @throws \InvalidArgumentException .
	 */
	protected static function toEncryptedDb( string $table, string $module, string $prop, $value ): void {
		try {

			if ( empty( $prop ) || ( HappyFenceNGPROC::equals( $prop, HappyFenceNGPlaceholder::EMPTY_STRING ) ) ) {
				throw new InvalidArgumentException( 'STORE->Property key (prop) must not be empty' );
			}

			if ( empty( $module ) || ( HappyFenceNGPROC::equals( $module, HappyFenceNGPlaceholder::EMPTY_STRING ) ) ) {
				throw new InvalidArgumentException( "STORE->Module key must not be empty $prop" );
			}

			if ( HappyFenceNGPROC::equals( $value, null ) ) {
				throw new InvalidArgumentException( "STORE->Passing null value not permitted $table $module $prop" );
			}

			if ( ! is_string( $value ) && ! is_int( $value ) && ! is_float( $value ) && ! is_bool( $value ) && ! is_array( $value ) ) {
				throw new InvalidArgumentException(
					'Invalid value type: only scalar types and arrays are allowed.'
				);
			}

			$a_module = self::mov( $module );
			$a_prop   = self::opt_key( $prop );
			$record   = array(
				'module' => $module,
				'prop'   => $a_prop,
				'data'   => $value,
			);
			$a_value  = self::mov( $record );

			HAPPYFENCENG_DB->query(
				HAPPYFENCENG_DB->prepare( 'INSERT INTO ' . $table . ' (module, prop, value) VALUES (%s, %s, %s) ON DUPLICATE KEY UPDATE value = VALUES(value)', $a_module, $a_prop, $a_value )
			);
		} catch ( Throwable $e ) {
			HappyFenceNGLOGCORE::logcore(
				static::class . ' (SET) database error' . $e->getMessage(),
				HappyFenceNGSyslogFacility::DB,
				HappyFenceNGSyslogSeverity::CRITICAL
			);

		}
	}

	/**PHPCS -> code compliance: we put useful comments where needed..
	 *
	 * @param string $table ... the name.
	 * @throws \RuntimeException If the table name is not defined.
	 */
	protected static function generic_uninstall( $table ) {
		try {
			HappyFenceNGLOGCORE::logcore(
				static::class . "->CALL UNINSTALL $table",
				HappyFenceNGSyslogFacility::DB,
				HappyFenceNGSyslogSeverity::INFO
			);
			if ( empty( $table ) ) {
				throw new \RuntimeException( 'Table name not defined for uninstall.' );
			}

			$sql = 'DROP TABLE IF EXISTS `' . $table . '`';
            /* phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery */
			HAPPYFENCENG_DB->query( $sql );
			HappyFenceNGLOGCORE::logcore(
				"Table $table deleted",
				HappyFenceNGSyslogFacility::SYSTEM,
				HappyFenceNGSyslogSeverity::WARNING
			);
		} catch ( \Throwable $e ) {
			HappyFenceNGLOGCORE::logcore(
				static::class . "REQUIRED TABLE NOT FOUND FOR DROP $table ->" . $e->getMessage(),
				HappyFenceNGSyslogFacility::DB,
				HappyFenceNGSyslogSeverity::CRITICAL
			);
		}
	}

	/**PHPCS -> code compliance: we put useful comments where needed..
	 *
	 * @param string $prop .. the name.
	 */
	protected static function opt_key( string $prop ): string {
		try {
			return md5( 'hf_' . static::class . "_$prop" );
		} catch ( \Throwable $e ) {
			HappyFenceNGLOGCORE::logcore(
				static::class . 'ZTV::OPT_KEY->' . $e->getMessage(),
				HappyFenceNGSyslogFacility::ZTV,
				HappyFenceNGSyslogSeverity::CRITICAL
			);
			return HappyFenceNGPlaceholder::EMPTY_STRING;
		}
	}


	/**PHPCS -> code compliance: we put useful comments where needed..
	 *
	 * @param string $value ... guess what?.
	 */
	protected static function mov( $value ): ?string {
		try {

			if ( HappyFenceNGPROC::equals( $value, null ) ) {
				$value = new HappyFenceNGPlaceholder(); }
			$key = HappyFence2KeyManager::get_instance()->get_key();
			//phpcs:ignore
			return base64_encode(
				openssl_encrypt(
					//phpcs:ignore
					serialize( $value ),
					'aes-256-cbc',
					$key,
					0,
					substr( $key, 0, 16 )
				)
			);
		} catch ( \Throwable $e ) {
			HappyFenceNGLOGCORE::logcore(
				static::class . 'ZTV::MOV->' . $e->getMessage(),
				HappyFenceNGSyslogFacility::ZTV,
				HappyFenceNGSyslogSeverity::CRITICAL
			);
			return HappyFenceNGPlaceholder::EMPTY_STRING;
		}
	}


	/**PHPCS -> code compliance: we put useful comments where needed..
	 *
	 * @param string $payload ... the payload.
	 */
	protected static function exp( $payload ) {
		try {
			if ( HappyFenceNGPROC::equals( $payload, null ) ) {
				HappyFenceNGLOGCORE::logcore(
					static::class . 'ZTV::EXP->EMPTY PAYLOAD !! RETURNING EMPTY STRING',
					HappyFenceNGSyslogFacility::ZTV,
					HappyFenceNGSyslogSeverity::CRITICAL
				);
				return HappyFenceNGPlaceholder::EMPTY_STRING;
			}
				$key       = HappyFence2KeyManager::get_instance()->get_key();
				$decrypted = openssl_decrypt(
					//phpcs:ignore
					base64_decode( $payload ),
					'aes-256-cbc',
					$key,
					0,
					substr( $key, 0, 16 )
				);

			if ( HappyFenceNGPROC::not_equals( $decrypted, false ) ) {
				$tmp_dec = maybe_unserialize( $decrypted );
				if ( $tmp_dec instanceof HappyFenceNGPlaceholder ) {
					HappyFenceNGLOGCORE::logcore(
						static::class . 'ZTV::EXP->EMPTY DATA FROM DB !! RETURNING EMPTY STRING',
						HappyFenceNGSyslogFacility::ZTV,
						HappyFenceNGSyslogSeverity::ERROR
					);
					return HappyFenceNGPlaceholder::EMPTY_STRING;
				} else {
					return $tmp_dec;
				}
			} else {
				return HappyFenceNGPlaceholder::EMPTY_STRING;
			}
		} catch ( \Throwable $e ) {
			HappyFenceNGLOGCORE::logcore(
				static::class . 'ZTV::EXP->' . $e->getMessage(),
				HappyFenceNGSyslogFacility::ZTV,
				HappyFenceNGSyslogSeverity::CRITICAL
			);
		}
	}
}
