<?php

namespace App\Http\Traits;

use phpseclib3\Crypt\AES;
use phpseclib3\Crypt\PublicKeyLoader;
use phpseclib3\Crypt\RSA;

trait CryptTrait
{
    protected string $base64PublicKey = "MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAoVdxG0Qi9pip46Jw9ImSlPVD8+L2mM47ey6EZna7D7utgNdh8Tzkjrm1Yl4h6kPJrhdWvMIJGS51+6dh041IXcJEoUquNblUEqAUXBYwQM8PdfnS12SjlvZrP4q6whBE7IV1SEIBJP0gSK5/8Iu+uld2ctJiU4p8uswL2bCPGWdvVPltxAg6hfAG/ImRUKPRewQsFhkFvqIDCpO6aeaR10q6wwENZltlJeeRnl02VWSneRmPqqypqCxz0Y+yWCYtsA+ngfZmwRMaFkXcWjaWnvSqqV33OAsrQkvuBHWoEEkvQ0P08+h9Fy2+FhY9TeuukQ2CVFz5YyOhp25QtWyQI+IaDKk+hLxJ1APR0c3tmV0ANEIjO6HhJIdu2KQKtgFppvqSrZp2OKtI8EZgVbWuho50xvlaPGzWoMi9HSCb+8ARamlOpesxHH3O0cTRUnft2Zk1FHQb2Pidb2z5onMEnzP2xpTqAIVQyb6nMac9tof5NFxwR/c4pmci+1n8GFJIFN18j2XGad1mNyio/R8LabqnzNwJC6VPnZJz5/pDUIk9yKNOY0KJe64SRiL0a4SNMohtyj6QlA/3SGxaEXb8UHpophv4G9wN1CgfyUamsRqp8zo5qDxBvlaIlfkqJvYPkltj7/23FHDjPi8q8UkSiAeu7IV5FTfB5KsiN8+sGSMCAwEAAQ==";

    protected function generateSessionId(): string
    {
        $data = random_bytes(16);
        $data[6] = chr(ord($data[6]) & 0x0f | 0x40); // set version to 0100
        $data[8] = chr(ord($data[8]) & 0x3f | 0x80); // set bits 6-7 to 10

        return vsprintf('%s%s-%s-%s-%s-%s%s%s', str_split(bin2hex($data), 4));
    }

    protected function generateRandomBytes(int $length): string
    {
        return base64_encode(random_bytes($length));
    }

    protected function generateSessionKey(string $sessionId, string $secretKey, string $iv): string
    {
        $sessionAesKey = "AES_GCM$" . $secretKey . "$" . $iv;
        $encryptedSessionAesKey = $this->encryptSessionAesKey($sessionAesKey);

        return "v1$" . $sessionId . "$" . $encryptedSessionAesKey;
    }

    protected function encryptSessionAesKey(string $sessionAesKey): string
    {
        $rsa = PublicKeyLoader::load($this->base64PublicKey)->withPadding(RSA::ENCRYPTION_OAEP)->withHash('sha1')->withMGFHash('sha1');

        return base64_encode($rsa->encrypt($sessionAesKey));
    }

    protected function encryptData(string $sessionId, string $secretKey, string $iv, string $data): string
    {
        $cipher = new AES('gcm');
        $cipher->setKey(base64_decode($secretKey));
        $cipher->setNonce(base64_decode($iv));
        $cipher->setAAD(base64_decode($secretKey));

        $encrypted = $cipher->encrypt($data);
        $combined = base64_encode($encrypted . $cipher->getTag());
        return 'v1$' . $sessionId . '$' . $combined;
    }

    protected function decryptData(string $secretKey, string $iv, string $encryptedData): string
    {
        $parsed = base64_decode(explode('$', $encryptedData)[2]);
        $encrypted = substr($parsed, 0, strlen($parsed) - 16);
        $tag = substr($parsed, strlen($parsed) - 16);

        $cipher = new AES('gcm');
        $cipher->setKey(base64_decode($secretKey));
        $cipher->setNonce(base64_decode($iv));
        $cipher->setAAD(base64_decode($secretKey));
        $cipher->setTag($tag);

        return $cipher->decrypt($encrypted);
    }
}
