<?php

declare(strict_types=1);

namespace Drupal\netforum;

use Drupal\netforum\xWeb\AuthTokenHandlerInterface;
use Drupal\netforum\xWeb\NetForumXml;
use Psr\Log\LoggerInterface;

/**
 * Configuration for the generated NetForum xWeb SDK.
 */
class NetForumXmlServiceOptions {

  /**
   * Contains the options to pass to the NetForumXml service when instantiating
   * a new instance.
   *
   * @var array
   */
  protected array $serviceOptions = [];

  /**
   * Custom stream context to set settings on.
   *
   * @var resource
   */
  private $streamContext;

  public function __construct() {
    $this->streamContext = stream_context_create();

    // By default, set a custom stream context to allow setting options.
    $this->serviceOptions[NetForumXml::WSDL_STREAM_CONTEXT] = $this->streamContext;
  }

  public function setWsdlCache(SoapWsdlCacheType $cacheWsdlType): static {
    $this->serviceOptions[NetForumXml::WSDL_CACHE_WSDL] = $cacheWsdlType->toSoapOptionValue();

    return $this;
  }

  public function getWsdlCache(): ?SoapWsdlCacheType {
    if (isset($this->serviceOptions[NetForumXml::WSDL_CACHE_WSDL])) {
      return SoapWsdlCacheType::fromSoapOptionValue($this->serviceOptions[NetForumXml::WSDL_CACHE_WSDL]);
    }

    return NULL;
  }

  public function setClassMap(array $classmap): static {
    $this->serviceOptions[NetForumXml::WSDL_CLASSMAP] = $classmap;

    return $this;
  }

  public function getClassMap(): array {
    return $this->serviceOptions[NetForumXml::WSDL_CLASSMAP];
  }

  public function setWsdl(string $wsdlUrl): static {
    $this->serviceOptions[NetForumXml::WSDL_URL] = $wsdlUrl;

    return $this;
  }

  public function getWsdl(): string {
    return $this->serviceOptions[NetForumXml::WSDL_URL];
  }

  public function getEndpoint(): string {
    return $this->serviceOptions[NetForumXml::WSDL_LOCATION];
  }

  public function setEndpoint(string $endpoint): static {
    $this->serviceOptions[NetForumXml::WSDL_LOCATION] = $endpoint;

    return $this;
  }

  public function setUserAgent(string $userAgent): static {
    $this->serviceOptions[NetForumXml::WSDL_USER_AGENT] = $userAgent;

    return $this;
  }

  public function getUserAgent(): string {
    return $this->serviceOptions[NetForumXml::WSDL_USER_AGENT];
  }

  public function setRequestTimeout(int $timeout): static {
    $this->serviceOptions[NetForumXml::WSDL_CONNECTION_TIMEOUT] = $timeout;

    stream_context_set_option($this->streamContext, 'http', 'timeout', $timeout);

    return $this;
  }

  public function getRequestTimeout(): int {
    return $this->serviceOptions[NetForumXml::WSDL_CONNECTION_TIMEOUT];
  }

  public function setHttpKeepalive(bool $httpKeepalive): static {
    $this->serviceOptions[NetForumXml::WSDL_KEEP_ALIVE] = $httpKeepalive;

    return $this;
  }

  public function getHttpKeepalive(): bool {
    return $this->serviceOptions[NetForumXml::WSDL_KEEP_ALIVE];
  }

  public function setHttpCompression(bool $httpCompression): static {
    if ($httpCompression) {
      $this->serviceOptions[NetForumXml::WSDL_COMPRESSION] = SOAP_COMPRESSION_ACCEPT | SOAP_COMPRESSION_GZIP | 6;
    }
    else {
      unset($this->serviceOptions[NetForumXml::WSDL_COMPRESSION]);
    }

    return $this;
  }

  public function getHttpCompression(): bool {
    return isset($this->serviceOptions[NetForumXml::WSDL_COMPRESSION]);
  }

  public function setVerifyTls(bool $verifyTls): static {
    stream_context_set_option($this->streamContext, 'ssl', 'verify_peer', $verifyTls);
    stream_context_set_option($this->streamContext, 'ssl', 'verify_peer_name', $verifyTls);
    stream_context_set_option($this->streamContext, 'ssl', 'allow_self_signed', !$verifyTls);

    return $this;
  }

  public function getVerifyTls(): bool {
    $streamOptions = stream_context_get_options($this->streamContext);

    if (!empty($streamOptions['ssl'])) {
      return $streamOptions['ssl']['verify_peer'] && $streamOptions['ssl']['verify_peer_name'] && !$streamOptions['ssl']['allow_self_signed'];
    }

    // By default, TLS is verified.
    return TRUE;
  }

  public function setHttpAuth(bool $enabled, SoapHttpAuthenticationType $authType = SoapHttpAuthenticationType::Basic, string $username = '', string $password = ''): static {
    if ($enabled) {
      $this->serviceOptions[NetForumXml::WSDL_LOGIN] = $username;
      $this->serviceOptions[NetForumXml::WSDL_PASSWORD] = $password;
      $this->serviceOptions[NetForumXml::WSDL_AUTHENTICATION] = $authType->toSoapOptionValue();
    }
    else {
      unset($this->serviceOptions[NetForumXml::WSDL_LOGIN]);
      unset($this->serviceOptions[NetForumXml::WSDL_PASSWORD]);
      unset($this->serviceOptions[NetForumXml::WSDL_AUTHENTICATION]);
    }

    return $this;
  }

  public function getHttpAuthEnabled(): bool {
    return !is_null($this->getHttpAuthType());
  }

  public function getHttpAuthType(): ?SoapHttpAuthenticationType {
    if (isset($this->serviceOptions[NetForumXml::WSDL_AUTHENTICATION])) {
      return SoapHttpAuthenticationType::fromSoapOptionValue($this->serviceOptions[NetForumXml::WSDL_AUTHENTICATION]);
    }

    return NULL;
  }

  public function getHttpAuthUsername(): ?string {
    if (isset($this->serviceOptions[NetForumXml::WSDL_LOGIN])) {
      return $this->serviceOptions[NetForumXml::WSDL_LOGIN];
    }

    return NULL;
  }

  public function getHttpAuthPassword(): ?string {
    if (isset($this->serviceOptions[NetForumXml::WSDL_PASSWORD])) {
      return $this->serviceOptions[NetForumXml::WSDL_PASSWORD];
    }

    return NULL;
  }

  public function setProxyServer(bool $enabled, string $hostname, int $port, string $username = '', string $password = ''): static {
    if ($enabled) {
      $this->serviceOptions[NetForumXml::WSDL_PROXY_HOST] = $hostname;
      $this->serviceOptions[NetForumXml::WSDL_PROXY_PORT] = $port;

      if (!empty($username)) {
        $this->serviceOptions[NetForumXml::WSDL_PROXY_LOGIN] = $username;
      }

      if (!empty($password)) {
        $this->serviceOptions[NetForumXml::WSDL_PROXY_PASSWORD] = $password;
      }
    }
    else {
      unset($this->serviceOptions[NetForumXml::WSDL_PROXY_HOST]);
      unset($this->serviceOptions[NetForumXml::WSDL_PROXY_PORT]);
      unset($this->serviceOptions[NetForumXml::WSDL_PROXY_LOGIN]);
      unset($this->serviceOptions[NetForumXml::WSDL_PROXY_PASSWORD]);
    }

    return $this;
  }

  public function getProxyServerEnabled(): ?bool {
    return !is_null($this->getProxyServerHostname());
  }

  public function getProxyServerHostname(): ?string {
    if (isset($this->serviceOptions[NetForumXml::WSDL_PROXY_HOST])) {
      return $this->serviceOptions[NetForumXml::WSDL_PROXY_HOST];
    }

    return NULL;
  }

  public function getProxyServerPort(): ?int {
    if (isset($this->serviceOptions[NetForumXml::WSDL_PROXY_PORT])) {
      return $this->serviceOptions[NetForumXml::WSDL_PROXY_PORT];
    }

    return NULL;
  }

  public function getProxyServerPassword(): ?string {
    if (isset($this->serviceOptions[NetForumXml::WSDL_PROXY_PASSWORD])) {
      return $this->serviceOptions[NetForumXml::WSDL_PROXY_PASSWORD];
    }

    return NULL;
  }

  public function getProxyServerUsername(): ?string {
    if (isset($this->serviceOptions[NetForumXml::WSDL_PROXY_LOGIN])) {
      return $this->serviceOptions[NetForumXml::WSDL_PROXY_LOGIN];
    }

    return NULL;
  }

  public function setAuthTokenHandler(AuthTokenHandlerInterface $authTokenHandler): static {
    $this->serviceOptions[NetForumXml::XWEB_AUTH_TOKEN_HANDLER] = $authTokenHandler;

    return $this;
  }

  public function setLogHandler(LoggerInterface $logHandler): static {
    $this->serviceOptions[NetForumXml::XWEB_LOG_HANDLER] = $logHandler;

    return $this;
  }

  public function getLogHandler(): ?LoggerInterface {
    if (isset($this->serviceOptions[NetForumXml::XWEB_LOG_HANDLER])) {
      return $this->serviceOptions[NetForumXml::XWEB_LOG_HANDLER];
    }

    return NULL;
  }

  public function setDebugLogAll(bool $debugLogAll): static {
    $this->serviceOptions[NetForumXml::XWEB_DEBUG_LOG_ALL] = $debugLogAll;

    return $this;
  }

  public function getDebugLogAll(): ?bool {
    if (isset($this->serviceOptions[NetForumXml::XWEB_DEBUG_LOG_ALL])) {
      return $this->serviceOptions[NetForumXml::XWEB_DEBUG_LOG_ALL];
    }

    return NULL;
  }

  public function getAuthTokenHandler(): ?AuthTokenHandlerInterface {
    if (isset($this->serviceOptions[NetForumXml::XWEB_AUTH_TOKEN_HANDLER])) {
      return $this->serviceOptions[NetForumXml::XWEB_AUTH_TOKEN_HANDLER];
    }

    return NULL;
  }

  public function getOptions(): array {
    return $this->serviceOptions;
  }

}
