<?php

namespace Opentalent\OtTemplating\Domain\Repository;

use GuzzleHttp\Client;
use GuzzleHttp\Exception\GuzzleException;
use Opentalent\OtTemplating\Exception\ApiRequestException;
use Psr\Http\Message\ResponseInterface;
use TYPO3\CMS\Extbase\Persistence\Repository;

/**
 *  Base class for repositories based on the Opentalent API
 *
 */
abstract class BaseApiRepository extends Repository
{
    const BASE_URI = 'https://api.opentalent.fr/api/';
    const HYDRA_TYPE = '';
    const HTTP_METHOD = 'GET';
    const ITEMS_PER_PAGE = 999;

    private $client;

    public function __construct(\TYPO3\CMS\Extbase\Object\ObjectManagerInterface $objectManager) {
        parent::__construct($objectManager);
        $this->client = new Client(['base_uri' => static::BASE_URI]);
    }

    /**
     * Send a request to the API and returns
     * the result as a Response object
     *
     * @param string $uri
     * @param array $params
     * @return ResponseInterface
     * @throws ApiRequestException
     */
    protected function get($uri, $params = [])
    {
        $uri = $uri . '?_format=json&itemsPerPage=' . (string)self::ITEMS_PER_PAGE . '';
        if (!empty($params)) {
            $uri = $uri . '&' . http_build_query($params);
        }
        try {
            return $this->client->request(static::HTTP_METHOD, $uri);
        } catch (GuzzleException $e) {
            throw ApiRequestException::from_exception($e);
        }
    }

    /**
     * Send a request to the API and returns
     * the response's body as a string
     *
     * @param string $uri
     * @param array $params
     * @return string
     * @throws ApiRequestException
     */
    protected function getBody($uri, $params = [])
    {
        try {
            return (string)$this->get($uri, $params)->getBody();
        } catch (GuzzleException $e) {
            throw ApiRequestException::from_exception($e);
        }
    }

    /**
     * Send a request to the API and
     * returns the Json response as an array
     *
     * @param string $uri
     * @param array $params
     * @return array
     * @throws ApiRequestException
     */
    protected function getJson($uri, $params = [])
    {
        return json_decode($this->getBody($uri, $params));
    }

    /**
     * Send a request to the API and
     * returns the records as an array (members)
     *
     * @param string $uri
     * @param array $params
     * @return array
     * @throws ApiRequestException
     */
    protected function getApiRecords($uri, $params = []) {
        try {
            $data = $this->getJson($uri, $params);
        } catch (GuzzleException $e) {
            throw ApiRequestException::from_exception($e);
        }

        if($data->{'@type'} == 'hydra:PagedCollection') {
            $records = $data->{'hydra:member'};
        } else if ($data->{'@type'} == $this::HYDRA_TYPE) {
            $records = [$data];
        } else {
            throw new ApiRequestException('The API response has an unexpected format');
        }
        return $records;
    }

    /**
     * Send a request to the API and
     * returns the first record (member)
     *
     * @param string $uri
     * @param array $params
     * @return array
     * @throws ApiRequestException
     */
    protected function getApiFirstRecord($uri, $params = []) {
        try {
            $records = $this->getApiRecords($uri, $params);
        } catch (GuzzleException $e) {
            throw ApiRequestException::from_exception($e);
        }
        return $records[0];
    }
}
