<?php

/*
 * Copyright (c) 2010-2022 Tim Düsterhus.
 *
 * Use of this software is governed by the Business Source License
 * included in the LICENSE file.
 *
 * Change Date: 2026-03-04
 *
 * On the date above, in accordance with the Business Source
 * License, use of this software will be governed by version 2
 * or later of the General Public License.
 */

namespace chat\page;

use chat\data\message\Message;
use chat\data\message\MessageList;
use chat\data\room\RoomCache;
use wcf\data\object\type\ObjectTypeCache;
use wcf\page\AbstractPage;
use wcf\system\database\util\PreparedStatementConditionBuilder;
use wcf\system\exception\IllegalLinkException;
use wcf\system\exception\PermissionDeniedException;
use wcf\system\page\PageLocationManager;
use wcf\system\request\LinkHandler;
use wcf\system\WCF;
use wcf\util\HeaderUtil;

/**
 * Shows the log of a specific chat room.
 */
final class LogPage extends AbstractPage
{
    use TConfiguredPage;

    /**
     * @inheritDoc
     */
    public $loginRequired = true;

    /**
     * The requested chat room ID.
     * @var int
     */
    public $roomID = 0;

    /**
     * The requested chat room.
     * @var \chat\data\room\Room
     */
    public $room;

    /**
     * The requested message ID.
     * @var int
     */
    public $messageID = 0;

    /**
     * The requested message.
     * @var \chat\data\message\Message
     */
    public $message;

    /**
     * The requested time.
     * @var int
     */
    public $datetime = 0;

    /**
     * @inheritDoc
     */
    public function readParameters()
    {
        parent::readParameters();

        if (isset($_GET['id'])) {
            $this->roomID = \intval($_GET['id']);
        }
        $this->room = RoomCache::getInstance()->getRoom($this->roomID);

        if ($this->room === null) {
            throw new IllegalLinkException();
        }
        if (!$this->room->canSee($user = null, $reason)) {
            throw $reason;
        }
        if (!$this->room->canSeeLog($user = null, $reason)) {
            throw $reason;
        }

        if (isset($_GET['messageid'])) {
            $this->messageID = \intval($_GET['messageid']);
        }
        if ($this->messageID) {
            $this->message = new Message($this->messageID);
            if (!$this->message->getMessageType()->getProcessor()->canSeeInLog($this->message, $this->room)) {
                throw new PermissionDeniedException();
            }
        }

        if (isset($_REQUEST['datetime'])) {
            $this->datetime = \strtotime($_REQUEST['datetime']);
        }
    }

    /**
     * @inheritDoc
     */
    public function readData()
    {
        parent::readData();

        if ($this->datetime) {
            // Determine message types supporting fast select
            $objectTypes = ObjectTypeCache::getInstance()->getObjectTypes('be.bastelstu.chat.messageType');
            $fastSelect = \array_map(static function ($item) {
                return $item->objectTypeID;
            }, \array_filter($objectTypes, static function ($item) {
                // TODO: Consider a method couldAppearInLog(): bool
                return $item->getProcessor()->supportsFastSelect();
            }));

            $minimum = 0;
            $loops = 0;
            do {
                // Build fast select filter
                $condition = new PreparedStatementConditionBuilder();
                $condition->add('((roomID = ? AND objectTypeID IN (?)) OR objectTypeID NOT IN (?))', [ $this->room->roomID, $fastSelect, $fastSelect ]);
                $condition->add('time >= ?', [ $this->datetime ]);
                if ($minimum) {
                    $condition->add('messageID > ?', [ $minimum ]);
                }

                $sql = "SELECT  messageID
                        FROM    chat1_message
                        {$condition}
                        ORDER BY messageID ASC";
                $statement = WCF::getDB()->prepare($sql, 20);
                $statement->execute($condition->getParameters());
                $messageIDs = $statement->fetchAll(\PDO::FETCH_COLUMN);

                $objectList = new MessageList();
                $objectList->setObjectIDs($messageIDs);
                $objectList->readObjects();
                $objects = $objectList->getObjects();
                if (empty($objects)) {
                    // TODO: UserInputException?
                    throw new IllegalLinkException();
                }

                foreach ($objects as $message) {
                    if ($message->getMessageType()->getProcessor()->canSeeInLog($message, $this->room)) {
                        $parameters = [
                            'messageid' => $message->messageID,
                            'object' => $this->room,
                        ];
                        HeaderUtil::redirect(LinkHandler::getInstance()->getControllerLink(self::class, $parameters));

                        exit;
                    }
                    $minimum = $message->messageID;
                }
            } while (++$loops <= 3);

            // Do a best guess redirect to an ID that is as near as possible
            $parameters = [
                'application' => 'chat',
                'messageid' => $minimum,
                'object' => $this->room,
            ];
            HeaderUtil::redirect(LinkHandler::getInstance()->getControllerLink(self::class, $parameters));

            exit;
        }
    }

    /**
     * @inheritDoc
     */
    public function assignVariables()
    {
        parent::assignVariables();

        PageLocationManager::getInstance()->addParentLocation(
            'be.bastelstu.chat.Room',
            $this->room->roomID,
            $this->room
        );
        WCF::getTPL()->assign([
            'room' => $this->room,
            'roomList' => RoomCache::getInstance()->getRooms(),
            'messageID' => $this->messageID,
            'message' => $this->message,
            'config' => $this->getConfig(),
        ]);
    }
}