<?php
namespace App\Services\Parser;

use Exception;
use Illuminate\Support\Facades\Http;

class Parser
{
    /**
     * Пространство имён папки Portals
     */
    const PORTALS_NAMESPACE = 'App\\Services\\Parser\\Portals\\';

    /**
     * Конфигурация (из config/parser.php)
     */
    private array $config;

    public function __construct()
    {
        $this->config = config('parser');
    }

    // -------------------------------------------------------------------------
    // Public API
    // -------------------------------------------------------------------------

    /**
     * Главная точка входа.
     * 1. Обходит активные порталы из конфига
     * 2. Вызывает parse() на каждом → данные оседают в tmp
     * 3. Читает результаты через getResult()
     * 4. Отправляет HTML в ChatGPT и получает JSON
     * 5. Возвращает массив готовых данных для создания Car
     */
    public function run(): array
    {
        $cars = [];

        foreach ($this->getActivePortals() as $portalInstance) {
            // Шаг 1: загружаем страницы и сохраняем HTML во временные файлы
            $portalInstance->parse();

            // Шаг 2: читаем HTML из tmp
            $results = $portalInstance->getResult();

            // Шаг 3: каждый HTML → ChatGPT → массив полей Car
            foreach ($results as $item) {
                try {
                    $carData = $this->processWithGpt($item['html']);

                    if ($carData !== null) {
                        $cars[] = $carData;
                    }
                } catch (Exception $e) {
                    error_log('[Parser] GPT error for file ' . ($item['file'] ?? '?') . ': ' . $e->getMessage());
                }
            }

            // clearData() — не вызываем пока, но метод готов
            // $portalInstance->clearData();
        }

        return $cars;
    }

    // -------------------------------------------------------------------------
    // Portal loading
    // -------------------------------------------------------------------------

    /**
     * Возвращает массив инстансов активных порталов из конфига.
     * Пример конфига:
     *   'portals' => ['Encar' => true, 'Drom' => false]
     *
     * @return object[]
     */
    private function getActivePortals(): array
    {
        $portals   = $this->config['portals'] ?? [];
        $instances = [];

        foreach ($portals as $name => $enabled) {
            if (! $enabled) {
                continue;
            }

            $class = self::PORTALS_NAMESPACE . $name;

            if (! class_exists($class)) {
                error_log("[Parser] Класс портала не найден: $class");
                continue;
            }

            $instance = new $class();

            // Убеждаемся что у класса есть нужные методы
            if (! method_exists($instance, 'parse') || ! method_exists($instance, 'getResult')) {
                error_log("[Parser] Портал $name не реализует parse() / getResult()");
                continue;
            }

            $instances[] = $instance;
        }

        return $instances;
    }

    // -------------------------------------------------------------------------
    // GPT integration
    // -------------------------------------------------------------------------

    /**
     * Отправляет HTML в ChatGPT, получает JSON, декодирует в массив.
     * Возвращает null если GPT вернул невалидный JSON.
     */
    private function processWithGpt(string $html): ?array
    {
        $prompt = $this->buildPrompt($html);
        $raw    = $this->callChatGpt($prompt);

        // Убираем возможные markdown-обёртки ```json … ```
        $json = preg_replace('/^```(?:json)?\s*/i', '', trim($raw));
        $json = preg_replace('/\s*```$/', '', $json);

        $data = json_decode($json, true);

        if (! is_array($data)) {
            error_log('[Parser] GPT вернул невалидный JSON: ' . substr($raw, 0, 200));
            return null;
        }

        return $data;
    }

    /**
     * Подставляет HTML в промт из конфига (плейсхолдер {html})
     */
    private function buildPrompt(string $html): string
    {
        $template = $this->config['gpt_prompt'] ?? '{html}';

        // Обрезаем HTML чтобы не превысить контекст модели (~100k символов достаточно)
        $trimmedHtml = mb_substr($html, 0, 80000);

        return str_replace('{html}', $trimmedHtml, $template);
    }

    /**
     * Отправляет запрос к OpenAI Chat Completions API и возвращает текст ответа.
     *
     * @throws Exception при сетевых ошибках или ошибках API
     */
    private function callChatGpt(string $prompt): string
    {
        $cfg    = $this->config['openai'] ?? [];
        $apiKey = $cfg['api_key'] ?? config('services.openai.key', '');
        $model  = $cfg['model'] ?? 'gpt-4o';
        $maxTok = $cfg['max_tokens'] ?? 2000;
        $temp   = $cfg['temperature'] ?? 0;

        if (empty($apiKey)) {
            throw new Exception('OPENAI_API_KEY не задан в конфиге или .env');
        }

        $response = Http::withToken($apiKey)
            ->timeout(60)
            ->post('https://api.openai.com/v1/chat/completions', [
                'model'    => $model,
                'messages' => [
                    ['role' => 'user', 'content' => $prompt],
                ],
            ]);

        if ($response->failed()) {
            $error = $response->json('error.message', 'unknown');
            throw new Exception("OpenAI API error [{$response->status()}]: {$error}");
        }

        return $response->json('choices.0.message.content', '');
    }
}
