<?php

namespace App\Services;

use Illuminate\Support\Facades\Log;

class EasypaisaCryptoService
{
    protected string $publicKeyPem = <<<EOD
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAn5jTUtv5E+0q4Z5Z5rm2
i3J9efGnTK8HpG4kDeX6vWeHyFysb/VcthL75leqyQgfxPOVxBaqzRJk9+NtFzz7
IC/mBIKoL5hvp/Ehnc2YOmYG+V/nQfQDFjq701U9hHjaws9q1gIXA0LeiZYeiMFN
zAMKqWO4xltaJGXi/MtHeMrMe69neqq7Vla+VEVTclFkZXzX6yMXep8ZmO+VGiQv
+NPG9r2V1/R7WiuLeWUj+r1j/tuqevVPy9r6Lor/tEa4PrZDoGDa/7UXKjaQo4In
BHy8L+0vZPurILv2vATXNZxJ2ThOD5Or2FiwMd2iEMROcdlT8Diit7vRLofmtC45
9QIDAQAB
-----END PUBLIC KEY-----
EOD;

    public function decryptCnic(string $encryptedHeader, string $encryptedCnic): ?string
    {
        // Step 1: Extract symmetric key
        if (!preg_match('/symmetricKey=([^&]+)/', $encryptedHeader, $matches)) {
            Log::warning('EasypaisaCryptoService: symmetricKey not found.');
            return null;
        }

        $symmetricKeyEncoded = urldecode($matches[1]);
        $symmetricKeyBytes = base64_decode($symmetricKeyEncoded);

        // Step 2: Decrypt symmetric key
        $publicKey = openssl_pkey_get_public($this->publicKeyPem);
        if (!$publicKey) {
            Log::error('EasypaisaCryptoService: Invalid public key.');
            return null;
        }

        $randomKey = null;
        if (!openssl_public_decrypt($symmetricKeyBytes, $randomKey, $publicKey, OPENSSL_PKCS1_PADDING)) {
            Log::error('EasypaisaCryptoService: Failed to decrypt symmetric key.');
            return null;
        }

        // Step 3: Generate secret key from SHA1
        $secretKey = $this->generateSecretKey($randomKey);

        // Step 4: Decrypt CNIC using AES-128-ECB
        $decryptedCnic = openssl_decrypt(
            base64_decode($encryptedCnic),
            'AES-128-ECB',
            $secretKey,
            OPENSSL_RAW_DATA
        );

        return $decryptedCnic ?: null;
    }

    private function generateSecretKey(string $seed): string
    {
        $btLength = 16;
        $bt = '';
        $index = 0;
        $digestSize = 20;
        $state = sha1($seed, true);

        while ($index < $btLength) {
            $output = sha1($state, true);
            $todo = min($btLength - $index, $digestSize);
            for ($i = 0; $i < $todo; $i++) {
                $bt .= $output[$i];
                $index++;
            }
        }

        return substr($bt, 0, 16); // return first 16 bytes only
    }
}
