<?php

declare(strict_types=1);

namespace App\Models;

use App\Core\Database;

final class SmtpSettingsModel
{
    private const ENCRYPTION_CIPHER = 'aes-256-cbc';

    public function get(): ?array
    {
        $stmt = Database::connection()->prepare('SELECT * FROM smtp_settings WHERE id = 1');
        $stmt->execute();
        $row = $stmt->fetch();

        if ($row === false) {
            return null;
        }

        if ($row['password_encrypted'] !== null) {
            $row['password'] = $this->decrypt($row['password_encrypted']);
        }

        return $row;
    }

    public function save(array $data, int $userId): void
    {
        $pdo = Database::connection();

        $encryptedPassword = isset($data['password']) && $data['password'] !== ''
            ? $this->encrypt($data['password'])
            : null;

        $stmt = $pdo->prepare(
            'INSERT INTO smtp_settings (id, host, port, encryption, username, password_encrypted, from_address, from_name, is_configured, updated_by, updated_at)
             VALUES (1, :host, :port, :encryption, :username, :password, :from_address, :from_name, 1, :user, NOW())
             ON DUPLICATE KEY UPDATE
                host = VALUES(host), port = VALUES(port), encryption = VALUES(encryption),
                username = VALUES(username),
                password_encrypted = COALESCE(VALUES(password_encrypted), password_encrypted),
                from_address = VALUES(from_address), from_name = VALUES(from_name),
                is_configured = 1, updated_by = VALUES(updated_by), updated_at = NOW()'
        );

        $stmt->execute([
            'host' => $data['host'],
            'port' => $data['port'],
            'encryption' => $data['encryption'],
            'username' => $data['username'] ?? null,
            'password' => $encryptedPassword,
            'from_address' => $data['from_address'],
            'from_name' => $data['from_name'],
            'user' => $userId,
        ]);
    }

    private function encryptionKey(): string
    {
        // Derives a 32-byte key from APP_KEY so no separate secret needs managing.
        return hash('sha256', (string) config('app.key'), true);
    }

    private function encrypt(string $plaintext): string
    {
        $iv = random_bytes(openssl_cipher_iv_length(self::ENCRYPTION_CIPHER));
        $cipherText = openssl_encrypt($plaintext, self::ENCRYPTION_CIPHER, $this->encryptionKey(), OPENSSL_RAW_DATA, $iv);

        return base64_encode($iv . $cipherText);
    }

    private function decrypt(string $encoded): ?string
    {
        $raw = base64_decode($encoded, true);
        if ($raw === false) {
            return null;
        }

        $ivLength = openssl_cipher_iv_length(self::ENCRYPTION_CIPHER);
        $iv = substr($raw, 0, $ivLength);
        $cipherText = substr($raw, $ivLength);

        $plaintext = openssl_decrypt($cipherText, self::ENCRYPTION_CIPHER, $this->encryptionKey(), OPENSSL_RAW_DATA, $iv);

        return $plaintext === false ? null : $plaintext;
    }
}
