<?php

declare(strict_types=1);

namespace App\Services\DataForSeo;

use Illuminate\Http\Client\ConnectionException;
use Illuminate\Http\Client\PendingRequest;
use Illuminate\Http\Client\RequestException;
use Illuminate\Support\Arr;
use Illuminate\Support\Facades\Http;
use RuntimeException;
use Throwable;

class DataForSeoClient
{
    /**
     * @param  list<array<string, mixed>>  $tasks
     * @return array<string, mixed>
     */
    public function postTasks(array $tasks): array
    {
        $response = $this->request()->post(
            config('dataforseo.merchant_google_products.task_post_endpoint'),
            $tasks,
        );

        return $this->validateResponse($response->json(), 'No se pudieron crear tareas en DataForSEO.');
    }

    /**
     * @return array<string, mixed>
     */
    public function getTaskResult(string $providerTaskId): array
    {
        $endpoint = rtrim((string) config('dataforseo.merchant_google_products.task_get_advanced_endpoint'), '/').'/'.$providerTaskId;
        $response = $this->request()->get($endpoint);

        return $this->validateResponse($response->json(), 'No se pudo recuperar la tarea de DataForSEO.');
    }

    private function request(): PendingRequest
    {
        $login = config('dataforseo.login');
        $password = config('dataforseo.password');

        if (! config('dataforseo.enabled')) {
            throw new RuntimeException('DataForSEO está deshabilitado. Configura DATAFORSEO_ENABLED=true para ejecutar esta integración.');
        }

        if (! is_string($login) || $login === '' || ! is_string($password) || $password === '') {
            throw new RuntimeException('Faltan credenciales de DataForSEO. Configura DATAFORSEO_LOGIN y DATAFORSEO_PASSWORD.');
        }

        return Http::baseUrl(rtrim((string) config('dataforseo.base_url'), '/'))
            ->withBasicAuth($login, $password)
            ->acceptJson()
            ->asJson()
            ->timeout((int) config('dataforseo.timeout'))
            ->connectTimeout((int) config('dataforseo.connect_timeout'))
            ->retry(
                3,
                500,
                function (Throwable $exception, PendingRequest $request): bool {
                    if ($exception instanceof ConnectionException) {
                        return true;
                    }

                    if (! $exception instanceof RequestException) {
                        return false;
                    }

                    $status = $exception->response?->status();

                    return in_array($status, [408, 409, 425, 429, 500, 502, 503, 504], true);
                },
                throw: false,
            );
    }

    /**
     * @return array<string, mixed>
     */
    private function validateResponse(mixed $payload, string $defaultMessage): array
    {
        if (! is_array($payload)) {
            throw new RuntimeException($defaultMessage.' Respuesta no válida del proveedor.');
        }

        $statusCode = Arr::get($payload, 'status_code');

        if (is_int($statusCode) && $statusCode >= 20000 && $statusCode < 30000) {
            return $payload;
        }

        $taskMessage = Arr::get($payload, 'tasks.0.status_message')
            ?? Arr::get($payload, 'status_message')
            ?? $defaultMessage;

        throw new RuntimeException((string) $taskMessage);
    }
}
