<?php
namespace API\GovZaCsd;

use API\Partenaire\BaseWs;
use API\Partenaire\Exception\WsInvalidResponse;
use Entity\Model\Dilispec;
use GuzzleHttp\Client;
use GuzzleHttp\Psr7\Request;
use GuzzleHttp\Utils;
use Psr\Container\ContainerInterface;
use Psr\Http\Message\ResponseInterface;
use Helpers\Session\ParseBase1;

/**
 * @see https://csdapi.green-field.co.za/Help
 */
class GovZaCsdWs extends BaseWs
{
    private ?Client $client = null;
    private string $baseUrl; //= 'https://csdapi.green-field.co.za/api';

    private string $apiKey;

//_____________________________________________________________________________
// Constructor

    public function __construct(
        string $baseUrl,
        string $apiKey
    ) {
        $this->baseUrl = trim($baseUrl, '/');
        $this->apiKey = $apiKey;
    }

    public static function createFromConfig(ContainerInterface $container) :GovZaCsdWs
    {
        /** @var \PDO */
        $pdo = $container->get('PDO.oxasql');
        $dilispec = (new Dilispec($pdo))->findAll(['TYPEDICO' => 'CSD']);
        
        $paramDB = array_column($dilispec, 'LIB01DICO', 'CODEDICO');
        /** @var array<mixed> */
        $param = Utils::jsonDecode(
            // TODO : get _etc from container
            (string) @file_get_contents(
                (new ParseBase1())->getRep()->etc.'API/externe/CSD/Parametres.json',
                true
            ),
            true
        );
        $env = $param[ $paramDB['TYPE_ENVIRONNEMENT'] ];
        return new GovZaCsdWs(
            $env['base_url'],
            $paramDB['API_KEY'],
        );
    }

//_____________________________________________________________________________
// Accessor

    protected function getBaseUrl() :string
    {
        return $this->baseUrl;
    }

    protected function getGuzzleClient() :Client
    {
        if ($this->client == null) {
            $this->client = new Client(['http_errors' => false]);
        }
        return $this->client;
    }

//_____________________________________________________________________________
// Process

    /**
     * @param array{
     *     name?:string,
     *     city?:string,
     *     registrationNumber?:string
     * } $query
     * @return array<\stdClass>
     */
    public function search(array $query) :array
    {
        $response = $this->send($request = $this->createRequest(
            'POST',
            '/Suppliers',
            [
                'Commoditylevel' => '',
                'City' => $query['city'] ?? '',
                'Province' => '',
                'SupplierName' => $query['name'] ?? '',
                'CSDNumber' => $query['registrationNumber'] ?? '',
                'Results' => 25,
            ]
        ));
        
        if (! $this->isValidHttpCodeStatus($response->getStatusCode())) {
            throw new WsInvalidResponse($request, $response);
        }

        /** @var mixed */
        $payload = Utils::jsonDecode($response->getBody());

        if (!is_array($payload)) {
            throw new WsInvalidResponse($request, $response);
        }
        return $payload;
    }

    /**
     * @_return ?object{SupplierIdentification:\stdClass}
     * @return ?\stdClass
     */
    public function companyInfo(string $csdNumber) :?object
    {
        $response = $this->send($request = $this->createRequest(
            'POST',
            '/Suppliers/SupplierDetails?'
            . http_build_query([
                'CSDNumber' => $csdNumber,
            ])
        ));

        if (! $this->isValidHttpCodeStatus($response->getStatusCode())) {
            throw new WsInvalidResponse($request, $response);
        }

        /** @var object{organization:object} */
        /** @var \stdClass */
        $payload = Utils::jsonDecode($response->getBody());

        return $payload->SupplierDetails ?? null;
    }

//_____________________________________________________________________________
// Sub-routine

    protected function send(Request $request) :ResponseInterface
    {
        return $this->getGuzzleClient()
            ->send($request);
    }

    /**
     * @param ?array<mixed> $jsonPayload
     */
    protected function createRequest(
        string $method,
        string $path,
        ?array $jsonPayload = null
    ) :Request {
        return new Request(
            $method,
            $this->getBaseUrl() . $path,
            [
                'Accept' => 'application/json',
                'API_Key' => $this->apiKey,
            ]
            + (! empty($jsonPayload) ? ['Content-Type' => 'application/json'] : []),
            ! empty($jsonPayload) ? Utils::jsonEncode($jsonPayload) : null
        );
    }
}
