<?php

namespace Docuform\Api\Authentication\OAuth2Server;

use DI\Container;
use DI\DependencyException;
use DI\NotFoundException;
use Docuform\Api\ApiUser;
use Docuform\Api\Authentication\AuthApi;
use Docuform\Api\Authentication\Entities\ScopeEntity;
use Docuform\Api\Authentication\Entities\UserEntity;
use Docuform\Api\Authentication\Repositories\UserRepository;
use Docuform\Database\DbException;
use League\OAuth2\Server\Entities\AccessTokenEntityInterface;
use League\OAuth2\Server\Exception\OAuthServerException;
use League\OAuth2\Server\ResponseTypes\BearerTokenResponse;
use Psr\Log\LoggerInterface;
use Docuform\Api\ApiScopes;

class BearerTokenResponseMps extends BearerTokenResponse
{
  /**
   * @param AccessTokenEntityInterface $accessToken
   * @return array
   * @throws DbException
   * @throws DependencyException
   * @throws NotFoundException
   * @throws OAuthServerException
   */
  protected function getExtraParams(AccessTokenEntityInterface $accessToken): array
  {
    $extraParams = [];

    $container = $accessToken->getContainer();

    /** @var LoggerInterface $logger */
    $logger = $container->get('logger');

    /** @var AuthApi $authApi */
    $authApi = $container->get('RestApi');

    $serverApiUrl = '';
    $error = '';
    $user = null;
    $authApi->CheckServerState($serverApiUrl, $error);

    $extraParams['server_api_url'] = $serverApiUrl;

    $scopes = [];

    /** @var ScopeEntity $scope */
    foreach ($accessToken->getScopes() as $scope)
    {
      $scopes[] = $scope->getIdentifier();
    }

    $extraParams['scope'] = implode(' ', $scopes);

    $sub = $accessToken->getUserIdentifier();

    if (!empty($sub))
    {
      $logger->debug("token: Retrieve user " . $sub);

      /** @var ApiUser $user */
      if (($user = $this->getUser($accessToken->getContainer(), $sub)) !== false && $user->isValid)
      {
        $logger->debug("User " . $user->id . ' (' . $user->name . ') authorized');

        // Adding User-Id to response
        $extraParams['user_id'] = $user->id;
      }
      else
      {
        if (!empty($user->id) && !$user->isValid)
        {
          throw OAuthServerException::invalidGrant('User not valid');
        }

        throw OAuthServerException::invalidGrant();
      }
    }

    if ($user !== null &&
      (in_array(ApiScopes::client_write, $scopes, true) ||
       in_array(ApiScopes::client_read, $scopes, true) ||
       in_array(ApiScopes::bulk, $scopes, true) ||
       in_array(ApiScopes::admin, $scopes, true)))
    {

      $clientApiUrl = $authApi->getClientApiUrl($user);

      $extraParams['client_api_url'] = $clientApiUrl;
    }

    return $extraParams;
  }


  /**
   * @param Container $container
   * @param string $uuid
   * @return bool|UserEntity
   * @throws DbException
   * @throws DependencyException
   * @throws NotFoundException
   */
  private function getUser(Container $container, string $uuid): bool|UserEntity
  {
    $user = false;

    if (!empty($uuid))
    {
      $userrepo = new UserRepository($container);

      $user = $userrepo->getUserEntityByUuid($uuid);

      if (!($user instanceof UserEntity))
      {
        $user = false;
      }
    }

    return $user;
  }
}
