<?php

declare(strict_types=1);

final class UcuzabulanApiClient
{
    private string $baseUrl;
    private string $gatewayToken;

    public function __construct(string $baseUrl = 'https://ucuzabulan.com', string $gatewayToken = '')
    {
        $this->baseUrl = rtrim($baseUrl, '/');
        $this->gatewayToken = trim($gatewayToken);
    }

    /** @param array<string,mixed> $params */
    private function buildQuery(array $params): string
    {
        $flat = [];
        foreach ($params as $key => $value) {
            if ($value === null || $value === '') continue;
            if (is_bool($value)) {
                $flat[$key] = $value ? '1' : '0';
                continue;
            }
            if (is_array($value)) {
                if (!$value) continue;
                $flat[$key] = implode(',', array_map('strval', $value));
                continue;
            }
            $flat[$key] = (string)$value;
        }
        $raw = http_build_query($flat);
        return $raw !== '' ? '?' . $raw : '';
    }

    /** @return array<string,mixed> */
    private function request(string $method, string $path, array $payload = [], bool $withGatewayToken = false): array
    {
        $url = $this->baseUrl . $path;
        $ch = curl_init($url);
        $headers = ['Accept: application/json'];

        if ($method === 'POST') {
            $body = json_encode($payload, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES) ?: '{}';
            $headers[] = 'Content-Type: application/json';
            curl_setopt($ch, CURLOPT_POST, true);
            curl_setopt($ch, CURLOPT_POSTFIELDS, $body);
        }

        if ($withGatewayToken && $this->gatewayToken !== '') {
            $headers[] = 'Authorization: Bearer ' . $this->gatewayToken;
        }

        curl_setopt_array($ch, [
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_FOLLOWLOCATION => true,
            CURLOPT_MAXREDIRS => 4,
            CURLOPT_TIMEOUT => 20,
            CURLOPT_HTTPHEADER => $headers,
            CURLOPT_CUSTOMREQUEST => $method,
        ]);

        $raw = (string)curl_exec($ch);
        $code = (int)curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
        $err = (string)curl_error($ch);
        curl_close($ch);

        if ($err !== '') {
            throw new RuntimeException('Ucuzabulan API isteği başarısız: ' . $err);
        }
        if ($code < 200 || $code >= 300) {
            throw new RuntimeException('Ucuzabulan API HTTP hata kodu: ' . $code . ' body=' . substr($raw, 0, 500));
        }

        $data = json_decode($raw, true);
        if (!is_array($data)) {
            throw new RuntimeException('Ucuzabulan API JSON parse hatası.');
        }
        return $data;
    }

    /** @return array<string,mixed> */
    public function searchProducts(string $q, int $limit = 24, ?string $mode = null): array
    {
        return $this->request('GET', '/api/v1/search.php' . $this->buildQuery(['q' => $q, 'limit' => $limit, 'mode' => $mode]));
    }

    /** @return array<string,mixed> */
    public function searchExplain(string $q, int $limit = 12, ?string $mode = null): array
    {
        return $this->request('GET', '/api/v1/search_explain.php' . $this->buildQuery(['q' => $q, 'limit' => $limit, 'mode' => $mode]));
    }

    /** @return array<string,mixed> */
    public function searchSuggest(string $q, int $limit = 8): array
    {
        return $this->request('GET', '/api/v1/search_suggest.php' . $this->buildQuery(['q' => $q, 'limit' => $limit]));
    }

    /** @return array<string,mixed> */
    public function productBySlug(string $slug): array
    {
        return $this->request('GET', '/api/v1/product.php' . $this->buildQuery(['slug' => $slug]));
    }

    /** @param array<string,mixed> $params @return array<string,mixed> */
    public function catalogProducts(array $params = []): array
    {
        return $this->request('GET', '/api/v1/catalog.php' . $this->buildQuery($params));
    }

    /** @param array<string,mixed> $params @return array<string,mixed> */
    public function catalogFacets(array $params = []): array
    {
        return $this->request('GET', '/api/v1/facets.php' . $this->buildQuery($params));
    }

    /** @param array<string,mixed> $params @return array<string,mixed> */
    public function productOffers(int $productId, array $params = []): array
    {
        $params = array_merge(['product_id' => $productId], $params);
        return $this->request('GET', '/api/v1/offers.php' . $this->buildQuery($params));
    }

    /** @return array<string,mixed> */
    public function priceHistory(int $productId, int $days = 30): array
    {
        return $this->request('GET', '/api/v1/price_history.php' . $this->buildQuery(['product_id' => $productId, 'days' => $days]));
    }

    /** @return array<string,mixed> */
    public function mobileBootstrap(int $bannerLimit = 6, int $categoryLimit = 10, int $pickLimit = 12): array
    {
        return $this->request('GET', '/api/v1/mobile_bootstrap.php' . $this->buildQuery(['banner_limit' => $bannerLimit, 'category_limit' => $categoryLimit, 'pick_limit' => $pickLimit]));
    }

    /** @return array<string,mixed> */
    public function mobileMe(): array
    {
        return $this->request('GET', '/api/v1/mobile_me.php');
    }

    /** @return array<string,mixed> */
    public function mobileCompare(array $ids): array
    {
        $ids = array_values(array_filter(array_map('intval', $ids), static fn(int $v): bool => $v > 0));
        return $this->request('GET', '/api/v1/mobile_compare.php' . $this->buildQuery(['ids' => $ids]));
    }

    /** @return array<string,mixed> */
    public function graphql(string $query, array $variables = []): array
    {
        return $this->request('POST', '/api/graphql.php', ['query' => $query, 'variables' => $variables]);
    }

    /** @return array<string,mixed> */
    public function graphqlPersisted(string $key, array $variables = []): array
    {
        return $this->request('POST', '/api/graphql_persisted.php', ['key' => $key, 'variables' => $variables]);
    }

    /** @return array<string,mixed> */
    public function gateway(string $route, array $params = []): array
    {
        return $this->request('POST', '/api/gateway.php', array_merge(['route' => $route], $params), true);
    }
}