<?php

require_once __DIR__ . '/../config/database.php';
require_once __DIR__ . '/RSSFeedService.php';
require_once __DIR__ . '/GeoRiskService.php';

class GeoPoliticalAggregator
{
    public static function analyze(string $symbol = 'XAUUSD'): array
    {
        $items = [];

        foreach (self::feeds() as $feed) {
            $result = RSSFeedService::fetch($feed['url'], 15);

            if (!empty($result['items'])) {
                foreach ($result['items'] as $item) {
                    $item['source'] = $feed['name'];
                    $items[] = $item;
                }
            }
        }

        $fmp = self::fetchFmpFallback($symbol);
        if (!empty($fmp['events'])) {
            foreach ($fmp['events'] as $event) {
                $items[] = [
                    'title' => $event['title'] ?? 'Market headline',
                    'summary' => $event['text'] ?? '',
                    'url' => $event['url'] ?? '',
                    'published_at' => $event['time'] ?? '',
                    'source' => 'FMP',
                ];
            }
        }

        $items = self::dedupe($items);
        self::cacheItems($items);

        return self::score($symbol, $items);
    }

    public static function feeds(): array
    {
        return [
            [
                'name' => 'Reuters World',
                'url' => 'https://feeds.reuters.com/reuters/worldNews'
            ],
            [
                'name' => 'CNBC World',
                'url' => 'https://www.cnbc.com/id/100727362/device/rss/rss.html'
            ],
            [
                'name' => 'Al Jazeera',
                'url' => 'https://www.aljazeera.com/xml/rss/all.xml'
            ],
            [
                'name' => 'BBC World',
                'url' => 'https://feeds.bbci.co.uk/news/world/rss.xml'
            ],
            [
                'name' => 'FXStreet News',
                'url' => 'https://www.fxstreet.com/rss/news'
            ],
        ];
    }

    private static function fetchFmpFallback(string $symbol): array
    {
        if (!class_exists('GeoRiskService')) {
            return [];
        }

        try {
            return GeoRiskService::analyze($symbol);
        } catch (Throwable $e) {
            return [];
        }
    }

    private static function dedupe(array $items): array
    {
        $seen = [];
        $clean = [];

        foreach ($items as $item) {
            $title = trim((string)($item['title'] ?? ''));
            if ($title === '') continue;

            $key = md5(strtolower($title));

            if (isset($seen[$key])) continue;

            $seen[$key] = true;
            $clean[] = $item;
        }

        return $clean;
    }

    private static function score(string $symbol, array $items): array
    {
        $negative = [
            'war' => 3,
            'conflict' => 2,
            'attack' => 3,
            'missile' => 3,
            'sanctions' => 2,
            'crisis' => 2,
            'invasion' => 3,
            'oil shock' => 3,
            'middle east' => 2,
            'iran' => 2,
            'israel' => 2,
            'russia' => 2,
            'ukraine' => 2,
            'taiwan' => 2,
            'terror' => 3,
            'escalation' => 3,
            'emergency' => 2,
            'hormuz' => 3,
            'red sea' => 2,
            'nuclear' => 3,
            'ceasefire collapses' => 3,
        ];

        $positive = [
            'ceasefire' => -2,
            'peace' => -2,
            'agreement' => -1,
            'de-escalation' => -2,
            'truce' => -2,
            'talks resume' => -1,
        ];

        $score = 0;
        $matched = [];

        foreach ($items as $item) {
            $text = strtolower(($item['title'] ?? '') . ' ' . ($item['summary'] ?? ''));
            $itemScore = 0;

            foreach ($negative as $word => $weight) {
                if (str_contains($text, $word)) {
                    $itemScore += $weight;
                }
            }

            foreach ($positive as $word => $weight) {
                if (str_contains($text, $word)) {
                    $itemScore += $weight;
                }
            }

            if ($itemScore !== 0) {
                $item['risk_score'] = $itemScore;
                $matched[] = $item;
                $score += $itemScore;
            }
        }

        if ($score >= 18) {
            $risk = 'HIGH';
            $penalty = -2;
        } elseif ($score >= 5) {
            $risk = 'MEDIUM';
            $penalty = -1;
        } elseif ($score <= -3) {
            $risk = 'LOW';
            $penalty = 0;
        } else {
            $risk = 'LOW';
            $penalty = 0;
        }

        $impact = self::impactForSymbol($symbol, $risk);

        return [
            'risk' => $risk,
            'impact' => $impact,
            'score_penalty' => $penalty,
            'sentiment' => $score,
            'message' => count($matched)
                ? 'Relevant geopolitical headlines detected and scored.'
                : 'No major geopolitical escalation detected across RSS sources.',
            'events' => array_slice($matched, 0, 6),
            'raw_count' => count($items),
            'source' => 'multi_source_rss+fmp'
        ];
    }

    private static function impactForSymbol(string $symbol, string $risk): string
    {
        $symbol = strtoupper($symbol);

        if ($symbol === 'XAUUSD') {
            if ($risk === 'HIGH') return 'Gold safe-haven volatility likely elevated';
            if ($risk === 'MEDIUM') return 'Gold volatility may increase';
        }

        if (str_contains($symbol, 'USD')) {
            if ($risk === 'HIGH') return 'USD volatility likely elevated';
            if ($risk === 'MEDIUM') return 'USD may react to risk sentiment';
        }

        return 'Neutral';
    }

    private static function cacheItems(array $items): void
    {
        if (empty($items)) return;

        try {
            $sql = "INSERT INTO news_cache
                    (source, title, summary, url, published_at, category, created_at)
                    VALUES (?, ?, ?, ?, ?, 'geopolitical', NOW())
                    ON DUPLICATE KEY UPDATE
                        summary = VALUES(summary),
                        published_at = VALUES(published_at),
                        updated_at = NOW()";

            $stmt = db()->prepare($sql);

            foreach ($items as $item) {
                $published = self::normalizeDate($item['published_at'] ?? null);

                $stmt->execute([
                    $item['source'] ?? 'RSS',
                    $item['title'] ?? '',
                    $item['summary'] ?? '',
                    $item['url'] ?? '',
                    $published,
                ]);
            }
        } catch (Throwable $e) {
            // Cache failure should not break the analysis engine.
        }
    }

    private static function normalizeDate($date): ?string
    {
        if (!$date) return null;

        $ts = strtotime((string)$date);

        return $ts ? date('Y-m-d H:i:s', $ts) : null;
    }
}
