<?php

class NumistaAPI
{
    private string $apiKey;
    private string $baseUrl;
    private int $timeout = 30;

    public function __construct()
    {
        $this->apiKey = NUMISTA_API_KEY;
        $this->baseUrl = NUMISTA_API_BASE;

        if (empty($this->apiKey)) {
            throw new Exception('Numista API key is not configured');
        }
    }

    /**
     * Make HTTP request to Numista API
     */
    private function request(string $endpoint, array $params = [], string $method = 'GET'): array
    {
        $url = $this->baseUrl . ltrim($endpoint, '/');

        if ($method === 'GET' && !empty($params)) {
            $url .= '?' . http_build_query($params);
        }

        $ch = curl_init();
        curl_setopt_array($ch, [
            CURLOPT_URL => $url,
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_TIMEOUT => $this->timeout,
            CURLOPT_HTTPHEADER => [
                'Numista-API-Key: ' . $this->apiKey,
                'Accept: application/json',
            ],
        ]);

        if ($method === 'POST') {
            $headers = [
                'Numista-API-Key: ' . $this->apiKey,
                'Accept: application/json',
                'Content-Type: application/json',
            ];
            curl_setopt($ch, CURLOPT_POST, true);
            curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($params));
            curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
        }

        $response = curl_exec($ch);
        $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        $error = curl_error($ch);
        curl_close($ch);

        if ($error) {
            throw new Exception('cURL error: ' . $error);
        }

        // Log response for debugging
        error_log("Numista API Request: $url");
        error_log("Numista API Response Code: $httpCode");
        error_log("Numista API Response: $response");

        if ($httpCode === 401) {
            throw new Exception('Numista API authentication failed');
        }

        if ($httpCode === 429) {
            throw new Exception('Numista API rate limit exceeded');
        }

        if ($httpCode >= 400) {
            throw new Exception('Numista API error: HTTP ' . $httpCode . ' - Response: ' . $response);
        }

        $data = json_decode($response, true);
        if (json_last_error() !== JSON_ERROR_NONE) {
            throw new Exception('Invalid JSON response from Numista API');
        }

        return $data;
    }

    /**
     * Search coins by filters
     */
    public function searchCoins(array $filters): array
    {
        return $this->searchTypes($filters, 'coin');
    }

    /**
     * Search banknotes by filters
     */
    public function searchBanknotes(array $filters): array
    {
        return $this->searchTypes($filters, 'banknote');
    }

    /**
     * Get detailed coin data
     */
    public function getCoinDetails(int $numistaId): array
    {
        return $this->request('/types/' . $numistaId, ['lang' => 'en']);
    }

    /**
     * Get detailed banknote data
     */
    public function getBanknoteDetails(int $numistaId): array
    {
        return $this->request('/types/' . $numistaId, ['lang' => 'en']);
    }

    /**
     * Get pricing data for a coin
     */
    public function getPricing(int $numistaId): array
    {
        return [];
    }

    /**
     * Get literature references for a coin
     */
    public function getLiterature(int $numistaId, string $type = 'coin'): array
    {
        $issues = $this->request('/types/' . $numistaId . '/issues', ['lang' => 'en']);
        $issueList = $issues['issues'] ?? $issues;
        $references = [];

        foreach ($issueList as $issue) {
            if (!is_array($issue)) {
                continue;
            }

            // Try to extract from references array first
            if (!empty($issue['references']) && is_array($issue['references'])) {
                foreach ($issue['references'] as $reference) {
                    if (!is_array($reference)) {
                        continue;
                    }

                    $catalogue = '';
                    if (!empty($reference['catalogue']) && is_array($reference['catalogue'])) {
                        $catalogue = $reference['catalogue']['code'] ?? $reference['catalogue']['name'] ?? '';
                    }

                    $number = $reference['number'] ?? '';
                    $references[] = [
                        'catalogue' => $catalogue,
                        'reference' => trim($catalogue . ' ' . $number),
                        'number' => $number,
                        'url' => $issue['url'] ?? null,
                    ];
                }
            } 
            // If no references, try to extract from comment field (e.g., "P#51? watermarked paper...")
            elseif (!empty($issue['comment'])) {
                $comment = $issue['comment'];
                // Try P# format first
                if (preg_match('/(P#\d+[a-z]?)/', $comment, $matches)) {
                    $catalogueCode = 'P';
                    $number = str_replace('P#', '', $matches[1]);
                    $references[] = [
                        'catalogue' => ['code' => $catalogueCode],
                        'reference' => $matches[1],
                        'number' => $number,
                        'url' => $issue['url'] ?? null,
                    ];
                }
                // If no P# found, use the issue ID as reference
                else {
                    $references[] = [
                        'catalogue' => ['code' => 'Numista'],
                        'reference' => 'ID ' . $issue['id'],
                        'number' => $issue['id'],
                        'url' => $issue['url'] ?? null,
                    ];
                }
            }
        }

        return $references;
    }

    /**
     * Get list of issuers (countries)
     */
    public function getIssuers(): array
    {
        return $this->request('/issuers', ['lang' => 'en']);
    }

    private function searchTypes(array $filters, string $category): array
    {
        $queryParts = array_filter([
            trim((string)($filters['value'] ?? '')),
        ]);

        $params = [
            'lang' => 'en',
            'category' => $category,
            'page' => 1,
            'count' => 20,
        ];

        if (!empty($filters['issuer'])) {
            $params['issuer'] = $filters['issuer'];
        }

        if (!empty($queryParts)) {
            $params['q'] = implode(' ', $queryParts);
        }

        return $this->request('/types', $params);
    }

    /**
     * Map Numista composition to local material values
     */
    public function mapMaterial(string $composition): ?string
    {
        $mapping = [
            'Copper' => 'copper',
            'Silver' => 'silver',
            'Gold' => 'gold',
            'Brass' => 'brass',
            'Aluminum' => 'aluminum',
            'Bronze' => 'alloy',
            'Copper-Nickel' => 'alloy',
            'Cupronickel' => 'alloy',
            'Nickel' => 'alloy',
            'Steel' => 'alloy',
            'Zinc' => 'alloy',
            'Iron' => 'alloy',
            'Lead' => 'alloy',
            'Tin' => 'alloy',
        ];

        foreach ($mapping as $numistaMat => $localMat) {
            if (stripos($composition, $numistaMat) !== false) {
                return $localMat;
            }
        }

        return 'alloy'; // Default to alloy for unknown compositions
    }
}
