<?php
namespace Misuzu\Home;

use RuntimeException;
use Index\DateTime;
use Index\Data\DbTools;
use Index\Data\IDbConnection;
use Index\Routing\Route;
use Index\Routing\RouteHandler;
use Misuzu\Pagination;
use Misuzu\SiteInfo;
use Misuzu\Template;
use Misuzu\Auth\AuthInfo;
use Misuzu\Changelog\Changelog;
use Misuzu\Comments\Comments;
use Misuzu\Config\IConfig;
use Misuzu\Counters\Counters;
use Misuzu\News\News;
use Misuzu\URLs\URLInfo;
use Misuzu\Users\UsersContext;

class HomeRoutes extends RouteHandler {
    public function __construct(
        private IConfig $config,
        private IDbConnection $dbConn,
        private SiteInfo $siteInfo,
        private AuthInfo $authInfo,
        private Changelog $changelog,
        private Comments $comments,
        private Counters $counters,
        private News $news,
        private UsersContext $usersCtx
    ) {}

    private function getStats(): array {
        return $this->counters->get([
            'users:active',
            'users:online:recent',
            'users:online:today',
            'comments:posts:visible',
            'forum:topics:visible',
            'forum:posts:visible',
        ]);
    }

    private function getOnlineUsers(): array {
        return $this->usersCtx->getUsers()->getUsers(
            lastActiveInMinutes: 5,
            deleted: false,
            orderBy: 'random',
        );
    }

    private array $newsCategoryInfos = [];

    private function getFeaturedNewsPosts(int $amount, bool $decorate): array {
        $postInfos = $this->news->getPosts(
            onlyFeatured: true,
            pagination: new Pagination($amount)
        );

        if(!$decorate)
            return $postInfos;

        $posts = [];

        foreach($postInfos as $postInfo) {
            $categoryId = $postInfo->getCategoryId();
            $userInfo = $postInfo->hasUserId() ? $this->usersCtx->getUserInfo($postInfo->getUserId()) : null;

            if(array_key_exists($categoryId, $this->newsCategoryInfos))
                $categoryInfo = $this->newsCategoryInfos[$categoryId];
            else
                $this->newsCategoryInfos[$categoryId] = $categoryInfo = $this->news->getCategory(postInfo: $postInfo);

            $commentsCount = $postInfo->hasCommentsCategoryId()
                ? $this->comments->countPosts(categoryInfo: $postInfo->getCommentsCategoryId(), deleted: false) : 0;

            $posts[] = [
                'post' => $postInfo,
                'category' => $categoryInfo,
                'user' => $userInfo,
                'user_colour' => $this->usersCtx->getUserColour($userInfo),
                'comments_count' => $commentsCount,
            ];
        }

        return $posts;
    }

    public function getPopularForumTopics(array $categoryIds): array {
        $args = 0;
        $stmt = $this->dbConn->prepare(
            'SELECT t.topic_id, c.forum_id, t.topic_title, c.forum_icon, t.topic_count_views'
            . ', (SELECT COUNT(*) FROM msz_forum_posts AS p WHERE p.topic_id = t.topic_id AND post_deleted IS NULL)'
            . ' FROM msz_forum_topics AS t'
            . ' LEFT JOIN msz_forum_categories AS c ON c.forum_id = t.forum_id'
            . ' WHERE c.forum_id IN (' . DbTools::prepareListString($categoryIds) . ') AND topic_deleted IS NULL AND topic_locked IS NULL'
            . ' ORDER BY (SELECT COUNT(*) FROM msz_forum_posts AS p WHERE p.topic_id = t.topic_id AND post_deleted IS NULL AND post_created > NOW() - INTERVAL 3 MONTH) DESC'
            . ' LIMIT 10'
        );

        foreach($categoryIds as $categoryId)
            $stmt->addParameter(++$args, (string)$categoryId);
        $stmt->execute();

        $topics = [];
        $result = $stmt->getResult();

        while($result->next())
            $topics[] = [
                'topic_id' => $result->getInteger(0),
                'forum_id' => $result->getInteger(1),
                'topic_title' => $result->getString(2),
                'forum_icon' => $result->getString(3),
                'topic_count_views' => $result->getInteger(4),
                'topic_count_posts' => $result->getInteger(5),
            ];

        return $topics;
    }

    public function getActiveForumTopics(array $categoryIds): array {
        $args = 0;
        $stmt = $this->dbConn->prepare(
            'SELECT t.topic_id, c.forum_id, t.topic_title, c.forum_icon, t.topic_count_views'
            . ', (SELECT COUNT(*) FROM msz_forum_posts AS p WHERE p.topic_id = t.topic_id AND post_deleted IS NULL)'
            . ', (SELECT MAX(post_id) FROM msz_forum_posts AS p WHERE p.topic_id = t.topic_id AND post_deleted IS NULL)'
            . ' FROM msz_forum_topics AS t'
            . ' LEFT JOIN msz_forum_categories AS c ON c.forum_id = t.forum_id'
            . ' WHERE c.forum_id IN (' . DbTools::prepareListString($categoryIds) . ') AND topic_deleted IS NULL AND topic_locked IS NULL'
            . ' ORDER BY topic_bumped DESC'
            . ' LIMIT 10'
        );

        foreach($categoryIds as $categoryId)
            $stmt->addParameter(++$args, (string)$categoryId);
        $stmt->execute();

        $topics = [];
        $result = $stmt->getResult();

        while($result->next())
            $topics[] = [
                'topic_id' => $result->getInteger(0),
                'forum_id' => $result->getInteger(1),
                'topic_title' => $result->getString(2),
                'forum_icon' => $result->getString(3),
                'topic_count_views' => $result->getInteger(4),
                'topic_count_posts' => $result->getInteger(5),
                'latest_post_id' => $result->getInteger(6),
            ];

        return $topics;
    }

    #[Route('GET', '/')]
    #[URLInfo('index', '/')]
    public function getIndex(...$args) {
        return $this->authInfo->isLoggedIn()
            ? $this->getHome(...$args)
            : $this->getLanding(...$args);
    }

    public function getHome() {
        $stats = $this->getStats();
        $onlineUserInfos = $this->getOnlineUsers();
        $featuredNews = $this->getFeaturedNewsPosts(5, true);
        $changelog = $this->changelog->getChanges(pagination: new Pagination(10));

        $stats['users:online:recent'] = count($onlineUserInfos);

        $birthdays = [];
        $birthdayInfos = $this->usersCtx->getUsers()->getUsers(deleted: false, birthdate: DateTime::now(), orderBy: 'random');
        foreach($birthdayInfos as $birthdayInfo)
            $birthdays[] = [
                'info' => $birthdayInfo,
                'colour' => $this->usersCtx->getUserColour($birthdayInfo),
            ];

        $newestMember = [];
        if(empty($birthdays)) {
            $newestMemberId = $this->config->getString('users.newest');
            if(!empty($newestMemberId))
                try {
                    $newestMember['info'] = $this->usersCtx->getUserInfo($newestMemberId);
                    $newestMember['colour'] = $this->usersCtx->getUserColour($newestMemberId);
                } catch(RuntimeException $ex) {
                    $newestMember = [];
                    $this->config->removeValues('users.newest');
                }
        }

        return Template::renderRaw('home.home', [
            'statistics' => $stats,
            'newest_member' => $newestMember,
            'online_users' => $onlineUserInfos,
            'birthdays' => $birthdays,
            'featured_changelog' => $changelog,
            'featured_news' => $featuredNews,
        ]);
    }

    #[Route('GET', '/_landing')]
    public function getLanding($response, $request) {
        $config = $this->config->getValues([
            ['social.embed_linked:b'],
            ['landing.forum_categories:a'],
            'social.linked:a'
        ]);

        if($config['social.embed_linked']) {
            $linkedData = [
                '@context' => 'http://schema.org',
                '@type' => 'Organization',
                'name' => $this->siteInfo->getName(),
                'url' => $this->siteInfo->getURL(),
                'logo' => $this->siteInfo->getExternalLogo(),
                'same_as' => $config['social.linked'],
            ];
        } else $linkedData = null;

        $stats = $this->getStats();
        $onlineUserInfos = $this->getOnlineUsers();
        $featuredNews = $this->getFeaturedNewsPosts(3, false);
        $popularTopics = $this->getPopularForumTopics($config['landing.forum_categories']);
        $activeTopics = $this->getActiveForumTopics($config['landing.forum_categories']);

        $stats['users:online:recent'] = count($onlineUserInfos);

        return Template::renderRaw('home.landing', [
            'statistics' => $stats,
            'online_users' => $onlineUserInfos,
            'featured_news' => $featuredNews,
            'linked_data' => $linkedData,
            'forum_popular' => $popularTopics,
            'forum_active' => $activeTopics,
        ]);
    }
}
