<?php
namespace ElixForms\Auth;

use Api\Core\HttpClient;
use ElixForms\Exceptions\ElixFormsException;

class ElixFormsApiClient
{
    private string $baseUrl;
    private HttpClient $httpClient;

    public function __construct(string $baseUrl, HttpClient $httpClient)
    {
        $this->baseUrl = rtrim($baseUrl, '/');
        $this->httpClient = $httpClient;
    }

    /**
     * Restituisce le istanze del modulo, opzionalmente filtrate per stato.
     * I flag di ElixFormsRequestStatus possono essere combinati con l'operatore |.
     *
     * @return array<int,array<string,mixed>>
     */
    public function lookupByStatus(
        string $moduleTag,
        string $authToken,
        string $username,
        ?int $status = null
    ): array
    {
        $queryParts = [];
        if ($status !== null) {
            foreach (ElixFormsRequestStatus::toApiValues($status) as $statusValue) {
                $queryParts[] = 'requestStatus=' . rawurlencode($statusValue);
            }
        }
        $queryParts[] = 'moduleTag=' . rawurlencode($moduleTag);

        $url = "{$this->baseUrl}/api/request/lookup/by-status?" . implode('&', $queryParts);
        $payload = $this->getJsonAsArray($url, $authToken, $username, 'LookupByStatus');
        $requests = $payload['value']['requests'] ?? [];

        if (!\is_array($requests)) {
            throw new ElixFormsException('Risposta LookupByStatus non valida: requests deve essere un array.');
        }

        return array_values($requests);
    }

    /**
     * @param int|string $requestId
     * @return array<int,array{name?:mixed,value?:mixed}>
     */
    public function getExportTags(
        $requestId,
        string $moduleTag,
        string $authToken,
        string $username,
        string $exportGroup = 'API'
    ): array
    {
        $exportGroup = trim($exportGroup);
        if ($exportGroup === '') {
            throw new \InvalidArgumentException('exportGroup deve essere una stringa non vuota.');
        }

        $url = \sprintf(
            '%s/services/api/request/%s/view/_DEFAULT/exportTags/get/v1?moduleTag=%s&exportGroup=%s',
            $this->baseUrl,
            rawurlencode((string) $requestId),
            rawurlencode($moduleTag),
            rawurlencode($exportGroup)
        );
        $payload = $this->getJsonAsArray($url, $authToken, $username, 'GetExportTags');
        $exportTags = $payload['value']['exportTags'] ?? [];

        if (!\is_array($exportTags)) {
            throw new ElixFormsException('Risposta GetExportTags non valida: exportTags deve essere un array.');
        }

        return array_values($exportTags);
    }

    private function getJsonAsArray(
        string $url,
        string $authToken,
        string $username,
        string $operation
    ): array {
        $response = $this->httpClient->get($url, [
            'Authorization' => "Bearer {$authToken}",
            'Accept' => 'application/json',
            'x-requested-with' => 'XMLHttpRequest',
            'x-api-username' => $username,
        ]);

        $status = $response['status'] ?? 500;
        if ($status !== 200) {
            throw new ElixFormsException(\sprintf(
                'Errore durante %s. HTTP Status: %d',
                $operation,
                $status
            ));
        }

        $payload = $response['json'] ?? null;
        $jsonError = JSON_ERROR_NONE;
        if (!\is_array($payload) && isset($response['body']) && \is_string($response['body'])) {
            $payload = json_decode($response['body'], true);
            $jsonError = json_last_error();
        }

        if (!\is_array($payload) || $jsonError !== JSON_ERROR_NONE) {
            throw new ElixFormsException(\sprintf(
                'Risposta non valida da %s: atteso JSON.',
                $operation
            ));
        }

        $globalStatus = $payload['value']['globalStatus'] ?? null;
        if ($globalStatus === 'ERROR') {
            $description = $payload['value']['description'] ?? 'errore non specificato';
            throw new ElixFormsException(\sprintf(
                '%s ha restituito un errore: %s',
                $operation,
                $description
            ));
        }

        return $payload;
    }
}
