<?php

namespace GravityKit\GravityExport\Save\Service;

use GravityKit\GravityExport\Foundation\Encryption\Encryption;

/**
 * Service that handles encrypting and decrypting passwords.
 *
 * @since 1.0
 *
 */
class PasswordService {
	/**
	 * Algorithm used for storing the password.
	 *
	 * @since 1.0
	 */
	private const CIPHER_ALGO = 'AES-128-ECB';

	/**
	 * Holds the hashing secret.
	 *
	 * @since 1.0
	 * @var string
	 */
	private $secret;

	/**
	 * The encryption from Foundation.
	 * @since $ver$
	 * @var Encryption
	 */
	private $foundation_encryption;

	/**
	 * Creates the service.
	 *
	 * @since 1.0
	 *
	 * @param string $secret The hashing secret.
	 */
	public function __construct( string $secret, ?Encryption $foundation_encryption = null ) {
		$this->secret                = $secret ?: wp_salt(); // fallback for legacy decryption.
		$this->foundation_encryption = $foundation_encryption ?? Encryption::get_instance($secret);
	}

	/**
	 * Encrypts the password using a predefined secret.
	 *
	 * @since 1.0
	 *
	 * @param string $password The password to encrypt.
	 *
	 * @return string The encrypted password.
	 */
	public function encrypt( string $password ): string {
		if ( empty( $password ) ) {
			return $password;
		}

		return $this->foundation_encryption->encrypt( $password ) ?: $password;
	}

	/**
	 * Whether this was encrypted with the legacy implementation.
	 * @since $ver$
	 *
	 * @param string $encrypted_password
	 *
	 * @return bool
	 */
	public function is_legacy_encryption( string $encrypted_password ): bool {
		return $this->legacy_decrypt( $encrypted_password ) !== false;
	}

	/**
	 * @param string $encrypted_password
	 *
	 * @return false|string
	 */
	private function legacy_decrypt( string $encrypted_password ) {
		return openssl_decrypt( $encrypted_password, self::CIPHER_ALGO, $this->secret );
	}

	/**
	 * Decrypts a hash back to a password.
	 *
	 * @since 1.0
	 *
	 * @param string $encrypted_password The password to decrypt.
	 *
	 * @return string|null The decrypted password.
	 */
	public function decrypt( string $encrypted_password ): ?string {
		if ( empty( $encrypted_password ) ) {
			return null;
		}

		$decrypted = $this->foundation_encryption->decrypt( $encrypted_password );
		if ( $decrypted !== null ) {
			return $decrypted;
		}

		// Fallback to legacy decryption.
		return $this->legacy_decrypt( $encrypted_password ) ?: null;
	}
}
