<?php

class CfSshKeys
{
    private $dbConnection;

    public function __construct()
    {
        $this->dbConnection = CfSettings::getInstance()->getConnection();
    }

    public function generate(): SshKeyEntity
    {
        $openSslKey = openssl_pkey_new([
            "digest_alg" => SSH_DIGEST_ALGORITHM,
            "private_key_bits" => SSH_PRIVATE_KEY_BITS,
            "private_key_type" => SSH_PRIVATE_KEY_TYPE
        ]);

        openssl_pkey_export($openSslKey, $privateKey);

        $sshKeyEntity = new SshKeyEntity();
        $sshKeyEntity->setPrivateKey($privateKey);

        /**
         * convert openssl public key format to openssh
         * @var phpseclib3\Crypt\RSA\PublicKey
         */
        $pk = \phpseclib3\Crypt\PublicKeyLoader::loadPublicKey(openssl_pkey_get_details($openSslKey)['key']);

        $sshKeyEntity->setPublicKey($pk->toString('openssh', ['comment' => 'generated-by-cfengine-ssh-api']));

        return $sshKeyEntity;
    }

    public function save(SshKeyEntity $sshKeyEntity): int
    {
        $stmt = $this->dbConnection->prepare(
            'INSERT INTO ssh_keys (public_key, private_key, generated_by) VALUES (:public_key, :private_key, :generated_by)'
        );
        $stmt->execute($sshKeyEntity->toArray());
        return $this->dbConnection->lastInsertId();
    }

    public function delete(int $id)
    {
        return $this->dbConnection->prepare('DELETE FROM ssh_keys WHERE id = ?')->execute([$id]);
    }

    public function list()
    {
        return $this
            ->dbConnection
            ->query('SELECT id, public_key, generated_by, generated_at FROM ssh_keys')
            ->fetchAll(\PDO::FETCH_ASSOC);
    }

    public function get(int $id)
    {
        $stmt = $this->dbConnection->prepare('SELECT id, public_key, generated_by, generated_at FROM ssh_keys WHERE id = ?');
        $stmt->execute([$id]);
        return $stmt->fetch(\PDO::FETCH_ASSOC);
    }
}

class SshKeyEntity
{
    private $privateKey;
    private $publicKey;
    private $generatedBy;

    public function toArray(): array
    {
        return [
            'private_key' => $this->getPrivateKey(),
            'public_key' => $this->getPublicKey(),
            'generated_by' => $this->getGeneratedBy()
        ];
    }

    public function getPrivateKey()
    {
        return $this->privateKey;
    }

    public function setPrivateKey($privateKey)
    {
        $this->privateKey = $privateKey;
    }

    public function getPublicKey()
    {
        return $this->publicKey;
    }

    public function setPublicKey($publicKey)
    {
        $this->publicKey = $publicKey;
    }

    public function getGeneratedBy()
    {
        return $this->generatedBy;
    }

    public function setGeneratedBy($generatedBy)
    {
        $this->generatedBy = $generatedBy;
    }
}
