<?php

/**
 * MrssFormat - RSS 2.0 + Media RSS
 * http://www.rssboard.org/rss-specification
 * http://www.rssboard.org/media-rss
 *
 * Validators:
 * https://validator.w3.org/feed/
 * http://www.rssboard.org/rss-validator/
 *
 * Notes about the implementation:
 *
 * - The item author is not supported as it needs to be an e-mail address to be
 *   valid.
 * - The RSS specification does not explicitly allow to have more than one
 *   enclosure as every item is meant to provide one "story", thus having
 *   multiple enclosures per item may lead to unexpected behavior.
 *   On top of that, it requires to have a length specified, which RSS-Bridge
 *   can't provide.
 * - The Media RSS extension comes in handy, since it allows to have multiple
 *   enclosures, even though they recommend to have only one enclosure because
 *   of the one-story-per-item reason. It only requires to specify the URL,
 *   everything else is optional.
 * - Since the Media RSS extension has its own namespace, the output is a valid
 *   RSS 2.0 feed that works with feed readers that don't support the extension.
 */
class MrssFormat extends FormatAbstract
{
    const MIME_TYPE = 'application/rss+xml';

    protected const ATOM_NS = 'http://www.w3.org/2005/Atom';
    protected const MRSS_NS = 'http://search.yahoo.com/mrss/';

    public function render(): string
    {
        $document = new \DomDocument('1.0', 'UTF-8');
        $document->formatOutput = true;

        $feed = $document->createElement('rss');
        $document->appendChild($feed);
        $feed->setAttribute('version', '2.0');
        $feed->setAttributeNS('http://www.w3.org/2000/xmlns/', 'xmlns:atom', self::ATOM_NS);
        $feed->setAttributeNS('http://www.w3.org/2000/xmlns/', 'xmlns:media', self::MRSS_NS);

        $channel = $document->createElement('channel');
        $feed->appendChild($channel);

        $feedArray = $this->getFeed();
        $uri = $feedArray['uri'];
        $title = $feedArray['name'];

        foreach ($feedArray as $feedKey => $feedValue) {
            if (in_array($feedKey, ['atom', 'donationUri'])) {
                continue;
            }
            if ($feedKey === 'name') {
                $channelTitle = $document->createElement('title');
                $channel->appendChild($channelTitle);
                $channelTitle->appendChild($document->createTextNode($title));

                $description = $document->createElement('description');
                $channel->appendChild($description);
                $description->appendChild($document->createTextNode($title));
            } elseif ($feedKey === 'uri') {
                $link = $document->createElement('link');
                $channel->appendChild($link);
                $link->appendChild($document->createTextNode($uri));

                $linkAlternate = $document->createElementNS(self::ATOM_NS, 'link');
                $channel->appendChild($linkAlternate);
                $linkAlternate->setAttribute('rel', 'alternate');
                $linkAlternate->setAttribute('type', 'text/html');
                $linkAlternate->setAttribute('href', $uri);

                $linkSelf = $document->createElementNS(self::ATOM_NS, 'link');
                $channel->appendChild($linkSelf);
                $linkSelf->setAttribute('rel', 'self');
                $linkSelf->setAttribute('type', 'application/atom+xml');
                $feedUrl = get_current_url();
                $linkSelf->setAttribute('href', $feedUrl);
            } elseif ($feedKey === 'icon') {
                $allowedIconExtensions = [
                    '.gif',
                    '.jpg',
                    '.png',
                    '.ico',
                ];
                $icon = $feedValue;
                if ($icon && in_array(substr($icon, -4), $allowedIconExtensions)) {
                    $feedImage = $document->createElement('image');
                    $channel->appendChild($feedImage);
                    $iconUrl = $document->createElement('url');
                    $iconUrl->appendChild($document->createTextNode($icon));
                    $feedImage->appendChild($iconUrl);
                    $iconTitle = $document->createElement('title');
                    $iconTitle->appendChild($document->createTextNode($title));
                    $feedImage->appendChild($iconTitle);
                    $iconLink = $document->createElement('link');
                    $iconLink->appendChild($document->createTextNode($uri));
                    $feedImage->appendChild($iconLink);
                }
            } elseif ($feedKey === 'itunes') {
                $feed->setAttributeNS('http://www.w3.org/2000/xmlns/', 'xmlns:itunes', self::ITUNES_NS);
                foreach ($feedValue as $itunesKey => $itunesValue) {
                    $itunesProperty = $document->createElementNS(self::ITUNES_NS, $itunesKey);
                    $channel->appendChild($itunesProperty);
                    $itunesProperty->appendChild($document->createTextNode($itunesValue));
                }
            } else {
                $element = $document->createElement($feedKey);
                $channel->appendChild($element);
                $element->appendChild($document->createTextNode($feedValue));
            }
        }

        foreach ($this->getItems() as $item) {
            $itemArray = $item->toArray();
            $itemTimestamp = $item->getTimestamp();
            $itemTitle = $item->getTitle();
            $itemUri = $item->getURI();
            $itemContent = $item->getContent() ?? '';
            $itemUid = $item->getUid();
            $isPermaLink = 'false';

            if (empty($itemUid) && !empty($itemUri)) {
                // Fallback to provided URI
                $itemUid = $itemUri;
                $isPermaLink = 'true';
            }

            if (empty($itemUid)) {
                // Fallback to title and content
                $itemUid = hash('sha1', $itemTitle . $itemContent);
            }

            $entry = $document->createElement('item');
            $channel->appendChild($entry);

            if (!empty($itemTitle)) {
                $entryTitle = $document->createElement('title');
                $entry->appendChild($entryTitle);
                $entryTitle->appendChild($document->createTextNode($itemTitle));
            }

            if (isset($itemArray['itunes'])) {
                $feed->setAttributeNS('http://www.w3.org/2000/xmlns/', 'xmlns:itunes', self::ITUNES_NS);
                foreach ($itemArray['itunes'] as $itunesKey => $itunesValue) {
                    $itunesProperty = $document->createElementNS(self::ITUNES_NS, $itunesKey);
                    $entry->appendChild($itunesProperty);
                    $itunesProperty->appendChild($document->createTextNode($itunesValue));
                }

                if (isset($itemArray['enclosure'])) {
                    $itunesEnclosure = $document->createElement('enclosure');
                    $entry->appendChild($itunesEnclosure);
                    $itunesEnclosure->setAttribute('url', $itemArray['enclosure']['url']);
                    $itunesEnclosure->setAttribute('length', $itemArray['enclosure']['length']);
                    $itunesEnclosure->setAttribute('type', $itemArray['enclosure']['type']);
                }
            }

            if (!empty($itemUri)) {
                $entryLink = $document->createElement('link');
                $entry->appendChild($entryLink);
                $entryLink->appendChild($document->createTextNode($itemUri));
            }

            $entryGuid = $document->createElement('guid');
            $entryGuid->setAttribute('isPermaLink', $isPermaLink);
            $entry->appendChild($entryGuid);
            $entryGuid->appendChild($document->createTextNode($itemUid));

            if (!empty($itemTimestamp)) {
                $entryPublished = $document->createElement('pubDate');
                $entry->appendChild($entryPublished);
                $entryPublished->appendChild($document->createTextNode(gmdate(\DATE_RFC2822, $itemTimestamp)));
            }

            if (!empty($itemContent)) {
                $entryDescription = $document->createElement('description');
                $entry->appendChild($entryDescription);
                $entryDescription->appendChild($document->createTextNode($itemContent));
            }

            foreach ($item->getEnclosures() as $enclosure) {
                $entryEnclosure = $document->createElementNS(self::MRSS_NS, 'content');
                $entry->appendChild($entryEnclosure);
                $entryEnclosure->setAttribute('url', $enclosure);
                $entryEnclosure->setAttribute('type', parse_mime_type($enclosure));
            }

            foreach ($item->getCategories() as $category) {
                $entryCategory = $document->createElement('category');
                $entry->appendChild($entryCategory);
                $entryCategory->appendChild($document->createTextNode($category));
            }
        }

        $xml = $document->saveXML();
        return $xml;
    }
}