<?php

declare(strict_types=1);

namespace PpPhp\Core\Deploy;

use PpPhp\Core\DB;

/**
 * Manages the symmetric key used to encrypt stored FTP/SFTP credentials.
 *
 * The key lives in the core `settings` table (created by the installer) under
 * `deploy_secret_key`, generated once on first use. Credentials are encrypted
 * with AES-256-CBC so a database dump never exposes plaintext passwords.
 */
class DeploySecret
{
    private static ?string $key = null;

    /** Return (or lazily create) the 32-byte encryption key. */
    public static function key(): string
    {
        if (self::$key !== null) {
            return self::$key;
        }

        DB::Init();
        DB::SetConnection();

        $stored = DB::FetchOne('SELECT `value` FROM `settings` WHERE `key` = ?', ['deploy_secret_key']);
        if (is_string($stored) && $stored !== '') {
            self::$key = base64_decode($stored, true) ?: hash('sha256', $stored, true);
            return self::$key;
        }

        $raw = random_bytes(32);
        DB::Query(
            'INSERT INTO `settings` (`key`, `value`) VALUES (?, ?) ON DUPLICATE KEY UPDATE `value` = VALUES(`value`)',
            ['deploy_secret_key', base64_encode($raw)]
        );
        self::$key = $raw;
        return self::$key;
    }

    /** Encrypt a plaintext value → base64(iv|ciphertext). Empty in, empty out. */
    public static function encrypt(string $plaintext): string
    {
        if ($plaintext === '') {
            return '';
        }
        $iv = random_bytes(16);
        $cipher = openssl_encrypt($plaintext, 'aes-256-cbc', self::key(), OPENSSL_RAW_DATA, $iv);
        if ($cipher === false) {
            return '';
        }
        return base64_encode($iv . $cipher);
    }

    /** Decrypt a value produced by encrypt(). Returns '' on any failure. */
    public static function decrypt(string $encrypted): string
    {
        if ($encrypted === '') {
            return '';
        }
        $data = base64_decode($encrypted, true);
        if ($data === false || strlen($data) <= 16) {
            return '';
        }
        $iv = substr($data, 0, 16);
        $cipher = substr($data, 16);
        $plain = openssl_decrypt($cipher, 'aes-256-cbc', self::key(), OPENSSL_RAW_DATA, $iv);
        return $plain === false ? '' : $plain;
    }
}
