<?php

namespace Shm\ShmChat\SchemaChat;

use Shm\Collection\Collection;
use Shm\Shm;
use Shm\ShmDB\mDB;
use Shm\ShmTypes\Classes\ShmEventPayload;
use Shm\ShmTypes\StructureType;

class ShmChannelMessages extends Collection
{

    private static bool $indexesEnsured = false;

    public static function ensureIndexes(): void
    {

        //TODO
        return;

        if (self::$indexesEnsured) {
            return;
        }
        self::$indexesEnsured = true;

        $collection = self::_collection();

        self::createIndexIfMissing($collection, [
            ShmChannelMessagesField::CHANNEL => 1,
            ShmChannelMessagesField::_ID => -1,
        ]);

        self::createIndexIfMissing($collection, [
            ShmChannelMessagesField::CHANNEL => 1,
            ShmChannelMessagesField::OWNER => 1,
            ShmChannelMessagesField::VIEWED => 1,
        ]);

        self::createIndexIfMissing($collection, [
            ShmChannelMessagesField::CHANNEL => 1,
            ShmChannelMessagesField::CLIENT_MESSAGE_ID => 1,
        ], [
            'unique' => true,
            'sparse' => true,
        ]);
    }

    public static function findByClientMessageId($channelId, string $clientMessageId): ?object
    {
        return self::structure()->findOne([
            ShmChannelMessagesField::CHANNEL => mDB::id($channelId),
            ShmChannelMessagesField::CLIENT_MESSAGE_ID => $clientMessageId,
        ]) ?: null;
    }

    public static function isDuplicateKeyError(\Throwable $e): bool
    {
        if ((int) $e->getCode() === 11000) {
            return true;
        }

        $message = $e->getMessage();

        return str_contains($message, 'E11000') || str_contains($message, 'duplicate key');
    }

    private static function createIndexIfMissing(\MongoDB\Collection $collection, array $keys, array $options = []): void
    {
        foreach ($collection->listIndexes() as $index) {
            if (($index['key'] ?? []) === $keys) {
                return;
            }
        }

        $collection->createIndex($keys, $options);
    }

    public function schema(): ?StructureType
    {
        $schema = Shm::structure([

            "channel" => ShmChannels::ID()->indexed(),
            "clientMessageId" => Shm::string(),
            "owner" => Shm::ID()->indexed(),
            "ownerCollection" => Shm::string(),
            "text" => Shm::string()->title("Текст сообщения"),
            "type" => Shm::enum([
                "regular" => "Обычное",
                "system" => "Системное",
            ])->title("Тип сообщения")->default("regular"),
            "attachments" => Shm::arrayOf(Shm::fileDocument())->title("Вложения"),
            "reply" => ShmChannelMessages::ID(),

            'voice' => Shm::fileAudio(),

            "actions" => Shm::arrayOf(
                Shm::structure([
                    "name" => Shm::string()->title("Имя действия"),
                    "type" => Shm::string()->title("Тип")->default("button"),
                    "value" => Shm::string()->title("Значение"),
                    "text" => Shm::string()->title("Текст кнопки"),
                    "style" => Shm::enum([
                        "default" => "По умолчанию",
                        "primary" => "Основная",
                        "danger" => "Опасная"
                    ])->title("Стиль")->default("default")
                ])
            )->title("Кнопки"),

            "reactions" => Shm::arrayOf(
                Shm::structure([
                    "user" => Shm::ID(),
                    "type" => Shm::enum([
                        "heart" => "Сердце",
                        "like" => "Нравится",
                        "laugh" => "Смех",
                        "wow" => "Удивление",
                        "sad" => "Грусть",
                        "angry" => "Злость",
                        "clap" => "Аплодисменты",
                        "party" => "Праздник",
                        "poop" => "Какахa",
                        "fire" => "Огонь"
                    ]),
                    "created_at" => Shm::timestamp()->title("Когда поставлена")
                ])
            )->title("Реакции"),

            'pinned' => Shm::structure([
                'enabled' => Shm::boolean()->title("Закреплено"),
                'user' => Shm::ID()->title("Кто закрепил"),
                'timestamp' => Shm::unixdatetime()->title("Когда закреплено"),
            ]),

            "payload" =>  Shm::structure([
                '*' => Shm::mixed()
            ]),

            'viewed' => Shm::bool()->title("Прочитано"),

            'deleted' => Shm::ID()->title("Кто удалил"),

        ]);

        $schema->addEventPostInsert(function (ShmEventPayload $payload) {
            $insertDocumentID  = $payload->postInsertPayload->insertIDs[0] ?? null;

            $message = ShmChannelMessages::structure()->findOne([ShmChannelMessagesField::_ID => $insertDocumentID]);

            if ($message) {
                ShmChannels::touchLastMessage(
                    ShmChannelMessagesField::CHANNEL_GET($message),
                    ShmChannelMessagesField::_ID_GET($message)
                );

                ShmChannels::updateUnreadCounts(
                    ShmChannelMessagesField::CHANNEL_GET($message),
                    ShmChannelMessagesField::OWNER_GET($message),
                    ShmChannelMessagesField::OWNER_COLLECTION_GET($message)
                );
            }
        });

        return $schema;
    }

    public static function togglePinnedMessage(string $messageId, string $userId): void
    {
        $messageId = mDB::id($messageId);
        $userId = mDB::id($userId);

        $collection = ShmChannelMessages::structure();

        $message = $collection->findOne(
            [ShmChannelMessagesField::_ID => $messageId],
            ['projection' => [ShmChannelMessagesField::PINNED => 1, ShmChannelMessagesField::CHANNEL => 1]]
        );

        if (!$message) {
            return;
        }

        $channelId = ShmChannelMessagesField::CHANNEL_GET($message);
        $isPinned = !empty(ShmChannelMessagesField::PINNED__ENABLED_GET($message));

        if ($isPinned) {
            $collection->updateOne(
                [ShmChannelMessagesField::_ID => $messageId],
                [
                    '$set' => [
                        ShmChannelMessagesField::PINNED => null
                    ]
                ]
            );

            ShmChannels::setPinnedMessageId($channelId, null);

            return;
        }

        $collection->updateMany(
            [
                ShmChannelMessagesField::CHANNEL => mDB::id($channelId),
                ShmChannelMessagesField::_ID => ['$ne' => $messageId],
                ShmChannelMessagesField::PINNED__ENABLED => true,
            ],
            [
                '$set' => [
                    ShmChannelMessagesField::PINNED => null
                ]
            ]
        );

        $collection->updateOne(
            [ShmChannelMessagesField::_ID => $messageId],
            [
                '$set' => [
                    ShmChannelMessagesField::PINNED => [
                        ShmChannelMessagesField::PINNED__ENABLED_KEY => true,
                        ShmChannelMessagesField::PINNED__USER_KEY => $userId,
                        ShmChannelMessagesField::PINNED__TIMESTAMP_KEY => time()
                    ]
                ]
            ]
        );

        ShmChannels::setPinnedMessageId($channelId, $messageId);
    }
}
