<?php

declare(strict_types=1);

namespace Drupal\netforum\xWeb;

use Drupal\netforum\xWeb\Generated\StructType\AuthorizationToken;

/**
 * Handle the Authorization token by reusing it for the lifetime of an instance
 * of the SoapClient. This also handles sliding authorization token expiration.
 */
class InstanceAuthTokenHandler extends AuthTokenHandler {

  /**
   * Before each SOAP call, check if an Authorization Token is needed and set.
   * If not, authenticate with xWeb to get one.
   *
   * @throws \Drupal\netforum\xWeb\Exception\AuthFailedException
   */
  public function preSoapCall(string $name, SoapClient $soapClient, array|null $requestHeaders): void {
    parent::preSoapCall($name, $soapClient, $requestHeaders);

    if ($this->isNoAuthTokenFunction($name)) {
      return;
    }

    if (is_array($requestHeaders)) {
      $hasAuthToken = array_any($requestHeaders, fn($requestHeader) => $requestHeader->name === 'AuthorizationToken');
      if ($hasAuthToken) {
        return;
      }
    }

    // There is no authorization token set, so xweb authentication is needed.
    $this->authenticate();
  }

  /**
   * After each SOAP call, save the Authorization Token for future calls.
   */
  public function postSoapCall(string $name, SoapClient $soapClient, array|null $responseHeaders): void {
    parent::postSoapCall($name, $soapClient, $responseHeaders);

    // If there is an authorization token in the last response, reuse it for
    // subsequent requests. This handles sliding authorization token expiration
    // policy.
    if (is_array($responseHeaders)) {
      foreach ($responseHeaders as $responseHeader) {
        if ($responseHeader instanceof AuthorizationToken) {
          SoapClientBase::setSoapHeaderOn($soapClient, NetForumXml::XML_NAMESPACE, 'AuthorizationToken', $responseHeader);
        }
      }
    }
  }

  public function handlesTokenExpiry(): bool {
    return TRUE;
  }

}
