<?php

declare(strict_types=1);

namespace BotGuard\Core;

/**
 * Authenticated symmetric encryption for secrets at rest (e.g. the SMTP
 * password stored in the settings table).
 *
 * Uses AES-256-GCM with a key derived from APP_KEY. Ciphertext is versioned and
 * base64-encoded as `enc:v1:<base64(iv|tag|cipher)>` so decrypt() can safely
 * distinguish encrypted values from legacy plaintext.
 */
final class Crypto
{
    private const PREFIX = 'enc:v1:';
    private const CIPHER = 'aes-256-gcm';

    public static function encrypt(string $plaintext): string
    {
        $key = self::key();
        $iv = random_bytes(12);
        $tag = '';

        $cipher = openssl_encrypt($plaintext, self::CIPHER, $key, OPENSSL_RAW_DATA, $iv, $tag);
        if ($cipher === false) {
            return $plaintext; // fail open to plaintext rather than losing the value
        }

        return self::PREFIX . base64_encode($iv . $tag . $cipher);
    }

    /**
     * Decrypt a value produced by encrypt(). Returns legacy plaintext unchanged
     * when it lacks the versioned prefix.
     */
    public static function decrypt(string $value): string
    {
        if (! str_starts_with($value, self::PREFIX)) {
            return $value; // not encrypted (legacy/plaintext) — return as-is
        }

        $raw = base64_decode(substr($value, strlen(self::PREFIX)), true);
        if ($raw === false || strlen($raw) < 28) {
            return '';
        }

        $iv = substr($raw, 0, 12);
        $tag = substr($raw, 12, 16);
        $cipher = substr($raw, 28);

        $plain = openssl_decrypt($cipher, self::CIPHER, self::key(), OPENSSL_RAW_DATA, $iv, $tag);

        return $plain === false ? '' : $plain;
    }

    public static function isEncrypted(string $value): bool
    {
        return str_starts_with($value, self::PREFIX);
    }

    /**
     * Derive a 32-byte key from APP_KEY (with a dev fallback so nothing breaks
     * before a key is set — production installs always have one via the wizard).
     */
    private static function key(): string
    {
        $appKey = (string) config('app.key', '');
        if ($appKey === '') {
            $appKey = 'botguard-insecure-dev-key';
        }

        return hash('sha256', $appKey, true);
    }
}
