<?php

namespace Drupal\straker_translate\Remote;

use Drupal\Core\Config\ConfigFactoryInterface;
use GuzzleHttp\ClientInterface;
use GuzzleHttp\RequestOptions;
use Symfony\Component\DependencyInjection\ContainerInterface;
use GuzzleHttp\Psr7\Utils;

/**
 * Straker Translate HTTP implementation using Guzzle.
 */
class StrakerTranslateHttp implements StrakerTranslateHttpInterface {

  /**
   * The HTTP client to interact with the Straker Translate service.
   *
   * @var \GuzzleHttp\Client
   */
  protected $httpClient;

  /**
   * The Straker Translate account settings.
   *
   * @var \Drupal\Core\Config\Config
   */
  protected $accountConfig;

  /**
   * The Straker Translate settings.
   *
   * @var \Drupal\Core\Config\Config
   */
  protected $config;

  /**
   * @param \GuzzleHttp\ClientInterface $http_client
   *   The Guzzle HTTP client.
   * @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
   *   The config factory.
   */
  public function __construct(ClientInterface $http_client, ConfigFactoryInterface $config_factory) {
    $this->httpClient = $http_client;
    $this->config = $config_factory->get('straker_translate.settings');
    $this->accountConfig = $config_factory->get('straker_translate.account');
  }

  /**
   * {@inheritdoc}
   */
  public static function create(ContainerInterface $container) {
    return new static(
      $container->get('http_client'),
      $container->get('config.factory')
    );
  }

  /**
   * {@inheritdoc}
   */
  public function get($path, $args = []) {
    $options = [];
    if (count($args)) {
      $options = [RequestOptions::QUERY => $args];
    }
    return $this->httpClient->get($this->getBaseUrl() . $path,
      [
        RequestOptions::HEADERS => $this->getDefaultHeaders(),
      ] + $options
    );
  }

  /**
   * {@inheritdoc}
   */
  public function post($path, $args = [], $use_multipart = FALSE) {
    $options = [];
    if (count($args) && $use_multipart) {
      $multipart = [];
      foreach ($args as $name => $contents) {
        if ($name == 'files') {
          $file_content = fopen($contents, 'r');
          $filename = \Drupal::service('file_system')->basename($contents);
          $multipart[] = [
            'name' => 'files',
            'contents' => Utils::streamFor($file_content),
            'headers' => ['Content-Type' => 'application/json'],
            'filename' => $filename,
          ];
        }
        else {
          $multipart[] = ['name' => $name, 'contents' => $contents];
        }
      }
      $options[RequestOptions::MULTIPART] = $multipart;
    }
    elseif (count($args) && !$use_multipart) {
      $options[RequestOptions::FORM_PARAMS] = $args;
    }
    return $this->httpClient->post($this->getBaseUrl() . $path,
      [
        RequestOptions::HEADERS => $this->getDefaultHeaders(),
      ] + $options
    );
  }

  /**
   * {@inheritdoc}
   */
  public function delete($path, $args = []) {
    // Let the post method masquerade as a DELETE.
    $options = [];
    if (count($args)) {
      $options = [RequestOptions::QUERY => $args];
    }
    return $this->httpClient->delete($this->getBaseUrl() . $path,
      [
        RequestOptions::HEADERS => $this->getDefaultHeaders() +
          ['X-HTTP-Method-Override' => 'DELETE'],
      ] + $options
    );
  }

  /**
   * {@inheritdoc}
   */
  public function patch($path, $args = [], $use_multipart = FALSE) {
    $options = [];
    if (count($args) && $use_multipart) {
      $multipart = [];
      foreach ($args as $name => $contents) {
        if (is_array($contents)) {
          foreach ($contents as $content) {
            $multipart[] = ['name' => $name, 'contents' => $content];
          }
        }
        else {
          $multipart[] = ['name' => $name, 'contents' => $contents];
        }
      }
      $options[RequestOptions::MULTIPART] = $multipart;
    }
    elseif (count($args) && !$use_multipart) {
      $options[RequestOptions::FORM_PARAMS] = $args;
    }
    return $this->httpClient->patch($this->getBaseUrl() . $path,
      [
        RequestOptions::HEADERS => $this->getDefaultHeaders() +
          // Let the post method masquerade as a PATCH.
          ['X-HTTP-Method-Override' => 'PATCH'],
      ] + $options
    );
  }

  /**
   * {@inheritdoc}
   */
  public function getCurrentToken() {
    return $this->accountConfig->get('access_token');
  }

  /**
   * Get the headers that are used in every request.
   *
   * @return string[]
   */
  protected function getDefaultHeaders() {
    $headers = ['Accept' => '*/*'];
    if ($token = $this->getCurrentToken()) {
      $headers['Authorization'] = 'bearer ' . $token;
    }
    return $headers;
  }

  /**
   * Gets the API base url.
   *
   * @return string
   *   The API base url.
   */
  protected function getBaseUrl() {
    $base_url = $this->accountConfig->get('host');
    return $base_url;
  }

}
