<?php

declare(strict_types=1);

namespace App\Infrastructure\Api\RapidMail;

use App\Framework\Api\ApiException;
use App\Framework\Http\Method;
use App\Framework\HttpClient\AuthConfig;
use App\Framework\HttpClient\ClientOptions;
use App\Framework\HttpClient\ClientRequest;
use App\Framework\HttpClient\ClientResponse;
use App\Framework\HttpClient\HttpClient;

final readonly class RapidMailApiClient
{
    private ClientOptions $defaultOptions;

    public function __construct(
        private RapidMailConfig $config,
        private HttpClient      $httpClient
    ) {
        $this->defaultOptions = new ClientOptions(
            timeout: $this->config->timeout,
            auth: AuthConfig::basic($this->config->username, $this->config->password)
        );
    }

    /**
     * Sendet eine API-Anfrage und gibt JSON-Daten zurück
     */
    public function request(
        Method $method,
        string $endpoint,
        array $data = [],
        array $queryParams = []
    ): array {
        $response = $this->sendRawRequest($method, $endpoint, $data, $queryParams);

        return $this->handleResponse($response);
    }

    /**
     * Sendet eine API-Anfrage und gibt raw Response zurück
     */
    public function sendRawRequest(
        Method $method,
        string $endpoint,
        array $data = [],
        array $queryParams = []
    ): ClientResponse {
        $url = $this->config->baseUrl . '/' . ltrim($endpoint, '/');

        $options = $this->defaultOptions;
        if (! empty($queryParams)) {
            $options = $options->with(['query' => $queryParams]);
        }

        if (in_array($method, [Method::GET, Method::DELETE]) && ! empty($data)) {
            $existingQuery = $options->query;
            $options = $options->with(['query' => array_merge($existingQuery, $data)]);
            $data = [];
        }

        $request = empty($data)
            ? new ClientRequest($method, $url, options: $options)
            : ClientRequest::json($method, $url, $data, $options);

        $response = $this->httpClient->send($request);

        if (! $response->isSuccessful()) {
            $this->throwApiException($response);
        }

        return $response;
    }

    /**
     * Standard Query-Parameter
     */
    public function getDefaultQueryParams(): array
    {
        return [
            'send_activationmail' => $this->config->sendActivationMail ? 'yes' : 'no',
            'test_mode' => $this->config->testMode ? 'yes' : 'no',
        ];
    }

    /**
     * Behandelt API-Response
     */
    private function handleResponse(ClientResponse $response): array
    {
        if (! $response->isJson()) {
            throw new ApiException('Expected JSON response, got: ' . $response->getContentType(), 0, $response);
            ;
        }

        try {
            return $response->json();
        } catch (\Exception $e) {
            throw new ApiException('Invalid JSON response: ' . $e->getMessage(), 0, $response);
        }
    }

    /**
     * Wirft API-Exception
     */
    private function throwApiException(ClientResponse $response): never
    {
        $data = [];

        if ($response->isJson()) {
            try {
                $data = $response->json();
            } catch (\Exception) {
                // JSON parsing failed
            }
        }

        $message = $this->formatErrorMessage($data, $response);

        throw new ApiException($message, $response->status->value, $response);
    }

    /**
     * Formatiert Fehlermeldung
     */
    private function formatErrorMessage(array $responseData, ClientResponse $response): string
    {
        if (isset($responseData['detail'])) {
            $message = 'RapidMail API Error: ' . $responseData['detail'];

            if (isset($responseData['validation_messages'])) {
                $message .= ' - Validation: ' . json_encode(
                    $responseData['validation_messages'],
                    JSON_UNESCAPED_UNICODE
                );
            }

            return $message;
        }

        if (isset($responseData['error'])) {
            return 'RapidMail API Error: ' . $responseData['error'];
        }

        if (isset($responseData['message'])) {
            return 'RapidMail API Error: ' . $responseData['message'];
        }

        return "RapidMail API Error (HTTP {$response->status->value}): " .
            substr($response->body, 0, 200);
    }
}
