<?php

require_once __DIR__ . '/../config/database.php';
require_once __DIR__ . '/ApiProviderRotationService.php';
require_once __DIR__ . '/CacheService.php';

class NewsProviderRotationService
{
    public static function fetchMarketNews(string $query = 'gold OR forex OR bitcoin OR Federal Reserve', int $limit = 20): array
    {
        $cacheKey = 'market_news:' . md5($query . ':' . $limit);

        return CacheService::remember($cacheKey, 300, function () use ($query, $limit) {
            $providers = self::activeProviders();
            $lastError = '';

            foreach ($providers as $provider) {
                $name = strtolower(trim((string)($provider['provider'] ?? '')));
                $started = microtime(true);

                try {
                    if ($name === 'newsapi') {
                        $result = self::fetchNewsApi($provider, $query, $limit);
                    } elseif ($name === 'financialmodelingprep' || $name === 'fmp') {
                        $result = self::fetchFmpNews($provider, $query, $limit);
                    } else {
                        $result = self::fetchGenericNews($provider, $query, $limit);
                    }

                    $responseMs = (int)((microtime(true) - $started) * 1000);

                    if (!empty($result['success'])) {
                        ApiProviderRotationService::markSuccess($provider, 'news', null, null, 1, $responseMs);
                        self::storeNews($provider, $result['articles']);

                        return [
                            'success' => true,
                            'provider' => $provider['provider'] ?? '',
                            'articles' => $result['articles']
                        ];
                    }

                    $lastError = $result['error'] ?? 'News provider failed.';
                    ApiProviderRotationService::markFailure($provider, 'news', $lastError, null, null, $responseMs);
                } catch (Throwable $e) {
                    $responseMs = (int)((microtime(true) - $started) * 1000);
                    $lastError = $e->getMessage();
                    ApiProviderRotationService::markFailure($provider, 'news', $lastError, null, null, $responseMs);
                }
            }

            return [
                'success' => false,
                'provider' => null,
                'articles' => [],
                'error' => $lastError ?: 'No news provider available.'
            ];
        });
    }

    private static function activeProviders(): array
    {
        $stmt = db()->query("
            SELECT *
            FROM api_settings
            WHERE is_active = 1
              AND (provider_type = 'news' OR supports_news = 1)
              AND (cooldown_until IS NULL OR cooldown_until <= NOW())
            ORDER BY priority_order ASC, fail_count ASC, used_today ASC
        ");

        return $stmt->fetchAll(PDO::FETCH_ASSOC) ?: [];
    }

    private static function fetchNewsApi(array $provider, string $query, int $limit): array
    {
        $base = rtrim($provider['base_url'] ?: 'https://newsapi.org/v2', '/');
        $key = trim((string)($provider['api_key'] ?? ''));

        if ($key === '') {
            return ['success' => false, 'error' => 'NewsAPI key is empty.'];
        }

        $response = self::httpGet($base . '/everything', [
            'q' => $query,
            'language' => 'en',
            'sortBy' => 'publishedAt',
            'pageSize' => min($limit, 100),
            'apiKey' => $key
        ]);

        if (!empty($response['json']['articles'])) {
            $articles = [];

            foreach ($response['json']['articles'] as $item) {
                $articles[] = [
                    'article_id' => md5(($item['url'] ?? '') . ($item['title'] ?? '')),
                    'published_at' => !empty($item['publishedAt']) ? date('Y-m-d H:i:s', strtotime($item['publishedAt'])) : null,
                    'title' => $item['title'] ?? '',
                    'source_name' => $item['source']['name'] ?? '',
                    'url' => $item['url'] ?? '',
                    'impact' => self::inferImpact($item['title'] ?? ''),
                    'sentiment' => 'neutral',
                    'raw_payload' => json_encode($item)
                ];
            }

            return ['success' => true, 'articles' => $articles];
        }

        return ['success' => false, 'error' => $response['json']['message'] ?? $response['error'] ?? 'NewsAPI returned no articles.'];
    }

    private static function fetchFmpNews(array $provider, string $query, int $limit): array
    {
        $base = rtrim($provider['base_url'] ?: 'https://financialmodelingprep.com/api/v3', '/');
        $key = trim((string)($provider['api_key'] ?? ''));

        if ($key === '') {
            return ['success' => false, 'error' => 'FMP API key is empty.'];
        }

        $response = self::httpGet($base . '/fmp/articles', [
            'page' => 0,
            'size' => min($limit, 50),
            'apikey' => $key
        ]);

        $data = $response['json']['content'] ?? $response['json'] ?? [];

        if (is_array($data) && $data) {
            $articles = [];

            foreach ($data as $item) {
                if (!is_array($item)) continue;

                $articles[] = [
                    'article_id' => md5(($item['url'] ?? '') . ($item['title'] ?? '')),
                    'published_at' => !empty($item['date']) ? date('Y-m-d H:i:s', strtotime($item['date'])) : null,
                    'title' => $item['title'] ?? '',
                    'source_name' => $item['site'] ?? 'FMP',
                    'url' => $item['url'] ?? '',
                    'impact' => self::inferImpact($item['title'] ?? ''),
                    'sentiment' => 'neutral',
                    'raw_payload' => json_encode($item)
                ];
            }

            return ['success' => true, 'articles' => $articles];
        }

        return ['success' => false, 'error' => $response['error'] ?: 'FMP returned no news.'];
    }

    private static function fetchGenericNews(array $provider, string $query, int $limit): array
    {
        return ['success' => false, 'error' => 'Generic news adapter is not configured for this provider.'];
    }

    private static function storeNews(array $provider, array $articles): void
    {
        foreach ($articles as $article) {
            try {
                db()->prepare("
                    INSERT INTO news_events
                        (provider, article_id, published_at, title, source_name, url, symbol, currency, impact, sentiment, raw_payload, created_at)
                    VALUES
                        (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, NOW())
                    ON DUPLICATE KEY UPDATE
                        published_at = VALUES(published_at),
                        title = VALUES(title),
                        source_name = VALUES(source_name),
                        url = VALUES(url),
                        impact = VALUES(impact),
                        sentiment = VALUES(sentiment),
                        raw_payload = VALUES(raw_payload)
                ")->execute([
                    $provider['provider'] ?? '',
                    $article['article_id'] ?? md5(json_encode($article)),
                    $article['published_at'] ?? null,
                    $article['title'] ?? '',
                    $article['source_name'] ?? '',
                    $article['url'] ?? '',
                    $article['symbol'] ?? '',
                    $article['currency'] ?? '',
                    $article['impact'] ?? 'MEDIUM',
                    $article['sentiment'] ?? 'neutral',
                    $article['raw_payload'] ?? json_encode($article)
                ]);
            } catch (Throwable $e) {
            }
        }
    }

    private static function inferImpact(string $title): string
    {
        $title = strtolower($title);

        foreach (['fed', 'fomc', 'cpi', 'nfp', 'powell', 'trump', 'war', 'rate decision', 'inflation'] as $keyword) {
            if (str_contains($title, $keyword)) {
                return 'HIGH';
            }
        }

        return 'MEDIUM';
    }

    private static function httpGet(string $url, array $params): array
    {
        $fullUrl = $url . '?' . http_build_query($params);

        if (function_exists('curl_init')) {
            $ch = curl_init($fullUrl);
            curl_setopt_array($ch, [
                CURLOPT_RETURNTRANSFER => true,
                CURLOPT_TIMEOUT => 25,
                CURLOPT_CONNECTTIMEOUT => 10,
                CURLOPT_SSL_VERIFYPEER => true
            ]);
            $body = curl_exec($ch);
            $error = curl_error($ch);
            curl_close($ch);
        } else {
            $body = @file_get_contents($fullUrl);
            $error = $body === false ? 'HTTP request failed' : '';
        }

        return [
            'json' => json_decode((string)$body, true) ?: [],
            'error' => $error
        ];
    }
}
