<?php
namespace Misuzu\Changelog;

use ErrorException;
use RuntimeException;
use Index\Http\{HttpRequest,HttpResponseBuilder};
use Index\Http\Routing\{HttpGet,RouteHandler,RouteHandlerCommon};
use Index\Syndication\FeedBuilder;
use Index\Urls\{UrlFormat,UrlRegistry,UrlSource,UrlSourceCommon};
use Misuzu\{Pagination,SiteInfo,Template};
use Misuzu\Auth\AuthInfo;
use Misuzu\Comments\CommentsContext;
use Misuzu\Users\UsersContext;

final class ChangelogRoutes implements RouteHandler, UrlSource {
    use RouteHandlerCommon, UrlSourceCommon;

    public function __construct(
        private SiteInfo $siteInfo,
        private UrlRegistry $urls,
        private ChangelogData $changelog,
        private UsersContext $usersCtx,
        private CommentsContext $commentsCtx,
        private AuthInfo $authInfo,
    ) {}

    #[HttpGet('/changelog')]
    #[UrlFormat('changelog-index', '/changelog', ['date' => '<date>', 'user' => '<user>', 'tags' => '<tags>', 'p' => '<page>'])]
    public function getIndex(HttpResponseBuilder $response, HttpRequest $request): int|string {
        $filterDate = (string)$request->getParam('date');
        $filterUser = (string)$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(empty($filterUser))
            $filterUser = null;
        else
            try {
                $filterUser = $this->usersCtx->getUserInfo($filterUser);
            } catch(RuntimeException $ex) {
                return 404;
            }

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

        $count = $this->changelog->countChanges($filterUser, $filterDate, $filterTags);
        $pagination = Pagination::fromRequest($request, $count, 30, 'p');
        if(!$pagination->validOffset)
            return 404;

        $changes = [];
        $changeInfos = $this->changelog->getChanges(userInfo: $filterUser, dateTime: $filterDate, tags: $filterTags, pagination: $pagination);
        $commentsCategoryName = null;

        foreach($changeInfos as $changeInfo) {
            $userInfo = $changeInfo->userId !== null ? $this->usersCtx->getUserInfo($changeInfo->userId) : null;

            if($commentsCategoryName === null)
                $commentsCategoryName = $changeInfo->commentsCategoryName;

            $changes[] = [
                'change' => $changeInfo,
                'user' => $userInfo,
                'user_colour' => $this->usersCtx->getUserColour($userInfo),
            ];
        }

        if(empty($changes))
            return 404;

        if(empty($filterDate))
            $commentsCategoryName = null;
        elseif($commentsCategoryName) // should this be run here?
            $this->commentsCtx->categories->ensureCategoryExists($commentsCategoryName);

        return Template::renderRaw('changelog.index', [
            'changelog_infos' => $changes,
            'changelog_date' => $filterDate,
            'changelog_user' => $filterUser,
            'changelog_tags' => $filterTags,
            'changelog_pagination' => $pagination,
            'comments_category_name' => $commentsCategoryName,
        ]);
    }

    #[HttpGet('/changelog/change/([0-9]+)')]
    #[UrlFormat('changelog-change', '/changelog/change/<change>')]
    #[UrlFormat('changelog-change-comments', '/changelog/change/<change>', fragment: 'comments')]
    public function getChange(HttpResponseBuilder $response, HttpRequest $request, string $changeId): int|string {
        try {
            $changeInfo = $this->changelog->getChange($changeId);
        } catch(RuntimeException $ex) {
            return 404;
        }

        $tagInfos = $this->changelog->getTags(changeInfo: $changeInfo);
        $userInfo = $changeInfo->userId !== null ? $this->usersCtx->getUserInfo($changeInfo->userId) : null;

        // should this be run here?
        $this->commentsCtx->categories->ensureCategoryExists($changeInfo->commentsCategoryName);

        return Template::renderRaw('changelog.change', [
            'change_info' => $changeInfo,
            'change_tags' => $tagInfos,
            'change_user_info' => $userInfo,
            'change_user_colour' => $this->usersCtx->getUserColour($userInfo),
        ]);
    }

    #[HttpGet('/changelog.(xml|rss|atom)')]
    #[UrlFormat('changelog-feed', '/changelog.xml')]
    public function getFeed(HttpResponseBuilder $response): string {
        $response->setContentType('application/rss+xml; charset=utf-8');

        $siteName = $this->siteInfo->name;
        $siteUrl = $this->siteInfo->url;
        $changes = $this->changelog->getChanges(pagination: new Pagination(10));

        $feed = new FeedBuilder;
        $feed->title = sprintf('%s ยป Changelog', $siteName);
        $feed->description = sprintf('Live feed of changes to %s.', $siteName);
        $feed->contentUrl = $siteUrl . $this->urls->format('changelog-index');
        $feed->feedUrl = $siteUrl . $this->urls->format('changelog-feed');

        foreach($changes as $change)
            $feed->createEntry(function($item) use ($change, $siteUrl) {
                $item->title = sprintf('%s: %s', $change->actionText, $change->summary);
                $item->createdAt = $change->createdTime;
                $item->contentUrl = $siteUrl . $this->urls->format('changelog-change', ['change' => $change->id]);
                $item->commentsUrl = $siteUrl . $this->urls->format('changelog-change-comments', ['change' => $change->id]);
            });

        return $feed->toXmlString();
    }
}