<?php

namespace App\Domains\Integration\Casts;

use Illuminate\Contracts\Database\Eloquent\CastsAttributes;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Encryption\Encrypter;
use Exception;

class EncryptedIntegrationData implements CastsAttributes
{
    protected function getEncrypter(): Encrypter
    {
        $secret = config('services.integrations.secret');
        
        if (empty($secret)) {
            throw new Exception('The integrations secret is not configured.');
        }

        // Laravel encrypter requires a key of exact length. Typically 32 bytes for AES-256-CBC.
        // If the secret is base64 encoded like the APP_KEY:
        if (str_starts_with($secret, 'base64:')) {
            $key = base64_decode(substr($secret, 7));
        } else {
            // Otherwise, we hash it to ensure 32 bytes for AES-256-CBC.
            $key = hash('sha256', $secret, true);
        }
        
        return new Encrypter($key, config('app.cipher', 'AES-256-CBC'));
    }

    /**
     * Cast the given value.
     *
     * @param  array<string, mixed>  $attributes
     */
    public function get(Model $model, string $key, mixed $value, array $attributes): mixed
    {
        if ($value === null) {
            return null;
        }

        try {
            $decrypted = $this->getEncrypter()->decryptString($value);
            return json_decode($decrypted, true);
        } catch (Exception $e) {
            // Return null or throw depending on how strict we want to be.
            return null;
        }
    }

    /**
     * Prepare the given value for storage.
     *
     * @param  array<string, mixed>  $attributes
     */
    public function set(Model $model, string $key, mixed $value, array $attributes): mixed
    {
        if ($value === null) {
            return null;
        }

        $json = json_encode($value);
        return $this->getEncrypter()->encryptString($json);
    }
}
