<?php


namespace Eater\Glim\Handler\Panel\ConfigBuilder;

use Eater\Glim\Handler\Session;
use Eater\Glim\Model\Certificate;
use Eater\Glim\Model\CertificateQuery;
use Eater\Glim\Model\Server;
use Eater\Glim\Model\ServerQuery;

class Action extends Session
{
    public function handle()
    {
        $zipFile = tempnam(sys_get_temp_dir(), '0zip');
        $zip = new \ZipArchive();
        $zip->open($zipFile, \ZipArchive::CREATE);
        $cert = $this->post('cert');
        $wantEmbedded = $this->post('want-embedded');

        $server = ServerQuery::create()->findOneByFingerprint($this->post('fingerprint'));
        $name = $server->getFqdn();

        if ($cert !== null && $wantEmbedded !== null) {
            $certModel = CertificateQuery::create()->findOneByUserAndName($this->getUser(), $cert);
            $config = $this->getEmbeddedConfig($zip, $server, $certModel);
            $name .= '-' . $certModel->getName() . '.' . $certModel->getSerial();

            return $this->getResponse()
                ->withHeader('Content-Type', 'text/plain')
                ->withHeader('Content-Disposition', 'attachment; filename="' . $name . '-embedded.conf"')
                ->write($config);
        }

        if ($cert !== null && $wantEmbedded === null) {
            $certModel = CertificateQuery::create()->findOneByUserAndName($this->getUser(), $cert);
            $this->addClientCertificateData($zip, $certModel);

            $name .= '-' . $certModel->getName() . '.' . $certModel->getSerial();
        }

        if ($wantEmbedded === null) {
            $this->fillZipWithCaAndConfig($zip, $server);
        }

        $zip->close();

        $zipContents = file_get_contents($zipFile);
        unlink($zipFile);

        return $this->getResponse()
            ->withHeader('Content-Type', 'application/zip')
            ->withHeader('Content-Disposition', 'attachment; filename="' . $name . '.zip"')
            ->write($zipContents);
    }

    /**
     * @param \ZipArchive $zip
     * @param Server $server
     */
    public function fillZipWithCaAndConfig($zip, $server)
    {
        $config = $this->getConfigForServerFingerprint($server);
        $zip->addFromString('server.conf', $config);
        $zip->addFromString('ca.crt', file_get_contents($this->getCore()->getBaseDir() . '/storage/ca/ca.crt'));
    }

    /**
     * @param Server $server
     * @param Certificate $cert
     * @throws \Twig_Error_Loader
     * @throws \Twig_Error_Runtime
     * @throws \Twig_Error_Syntax
     * @return string
     */
    public function getEmbeddedConfig($server, $cert)
    {
        /** @var \Twig_Environment $twig */
        $twig = $this->get('twig');

        $parameters = [
            'server' => $server,
            'ca' => file_get_contents($this->getCore()->getBaseDir() . '/storage/ca/ca.crt'),
            'cert' => $cert->getCertificate(),
            'key' => '',
        ];

        if ($cert->hasPrivateKey()) {
            $parameters['key'] = $cert->getPrivateKey();
        }

        return $twig->render('etc/openvpn-client-embedded.conf.twig', $parameters);
    }

    /**
     * @param Server $server
     * @return string
     */
    public function getConfigForServerFingerprint($server)
    {
        /** @var \Twig_Environment $twig */
        $twig = $this->get('twig');

        $config = $twig->render('etc/openvpn-client.conf.twig', [
            'server' => $server
        ]);

        return $config;
    }

    /**
     * @param \ZipArchive $zip
     * @param Certificate $cert
     */
    public function addClientCertificateData($zip, $cert)
    {
        $zip->addFromString('client.crt', $cert->getCertificate());

        if ($cert->hasPrivateKey()) {
            $zip->addFromString('client.key', $cert->getPrivateKey());
        }
    }
}