<?php

require_once __DIR__ . '/../config/database.php';
require_once __DIR__ . '/NewsRiskService.php';
require_once __DIR__ . '/EconomicCalendarService.php';

class NewsAggregatorService
{
    public static function check(string $symbol, int $minutesAhead = 90): array
    {
        $minutesAhead = max(360, $minutesAhead);
        $minutesBehind = 360;

        $calendar = self::safeCalendar($symbol, $minutesAhead, $minutesBehind);
        $risk = self::safeRisk($symbol, $minutesAhead);
        $local = self::localFallback($symbol, $minutesBehind, $minutesAhead);

        $events = array_merge($calendar['events'] ?? [], $risk['events'] ?? [], $local['events'] ?? []);
        $events = self::tagSpeechEvents($events);

        usort($events, function ($a, $b) {
            return (int)($a['timestamp'] ?? strtotime((string)($a['time'] ?? 'now'))) <=> (int)($b['timestamp'] ?? strtotime((string)($b['time'] ?? 'now')));
        });

        $speechRisk = self::speechRisk($events);
        $finalRisk = self::maxRisk(
            strtoupper((string)($calendar['risk'] ?? 'LOW')),
            self::maxRisk(strtoupper((string)($risk['risk'] ?? 'LOW')), self::maxRisk(strtoupper((string)($local['risk'] ?? 'LOW')), $speechRisk['risk']))
        );

        $primary = $speechRisk['event'] ?? ($events[0] ?? []);
        $time = $primary['time'] ?? ($calendar['time'] ?? ($local['time'] ?? ($risk['time'] ?? '')));
        $timestamp = $primary['timestamp'] ?? ($time ? strtotime((string)$time) : null);
        $minutesUntil = $timestamp ? (int)round(($timestamp - time()) / 60) : null;

        return [
            'has_news' => in_array($finalRisk, ['MEDIUM', 'HIGH', 'EXTREME'], true),
            'has_scheduled_event' => !empty($calendar['has_news']) || !empty($local['has_news']) || !empty($speechRisk['has_news']),
            'risk' => $finalRisk,
            'scheduled_risk' => self::maxRisk(strtoupper((string)($calendar['risk'] ?? 'LOW')), self::maxRisk(strtoupper((string)($local['risk'] ?? 'LOW')), $speechRisk['risk'])),
            'macro_risk' => strtoupper((string)($risk['risk'] ?? 'LOW')),
            'score_penalty' => max((int)($calendar['score_penalty'] ?? 0), (int)($risk['score_penalty'] ?? 0), (int)($local['score_penalty'] ?? 0), !empty($speechRisk['has_news']) ? 2 : 0),
            'title' => $primary['title'] ?? ($calendar['title'] ?: ($local['title'] ?? ($risk['title'] ?? ''))),
            'time' => $time,
            'minutes_until' => $minutesUntil,
            'countdown_label' => self::countdownLabel($minutesUntil),
            'macro_supports' => 'NEUTRAL',
            'macro_summary' => !empty($events) ? 'Calendar/news events detected. Check timing before execution.' : 'No major macro event detected.',
            'scheduled_events' => array_slice(array_merge(!empty($speechRisk['event']) ? [$speechRisk['event']] : [], $calendar['events'] ?? [], $local['events'] ?? []), 0, 10),
            'macro_events' => $risk['events'] ?? [],
            'message' => self::message($finalRisk, $primary['title'] ?? ''),
            'events' => array_slice($events, 0, 10),
            'source' => 'calendar+headline+speech+local_safety_window',
        ];
    }

    private static function safeCalendar(string $symbol, int $ahead, int $behind): array
    {
        try { return EconomicCalendarService::check($symbol, $ahead, $behind); }
        catch (Throwable $e) { return ['has_news' => false, 'risk' => 'LOW', 'events' => []]; }
    }

    private static function safeRisk(string $symbol, int $ahead): array
    {
        try { return NewsRiskService::check($symbol, $ahead); }
        catch (Throwable $e) { return ['has_news' => false, 'risk' => 'LOW', 'events' => []]; }
    }

    private static function tagSpeechEvents(array $events): array
    {
        foreach ($events as &$event) {
            if (!is_array($event)) continue;
            $title = strtoupper((string)($event['title'] ?? $event['event'] ?? $event['headline'] ?? ''));
            $isSpeech = preg_match('/\b(TRUMP|POWELL|FED CHAIR|FOMC MEMBER|LAGARDE|BAILEY|SPEECH|SPEAKS|TESTIFIES|PRESS CONFERENCE)\b/', $title);
            if ($isSpeech) {
                $event['impact'] = 'High';
                $event['speech_risk'] = true;
            }
        }
        return $events;
    }

    private static function speechRisk(array $events): array
    {
        foreach ($events as $event) {
            if (empty($event['speech_risk'])) continue;
            $ts = $event['timestamp'] ?? null;
            if (!$ts && !empty($event['time'])) $ts = strtotime((string)$event['time']);
            if (!$ts && !empty($event['published_at'])) $ts = strtotime((string)$event['published_at']);
            $mins = $ts ? (int)round(($ts - time()) / 60) : null;
            if ($mins === null || ($mins >= -120 && $mins <= 180)) {
                return ['has_news' => true, 'risk' => 'HIGH', 'event' => $event];
            }
        }
        return ['has_news' => false, 'risk' => 'LOW', 'event' => null];
    }

    private static function localFallback(string $symbol, int $back, int $ahead): array
    {
        try {
            $pdo = db();
            $tables = $pdo->query("SHOW TABLES")->fetchAll(PDO::FETCH_COLUMN);
            $events = [];
            $currencies = self::currenciesForSymbol($symbol);

            foreach ($tables as $table) {
                $name = strtolower((string)$table);
                if (!str_contains($name, 'calendar') && !str_contains($name, 'news') && !str_contains($name, 'event')) continue;

                $cols = $pdo->query("SHOW COLUMNS FROM `$table`")->fetchAll(PDO::FETCH_COLUMN);
                $lower = array_map('strtolower', $cols);
                $titleCol = self::firstColumn($cols, $lower, ['title', 'event', 'name', 'headline']);
                $timeCol = self::firstColumn($cols, $lower, ['time', 'event_time', 'date', 'datetime', 'published_at', 'created_at']);
                $impactCol = self::firstColumn($cols, $lower, ['impact', 'importance', 'priority', 'risk']);
                $currencyCol = self::firstColumn($cols, $lower, ['currency', 'country', 'symbol']);

                if (!$titleCol || !$timeCol) continue;

                $stmt = $pdo->prepare("SELECT * FROM `$table` WHERE `$timeCol` BETWEEN DATE_SUB(NOW(), INTERVAL :back MINUTE) AND DATE_ADD(NOW(), INTERVAL :ahead MINUTE) ORDER BY `$timeCol` ASC LIMIT 30");
                $stmt->execute([':back' => $back, ':ahead' => $ahead]);

                foreach ($stmt->fetchAll(PDO::FETCH_ASSOC) as $row) {
                    $title = (string)($row[$titleCol] ?? '');
                    $impact = strtoupper((string)($impactCol ? ($row[$impactCol] ?? '') : ''));
                    $currency = strtoupper((string)($currencyCol ? ($row[$currencyCol] ?? '') : ''));
                    $titleUpper = strtoupper($title);

                    $isHigh = str_contains($impact, 'HIGH') || str_contains($impact, '3') || preg_match('/\b(CPI|FOMC|NFP|NONFARM|FED|POWELL|TRUMP|SPEECH|SPEAKS|TESTIFIES|INTEREST RATE|GDP|PCE|JOBLESS|UNEMPLOYMENT)\b/', $titleUpper);
                    if (!$isHigh || !self::affects($currency, $titleUpper, $currencies)) continue;

                    $events[] = [
                        'title' => $title ?: 'High-impact economic event',
                        'time' => (string)($row[$timeCol] ?? ''),
                        'timestamp' => strtotime((string)($row[$timeCol] ?? '')),
                        'impact' => 'High',
                        'currency' => $currency,
                        'source' => $table,
                    ];
                }
            }

            if (!$events) return ['has_news' => false, 'risk' => 'LOW', 'events' => []];

            return [
                'has_news' => true,
                'risk' => 'HIGH',
                'score_penalty' => 2,
                'title' => $events[0]['title'] ?? 'High-impact economic event',
                'time' => $events[0]['time'] ?? '',
                'events' => $events,
            ];
        } catch (Throwable $e) {
            return ['has_news' => false, 'risk' => 'LOW', 'events' => []];
        }
    }


    public static function getMajorForexEvents(int $minutesAhead = 60): array
    {
        /*
        |--------------------------------------------------------------------------
        | ForexFactory-style major event watch
        |--------------------------------------------------------------------------
        | Uses the existing EconomicCalendarService to collect major events across
        | the main FX currencies without creating a conflicting news service.
        |--------------------------------------------------------------------------
        */

        $minutesAhead = max(15, min(1440, $minutesAhead));
        $watchSymbols = ['EURUSD', 'GBPUSD', 'USDJPY', 'USDCHF', 'USDCAD', 'AUDUSD', 'NZDUSD', 'XAUUSD'];
        $events = [];
        $seen = [];

        foreach ($watchSymbols as $symbol) {
            try {
                if (!class_exists('EconomicCalendarService') || !method_exists('EconomicCalendarService', 'getUpcomingEvents')) {
                    continue;
                }

                $rows = EconomicCalendarService::getUpcomingEvents($symbol, $minutesAhead, 0);

                foreach ($rows as $event) {
                    if (!is_array($event)) {
                        continue;
                    }

                    $impact = strtoupper((string)($event['impact'] ?? 'LOW'));
                    $title = (string)($event['title'] ?? $event['event'] ?? 'Economic event');
                    $timestamp = $event['timestamp'] ?? null;

                    if (!$timestamp && !empty($event['time'])) {
                        $timestamp = strtotime((string)$event['time']);
                    }

                    if (!$timestamp) {
                        continue;
                    }

                    if ($timestamp < time() || $timestamp > (time() + ($minutesAhead * 60))) {
                        continue;
                    }

                    if (!in_array($impact, ['MEDIUM', 'HIGH', 'EXTREME'], true)) {
                        continue;
                    }

                    $currency = strtoupper((string)($event['currency'] ?? ''));
                    $key = md5($currency . '|' . strtoupper($title) . '|' . date('Y-m-d H:i', (int)$timestamp));

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

                    $seen[$key] = true;
                    $minutesUntil = (int)ceil(((int)$timestamp - time()) / 60);

                    $event['title'] = $title;
                    $event['event'] = $title;
                    $event['currency'] = $currency ?: self::currencyFromTitle($title);
                    $event['impact'] = $impact;
                    $event['timestamp'] = (int)$timestamp;
                    $event['time'] = date('Y-m-d H:i:s', (int)$timestamp);
                    $event['minutes_until'] = $minutesUntil;
                    $event['countdown_label'] = self::countdownLabel($minutesUntil);
                    $event['source'] = $event['source'] ?? 'economic_calendar';

                    $events[] = $event;
                }
            } catch (Throwable $e) {
                continue;
            }
        }

        usort($events, fn($a, $b) => (int)($a['timestamp'] ?? 0) <=> (int)($b['timestamp'] ?? 0));

        return array_slice($events, 0, 15);
    }

    private static function currencyFromTitle(string $title): string
    {
        $upper = strtoupper($title);
        foreach (['USD','EUR','GBP','JPY','CHF','CAD','AUD','NZD'] as $cur) {
            if (str_contains($upper, $cur)) {
                return $cur;
            }
        }
        if (preg_match('/\b(FED|FOMC|CPI|PCE|NFP|NONFARM|JOBLESS|UNEMPLOYMENT|GDP|RETAIL SALES)\b/', $upper)) {
            return 'USD';
        }
        return '';
    }

    private static function firstColumn(array $cols, array $lower, array $names): ?string
    {
        foreach ($names as $name) {
            $idx = array_search($name, $lower, true);
            if ($idx !== false) return $cols[$idx];
        }
        return null;
    }

    private static function currenciesForSymbol(string $symbol): array
    {
        $symbol = strtoupper(str_replace('/', '', $symbol));
        if ($symbol === 'XAUUSD') return ['USD'];
        if (strlen($symbol) >= 6) return [substr($symbol, 0, 3), substr($symbol, 3, 3)];
        return ['USD'];
    }

    private static function affects(string $currency, string $title, array $currencies): bool
    {
        foreach ($currencies as $cur) {
            if ($currency === $cur || str_contains($title, $cur)) return true;
            if ($cur === 'USD' && (str_contains($currency, 'UNITED STATES') || str_contains($title, 'FED') || str_contains($title, 'CPI') || str_contains($title, 'NFP') || str_contains($title, 'TRUMP'))) return true;
        }
        return false;
    }

    private static function maxRisk(string $a, string $b): string
    {
        $rank = ['UNKNOWN' => 0, 'LOW' => 1, 'MEDIUM' => 2, 'HIGH' => 3, 'EXTREME' => 4];
        return ($rank[$b] ?? 0) > ($rank[$a] ?? 0) ? $b : $a;
    }

    private static function countdownLabel($minutesUntil): string
    {
        if ($minutesUntil === null) return '';
        $minutesUntil = (int)$minutesUntil;
        if ($minutesUntil >= 0) return $minutesUntil < 60 ? 'in ' . $minutesUntil . ' minutes' : 'in ' . intdiv($minutesUntil, 60) . 'h ' . ($minutesUntil % 60) . 'm';
        $ago = abs($minutesUntil);
        return $ago < 60 ? $ago . ' minutes ago' : intdiv($ago, 60) . 'h ' . ($ago % 60) . 'm ago';
    }

    private static function message(string $risk, string $title = ''): string
    {
        if (in_array(strtoupper($risk), ['HIGH', 'EXTREME'], true)) {
            return 'High-impact macro/news risk detected' . ($title ? ': ' . $title : '') . '.';
        }
        return 'No high-impact macro/news risk detected inside the configured window.';
    }
}