<?php

namespace Pay4AllForMypos\Support;

use Pay4AllForMypos\Exception\OpenSslNotLoadedException;
use Pay4AllForMypos\Exception\PropertiesNotSetException;

class Cipher
{
    /** @var string */
    private $key;

    /** @var string */
    private $salt;

    public function __construct()
    {
        $this->key  = $this->get_key();
        $this->salt = $this->get_salt();
    }

    /**
     * @throws OpenSslNotLoadedException
     * @throws PropertiesNotSetException
     * @throws \Exception
     */
    public function encrypt( $value )
    {
        if ( empty( $this->key ) ) {
            throw new PropertiesNotSetException( esc_html__( 'The constant LOGGED_IN_KEY is missing.', 'pay4all-for-mypos' ) );
        }

        if ( empty( $this->salt ) ) {
            throw new PropertiesNotSetException( esc_html__( 'The constant LOGGED_IN_SALT is missing.', 'pay4all-for-mypos' ) );
        }

        if ( !extension_loaded( 'openssl' ) ) {
            throw new OpenSslNotLoadedException( esc_html__( 'OpenSSL not activated.', 'pay4all-for-mypos' ) );
        }

        $method = 'aes-256-ctr';
        $ivlen  = openssl_cipher_iv_length( $method );
        $iv     = openssl_random_pseudo_bytes( $ivlen );

        $raw_value = openssl_encrypt( $value . $this->salt, $method, $this->key, 0, $iv );
        if ( !$raw_value ) {
            throw new \Exception( 'Cipher failed.' );
        }

        return base64_encode( $iv . $raw_value );
    }

    /**
     * @throws OpenSslNotLoadedException
     * @throws PropertiesNotSetException
     * @throws \Exception
     */
    public function decrypt( $raw_value )
    {
        if ( empty( $this->key ) ) {
            throw new PropertiesNotSetException( esc_html__( 'The constant LOGGED_IN_KEY is missing.', 'pay4all-for-mypos' ) );
        }

        if ( empty( $this->salt ) ) {
            throw new PropertiesNotSetException( esc_html__( 'The constant LOGGED_IN_SALT is missing.', 'pay4all-for-mypos' ) );
        }

        if ( !extension_loaded( 'openssl' ) ) {
            throw new OpenSslNotLoadedException( esc_html__( 'OpenSSL not activated.', 'pay4all-for-mypos' ) );
        }

        $raw_value = base64_decode( $raw_value, true );

        $method = 'aes-256-ctr';
        $ivlen  = openssl_cipher_iv_length( $method );
        $iv     = substr( $raw_value, 0, $ivlen );

        $raw_value = substr( $raw_value, $ivlen );

        $value = openssl_decrypt( $raw_value, $method, $this->key, 0, $iv );
        if ( !$value || substr( $value, -strlen( $this->salt ) ) !== $this->salt ) {
            throw new \Exception( 'Decryption failed.' );
        }

        return substr( $value, 0, -strlen( $this->salt ) );
    }

    /**
     * @return false|string
     */
    private function get_key()
    {
        if ( !defined( 'LOGGED_IN_KEY' ) || '' === LOGGED_IN_KEY ) {
            return false;
        }

        return LOGGED_IN_KEY;
    }

    /**
     * @return false|string
     */
    private function get_salt()
    {
        if ( !defined( 'LOGGED_IN_SALT' ) || '' === LOGGED_IN_SALT ) {
            return false;
        }

        return LOGGED_IN_SALT;
    }
}