<?php

namespace Drupal\miniorange_2fa\Authentication\Provider;

use Drupal\basic_auth\Authentication\Provider\BasicAuth;
use Drupal\Core\Authentication\AuthenticationProviderInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Session\AccountInterface;
use Drupal\Core\Config\ConfigFactoryInterface;
use Drupal\user\UserInterface;
use Psr\Log\LoggerInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;

/**
 * Decorates the basic authentication provider to enforce 2FA.
 */
class TfaBasicAuthDecorator implements AuthenticationProviderInterface {

  /**
   * The decorated basic authentication provider.
   *
   * @var \Drupal\basic_auth\Authentication\Provider\BasicAuth
   */
  protected $innerAuthenticationProvider;

  /**
   * The current user.
   *
   * @var \Drupal\Core\Session\AccountInterface
   */
  protected $currentUser;

  /**
   * The entity type manager.
   *
   * @var \Drupal\Core\Entity\EntityTypeManagerInterface
   */
  protected $entityTypeManager;

  /**
   * The logger.
   *
   * @var \Psr\Log\LoggerInterface
   */
  protected $logger;

  /**
   * The configuration factory.
   *
   * @var \Drupal\Core\Config\ConfigFactoryInterface
   */
  protected $configFactory;

  /**
   * Constructs a TfaBasicAuthDecorator object.
   *
   * @param \Drupal\basic_auth\Authentication\Provider\BasicAuth $inner_authentication_provider
   *   The decorated basic authentication provider.
   * @param \Drupal\Core\Session\AccountInterface $current_user
   *   The current user.
   * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
   *   The entity type manager.
   * @param \Psr\Log\LoggerInterface $logger
   *   The logger.
   * @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
   *   The configuration factory.
   */
  public function __construct(
    BasicAuth $inner_authentication_provider,
    AccountInterface $current_user,
    EntityTypeManagerInterface $entity_type_manager,
    LoggerInterface $logger,
    ConfigFactoryInterface $config_factory
  ) {
    $this->innerAuthenticationProvider = $inner_authentication_provider;
    $this->currentUser = $current_user;
    $this->entityTypeManager = $entity_type_manager;
    $this->logger = $logger;
    $this->configFactory = $config_factory;
  }

  /**
   * {@inheritdoc}
   */
  public function applies(Request $request) {
    return $this->innerAuthenticationProvider->applies($request);
  }

  /**
   * {@inheritdoc}
   */
  public function authenticate(Request $request) {
    $account = $this->innerAuthenticationProvider->authenticate($request);

    if ($account) {
      $user = $this->entityTypeManager->getStorage('user')->load($account->id());

      if ($user instanceof UserInterface && $this->is2faRequired($user)) {
        $this->logger->warning('API access blocked: User @user attempted to use Basic Auth without completed 2FA.', [
          '@user' => $user->getAccountName(),
        ]);

        // Throw an exception to deny access.
        throw new AccessDeniedHttpException('API access denied. Two-factor authentication is required.');
      }
    }

    return $account;
  }

  /**
   * Determines if 2FA is required for the given user.
   *
   * @param \Drupal\user\UserInterface $user
   *   The user entity.
   *
   * @return bool
   *   TRUE if 2FA is required, FALSE otherwise.
   */
  protected function is2faRequired(UserInterface $user) {
    // $uesr object is passed for further use, if needed.
    $config = $this->configFactory->get('miniorange_2fa.settings');
    return $config->get('mo_auth_enable_two_factor');
  }
}
