<?php

declare(strict_types=1);

/*
 * Chill is a software for social workers
 *
 * For the full copyright and license information, please view
 * the LICENSE file that was distributed with this source code.
 */

namespace Chill\FranceTravailApiBundle\ApiHelper;

use GuzzleHttp\Client;
use GuzzleHttp\Psr7\Request;
use GuzzleHttp\Exception\ClientException;
use GuzzleHttp\Exception\BadResponseException;
use GuzzleHttp\Psr7;
use Psr\Log\LoggerInterface;

/**
 * Methods to process request against the api, and handle the
 * Exceptions.
 */
trait ProcessRequestTrait
{
    /**
     * Handle a request and 429 errors.
     *
     * @param Request $request    the request
     * @param array   $parameters the requests parameters
     */
    protected function handleRequest(
        Request $request,
        array $parameters,
        Client $client,
        LoggerInterface $logger,
    ) {
        return $this->handleRequestRecursive(
            $request,
            $parameters,
            $client,
            $logger
        );
    }

    /**
     * internal method to handle recursive requests.
     *
     * @throws BadResponseException
     */
    private function handleRequestRecursive(
        Request $request,
        array $parameters,
        Client $client,
        LoggerInterface $logger,
        $counter = 0,
    ) {
        try {
            return $client->send($request, $parameters);
        } catch (BadResponseException $e) {
            if (
                // get 429 exceptions
                $e instanceof ClientException
                && 429 === $e->getResponse()->getStatusCode()
                && count($e->getResponse()->getHeader('Retry-After')) > 0) {
                if ($counter > 5) {
                    $logger->error('too much 429 response', [
                        'request' => Psr7\get($e->getRequest()),
                    ]);

                    throw $e;
                }

                $delays = $e->getResponse()->getHeader('Retry-After');
                $delay = \end($delays);

                sleep($delay);

                return $this->handleRequestRecursive(
                    $request,
                    $parameters,
                    $client,
                    $logger,
                    $counter + 1
                );
            }

            // handling other errors
            $logger->error('Error while querying ROME api', [
                'status_code' => $e->getResponse()->getStatusCode(),
                'part' => 'appellation',
                'request' => $e->getRequest()->getBody()->getContents(),
                'response' => $e->getResponse()->getBody()->getContents(),
            ]);

            throw $e;
        }
    }
}
