<?php

namespace Drupal\social_auth_vk;

use Drupal\Core\Config\ConfigFactory;
use Drupal\Core\Logger\LoggerChannelFactoryInterface;
use Drupal\social_auth\AuthManager\OAuth2Manager;
use Drupal\social_auth\User\SocialAuthUser;
use Drupal\social_auth\User\SocialAuthUserInterface;
use Symfony\Component\HttpFoundation\RequestStack;
use VK\OAuth\Scopes\VKOAuthUserScope;
use VK\OAuth\VKOAuthDisplay;
use VK\OAuth\VKOAuthResponseType;

/**
 * Contains all the logic for VK OAuth2 authentication.
 */
class VkAuthManager extends OAuth2Manager {

  /**
   * Auth manager.
   *
   * @param \Drupal\Core\Config\ConfigFactory $configFactory
   *   The configuration factory.
   * @param \Drupal\Core\Logger\LoggerChannelFactoryInterface $loggerFactory
   *   The logger factory.
   * @param \Symfony\Component\HttpFoundation\RequestStack $requestStack
   *   The request stack.
   */
  public function __construct(
    ConfigFactory $configFactory,
    LoggerChannelFactoryInterface $loggerFactory,
    RequestStack $requestStack
  ) {
    parent::__construct(
      $configFactory->get('social_auth_vk.settings'),
      $loggerFactory,
      $this->request = $requestStack->getCurrentRequest()
    );
  }

  /**
   * {@inheritdoc}
   */
  public function getAuthorizationUrl(): string {
    $scopes = [VKOAuthUserScope::EMAIL, VKOAuthUserScope::OFFLINE];

    $extraScopes = $this->getScopes();
    if (!empty($extraScopes)) {
      $scopes = array_unique($scopes + explode(',', $extraScopes));
    }

    // Returns the URL where user will be redirected.
    return $this->client->getAuthorizationUrl([
      'response_type' => VKOAuthResponseType::CODE,
      'display' => VKOAuthDisplay::PAGE,
      'scope' => $scopes,
    ]);
  }

  /**
   * {@inheritdoc}
   */
  public function authenticate(): void {
    try {
      $code = $this->request->query->get('code');
      $this->setAccessToken($this->client->getAccessToken(NULL, ['code' => $code]));
    }
    catch (\Throwable $exception) {
      $this->loggerFactory->get('social_auth_vk')
        ->error('There was an error during authentication. Exception: ' . $exception->getMessage());
    }
  }

  /**
   * {@inheritdoc}
   */
  public function getUserInfo(): ?SocialAuthUserInterface {
    if (!$this->user) {
      try {
        /** @var \Drupal\social_auth_vk\OAuth2\Client\Provider\VkUser $owner */
        $owner = $this->client->getResourceOwner($this->getAccessToken());
        $user = new SocialAuthUser(
          trim("{$owner->getFirstName()} {$owner->getLastName()}"),
          $owner->getId(),
          $this->getAccessToken(),
          $owner->getEmail(),
          $owner->getImageUrl(),
        );
        $user->setFirstName($owner->getFirstName());
        $user->setLastName($owner->getLastName());
        $this->user = $user;
      }
      catch (\Throwable $exception) {
        $this->loggerFactory->get('social_auth_vk')
          ->error('There was an error during retrieving user data. Exception: ' . $exception->getMessage());

        return NULL;
      }
    }
    return $this->user;
  }

  /**
   * {@inheritdoc}
   */
  public function getState(): string {
    return $this->client->getState();
  }

  /**
   * {@inheritDoc}
   */
  public function requestEndPoint(string $method, string $path, ?string $domain = NULL, array $options = []): mixed {
    throw new \BadMethodCallException('Not implemented/used');
  }

}
