<?php

namespace Docuform\Api\Authentication;

use DI\DependencyException;
use DI\NotFoundException;
use Docuform\Api\Authentication\OAuth2Server\AuthorizationServerMps;
use Docuform\Api\Exception\ApiHttpException;
use Docuform\Api\HttpRequestHandler;
use Exception;
use Nyholm\Psr7\Stream;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;

class Certs extends HttpRequestHandler
{
  /**
   * @param   ServerRequestInterface  $request
   *
   * @return  array
   */
  public function getAllowedUserTypes($request): array
  {
    return [];
  }

  /**
   * @param   ServerRequestInterface  $request
   *
   * @return  array
   */
  public function getRequiredScopes($request): array
  {
    return [
      'allOf' => [],
      'anyOf' => []
    ];
  }

  /**
   * @param   ServerRequestInterface  $request
   * @param   ResponseInterface       $response
   * @param   array                   $arguments
   *
   * @return int HTTP code
   *
   * @throws DependencyException
   * @throws NotFoundException
   */
  public function handleRequest($request, &$response, $arguments): int
  {
    $code = 500;

    /** @var AuthorizationServerMps $server */
    $server  = $this->getContainer()->get('authserver');

    if ($server !== null)
    {
      try
      {
        $errDescription = '';

        return $this->handleGetCertificates($response);
      }
      catch (ApiHttpException $exception)
      {
        $code = $exception->getCode();

        $this->getLogger()->error($exception->getMessage() . ': ' . $exception->getDescription());

        $errorMessage = $exception->getMessage();
        $errDescription = $exception->getDescription();
      }
      catch (Exception $exception)
      {
        $this->getLogger()->error($exception->getMessage());

        $errorMessage = 'Server error';
      }

      if (!empty($errorMessage))
      {
        $jsPayload = ['error' => $errorMessage, 'error_description' => $errDescription];

        $bodyStream = Stream::create();

        $bodyStream->write(json_encode($jsPayload, JSON_UNESCAPED_SLASHES));

        $response = $response->withStatus($code)->withHeader('Content-Type', 'application/json')->withBody($bodyStream);
      }
    }

    return $code;
  }


  /**
   * @param ResponseInterface $response
   *
   * @return int
   * @throws DependencyException
   * @throws NotFoundException
   */
  private function handleGetCertificates(ResponseInterface $response): int
  {
    global $apiSettings;

    $code = 500;

    $jsonData = [];

    $publicKeyFile = $apiSettings['public_key_file'];

    try
    {
      $keyInfo = openssl_pkey_get_details(openssl_pkey_get_public(file_get_contents($publicKeyFile)));

      if (!empty($keyInfo))
      {
        $jsonData = [
          'keys' => [
            [
              'kty' => 'RSA',
              'alg' => 'RS256',
              'kid' => 'mpskey',
              'n' => rtrim(str_replace(['+', '/'], ['-', '_'], base64_encode($keyInfo['rsa']['n'])), '='),
              'e' => rtrim(str_replace(['+', '/'], ['-', '_'], base64_encode($keyInfo['rsa']['e'])), '='),
            ],
          ],
        ];

        $code = 200;
      }
    }
    catch (Exception $e)
    {
      $code = 500;
      $jsonData = [];
      $this->getLogger()->error('Exception while generating JWK: ' . $e->getMessage());
    }

    $json = json_encode($jsonData, JSON_UNESCAPED_SLASHES);

    $response->getBody()->write($json);

    return $code;
  }
}
