<?php

class RSSFeedService
{
    public static function fetch(string $url, int $limit = 20): array
    {
        $response = self::request($url);

        if (!$response['ok']) {
            return [
                'ok' => false,
                'items' => [],
                'message' => $response['message'],
                'source_url' => $url
            ];
        }

        $items = self::parseRss($response['body'], $limit);

        return [
            'ok' => true,
            'items' => $items,
            'message' => count($items) ? 'RSS feed loaded.' : 'RSS loaded but no items found.',
            'source_url' => $url
        ];
    }

    private static function request(string $url): array
    {
        $ch = curl_init();

        curl_setopt_array($ch, [
            CURLOPT_URL => $url,
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_TIMEOUT => 20,
            CURLOPT_CONNECTTIMEOUT => 10,
            CURLOPT_FOLLOWLOCATION => true,
            CURLOPT_SSL_VERIFYPEER => false,
            CURLOPT_USERAGENT => 'InstitutionalTradingAssistant/1.0',
            CURLOPT_HTTPHEADER => [
                'Accept: application/rss+xml, application/xml, text/xml, */*'
            ],
        ]);

        $body = curl_exec($ch);
        $http = (int)curl_getinfo($ch, CURLINFO_HTTP_CODE);
        $error = curl_error($ch);

        curl_close($ch);

        if ($body === false || $http < 200 || $http >= 300) {
            return [
                'ok' => false,
                'body' => '',
                'message' => $error ?: ('HTTP ' . $http)
            ];
        }

        return [
            'ok' => true,
            'body' => $body,
            'message' => 'OK'
        ];
    }

    private static function parseRss(string $xmlText, int $limit): array
    {
        libxml_use_internal_errors(true);

        $xml = simplexml_load_string($xmlText, 'SimpleXMLElement', LIBXML_NOCDATA);

        if (!$xml) {
            return [];
        }

        $items = [];

        if (isset($xml->channel->item)) {
            foreach ($xml->channel->item as $item) {
                $items[] = self::normalizeItem($item);
                if (count($items) >= $limit) break;
            }
        } elseif (isset($xml->entry)) {
            foreach ($xml->entry as $entry) {
                $items[] = self::normalizeAtom($entry);
                if (count($items) >= $limit) break;
            }
        }

        return array_values(array_filter($items, fn($item) => !empty($item['title'])));
    }

    private static function normalizeItem(SimpleXMLElement $item): array
    {
        return [
            'title' => trim((string)$item->title),
            'summary' => trim(strip_tags((string)($item->description ?? ''))),
            'url' => trim((string)$item->link),
            'published_at' => trim((string)($item->pubDate ?? '')),
            'source' => '',
        ];
    }

    private static function normalizeAtom(SimpleXMLElement $entry): array
    {
        $link = '';

        if (isset($entry->link)) {
            foreach ($entry->link as $l) {
                $attrs = $l->attributes();
                if (isset($attrs['href'])) {
                    $link = (string)$attrs['href'];
                    break;
                }
            }
        }

        return [
            'title' => trim((string)$entry->title),
            'summary' => trim(strip_tags((string)($entry->summary ?? $entry->content ?? ''))),
            'url' => $link,
            'published_at' => trim((string)($entry->updated ?? $entry->published ?? '')),
            'source' => '',
        ];
    }
}
