<?php
namespace Misuzu\Http\Handlers;

use ErrorException;
use RuntimeException;
use Misuzu\Pagination;
use Misuzu\Template;
use Misuzu\Comments\CommentsEx;
use Misuzu\Feeds\Feed;
use Misuzu\Feeds\FeedItem;
use Misuzu\Feeds\AtomFeedSerializer;
use Misuzu\Feeds\RssFeedSerializer;
use Misuzu\Users\User;

class ChangelogHandler extends Handler {
    private array $userInfos = [];

    public function index($response, $request) {
        $filterDate = (string)$request->getParam('date');
        $filterUser = (int)$request->getParam('user', FILTER_SANITIZE_NUMBER_INT);
        $filterTags = (string)$request->getParam('tags');

        if(empty($filterDate))
            $filterDate = null;
        else
            try {
                $dateParts = explode('-', $filterDate, 3);
                $filterDate = gmmktime(12, 0, 0, (int)$dateParts[1], (int)$dateParts[2], (int)$dateParts[0]);
            } catch(ErrorException $ex) {
                return 404;
            }

        if($filterUser > 0)
            try {
                $filterUser = User::byId($filterUser);
            } catch(RuntimeException $ex) {
                return 404;
            }
        else
            $filterUser = null;

        if(empty($filterTags))
            $filterTags = null;
        else {
            $filterTags = explode(',', $filterTags);
            foreach($filterTags as &$tag)
                $tag = trim($tag);
        }

        $changelog = $this->context->getChangelog();
        $count = $changelog->countAllChanges($filterUser, $filterDate, $filterTags);
        $pagination = new Pagination($count, 30);
        if(!$pagination->hasValidOffset())
            return 404;

        $changeInfos = $changelog->getAllChanges(userInfo: $filterUser, dateTime: $filterDate, tags: $filterTags, pagination: $pagination);
        if(empty($changeInfos))
            return 404;

        $changes = [];

        foreach($changeInfos as $changeInfo) {
            $userId = $changeInfo->getUserId();

            if(array_key_exists($userId, $this->userInfos)) {
                $userInfo = $this->userInfos[$userId];
            } else {
                try {
                    $userInfo = User::byId($userId);
                } catch(RuntimeException $ex) {
                    $userInfo = null;
                }

                $this->userInfos[$userId] = $userInfo;
            }

            $changes[] = [
                'change' => $changeInfo,
                'user' => $userInfo,
            ];
        }

        $response->setContent(Template::renderRaw('changelog.index', [
            'changelog_infos' => $changes,
            'changelog_date' => $filterDate,
            'changelog_user' => $filterUser,
            'changelog_tags' => $filterTags,
            'changelog_pagination' => $pagination,
            'comments_info' => empty($filterDate) ? null : $this->getCommentsInfo($changeInfos[0]->getCommentsCategoryName()),
        ]));
    }

    private function getCommentsInfo(string $categoryName): object {
        $comments = new CommentsEx($this->context->getComments(), $this->userInfos);
        return $comments->getCommentsForLayout($categoryName);
    }

    public function change($response, $request, string $changeId) {
        try {
            $changeInfo = $this->context->getChangelog()->getChangeById($changeId, withTags: true);
        } catch(RuntimeException $ex) {
            return 404;
        }

        try {
            $userInfo = User::byId($changeInfo->getUserId());
        } catch(RuntimeException $ex) {
            $userInfo = null;
        }

        $response->setContent(Template::renderRaw('changelog.change', [
            'change_info' => $changeInfo,
            'change_user_info' => $userInfo,
            'comments_info' => $this->getCommentsInfo($changeInfo->getCommentsCategoryName()),
        ]));
    }

    private function createFeed(string $feedMode): Feed {
        $siteName = $this->context->getConfig()->getString('site.name', 'Misuzu');
        $changes = $this->context->getChangelog()->getAllChanges(pagination: new Pagination(10));

        $feed = (new Feed)
            ->setTitle($siteName . ' » Changelog')
            ->setDescription('Live feed of changes to ' . $siteName . '.')
            ->setContentUrl(url_prefix(false) . url('changelog-index'))
            ->setFeedUrl(url_prefix(false) . url("changelog-feed-{$feedMode}"));

        foreach($changes as $change) {
            $changeUrl = url_prefix(false) . url('changelog-change', ['change' => $change->getId()]);
            $commentsUrl = url_prefix(false) . url('changelog-change-comments', ['change' => $change->getId()]);

            $feedItem = (new FeedItem)
                ->setTitle($change->getActionText() . ': ' . $change->getSummary())
                ->setCreationDate($change->getCreatedTime())
                ->setUniqueId($changeUrl)
                ->setContentUrl($changeUrl)
                ->setCommentsUrl($commentsUrl);

            $feed->addItem($feedItem);
        }

        return $feed;
    }

    public function feedAtom($response, $request) {
        $response->setContentType('application/atom+xml; charset=utf-8');
        return (new AtomFeedSerializer)->serializeFeed(self::createFeed('atom'));
    }

    public function feedRss($response, $request) {
        $response->setContentType('application/rss+xml; charset=utf-8');
        return (new RssFeedSerializer)->serializeFeed(self::createFeed('rss'));
    }
}
