<?php

declare(strict_types=1);

namespace Drupal\languagewire_translation_provider\api;

use Drupal\languagewire_translation_provider\api\Core\Authenticator;
use Drupal\languagewire_translation_provider\api\Core\Exception\Error;
use Drupal\languagewire_translation_provider\api\Core\ProjectAPILibraryInterface;
use Drupal\languagewire_translation_provider\api\Core\Settings;
use Drupal\languagewire_translation_provider\api\Managers\ConfigManager;

/**
 * Factory for creating new instances of the Project API Library.
 */
class ProjectAPILibraryFactory {

  /**
   * Creates a new settings instance with the provided authorization token.
   *
   * @param string $authorizationToken
   *   The authorization token.
   * @param string|null $endpointUri
   *   The endpoint URI.
   *
   * @return \Drupal\languagewire_translation_provider\api\Core\Settings
   *   The settings instance.
   *
   * @throws \Drupal\languagewire_translation_provider\api\Core\Exception\Error
   */
  public static function createNewSettingsTokenInstance(string $authorizationToken, ?string $endpointUri = NULL): Settings {
    return new Settings($endpointUri ?? self::getDefaultEndpointUri(), $authorizationToken);
  }

  /**
   * Creates a new settings instance with client ID and client secret.
   *
   * @param string $clientID
   *   The client ID.
   * @param string $clientSecret
   *   The client secret.
   * @param string|null $endpointUri
   *   The endpoint URI.
   *
   * @return \Drupal\languagewire_translation_provider\api\Core\Settings
   *   The settings instance.
   *
   * @throws \Drupal\languagewire_translation_provider\api\Core\Exception\Error
   */
  public static function createNewSettingsCredentialsInstance(string $clientID, string $clientSecret, ?string $endpointUri = NULL): Settings {
    return new Settings(
          $endpointUri ?? self::getDefaultEndpointUri(),
          self::createNewAuthenticationToken($clientID, $clientSecret)
      );
  }

  /**
   * Creates a new instance with authorization token.
   *
   * @param string $className
   *   The class name.
   * @param string $authorizationToken
   *   The authorization token.
   * @param string|null $endpointUri
   *   The endpoint URI.
   *
   * @return \Drupal\languagewire_translation_provider\api\Core\ProjectAPILibraryInterface
   *   The project API library instance.
   *
   * @throws \Drupal\languagewire_translation_provider\api\Core\Exception\Error
   */
  public static function createNewTokenInstance(string $className, string $authorizationToken, ?string $endpointUri = NULL): ProjectAPILibraryInterface {
    if (!class_exists($className) || !is_subclass_of($className, ProjectAPILibraryInterface::class)) {
      throw new Error('Invalid Endpoint');
    }

    return new $className(
          self::createNewSettingsTokenInstance(
              $authorizationToken,
              $endpointUri ?? self::getDefaultEndpointUri()
          )
      );
  }

  /**
   * Creates a new instance with client ID and client secret.
   *
   * @param string $className
   *   The class name.
   * @param string $clientID
   *   The client ID.
   * @param string $clientSecret
   *   The client secret.
   * @param string|null $endpointUri
   *   The endpoint URI.
   *
   * @return \Drupal\languagewire_translation_provider\api\Core\ProjectAPILibraryInterface
   *   The project API library instance.
   *
   * @throws \Drupal\languagewire_translation_provider\api\Core\Exception\Error
   */
  public static function createNewAuthenticationInstance(string $className, string $clientID, string $clientSecret, ?string $endpointUri = NULL): ProjectAPILibraryInterface {
    return self::createNewTokenInstance(
          $className,
          self::createNewAuthenticationToken($clientID, $clientSecret),
          $endpointUri ?? self::getDefaultEndpointUri()
      );
  }

  /**
   * Creates a new authentication token.
   *
   * @param string $clientID
   *   The client ID.
   * @param string $clientSecret
   *   The client secret.
   *
   * @return string
   *   The authentication token.
   *
   * @throws \Drupal\languagewire_translation_provider\api\Core\Exception\Error
   */
  public static function createNewAuthenticationToken(string $clientID, string $clientSecret): string {
    // Start config manager.
    new ConfigManager();

    return (new Authenticator($clientID, $clientSecret))->authenticate();
  }

  /**
   * Gets the default endpoint URI.
   *
   * @throws \Drupal\languagewire_translation_provider\api\Core\Exception\Error
   */
  private static function getDefaultEndpointUri(): string {
    // Start config manager.
    new ConfigManager();

    if (!defined('PROJECT_API_ENDPOINT')) {
      throw new Error('No endpoint to call');
    }

    return PROJECT_API_ENDPOINT;
  }

}
