<?php

namespace Shm\ShmChat;

use Shm\ShmChat\Classes\ChannelReference;
use Shm\ShmChat\Classes\ChatChannelContext;
use Shm\ShmChat\Classes\ChatMember;
use Shm\ShmChat\Classes\CreateChannelInput;
use Shm\ShmChat\Classes\FindChannelsInput;
use Shm\ShmChat\Classes\ListQueryInput;
use Shm\ShmChat\Classes\SendMessageInput;
use Shm\ShmChat\SchemaChat\ShmChannelMessages;
use Shm\ShmChat\SchemaChat\ShmChannels;
use Shm\ShmChat\ShmChatBlueprints\ShmChatBlueprintsClientRPC;
use Shm\ShmUtils\ShmInit;
use Shm\ShmUtils\ShmTwig;

/**
 * Server-side API для работы с чатами из PHP-кода (cron, webhooks, бизнес-логика).
 *
 * @example
 * ```php
 * ShmChat::ensureIndexes();
 *
 * $user = new ChatMember($order->userId, 'users');
 * $support = new ChatMember($adminId, 'admins', 'support');
 *
 * $channel = ShmChat::findOrCreateDirect($user, $support, 'orders:' . $order->_id);
 *
 * ShmChat::sendSystemMessage((string) $channel->_id, 'Обращение #' . $order->number, $support);
 *
 * ShmChat::sendMessage(new SendMessageInput(
 *     channelId: (string) $channel->_id,
 *     sender: $support,
 *     text: 'Здравствуйте!',
 * ));
 *
 * Для joinable-каналов и имён участников настройте в схеме коллекции пользователей:
 * `$usersSchema->setChatNameHandler(fn ($id) => ...)` и
 * `ShmChannels::setJoinablePipelineHandler(fn (): array => [...])`.
 * ```
 */
class ShmChat
{
    private static function url($path = "")
    {
        $scheme =  (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on') ? 'https' : 'http';

        $host = $_SERVER['HTTP_HOST'] ?? "";

        $currentURL = $scheme . '://' . $host;

        return $currentURL . $path;
    }

    private static function html()
    {
        $url = self::url();

        $js =  $url . "/static/chat.js?shm=" . ShmInit::$shmVersionHash;
        $css = $url . "/static/chat.css?shm=" . ShmInit::$shmVersionHash;

        return ShmTwig::render('@shm/chat', [
            'js' => $js,
            'css' => $css,
        ]);
    }

    public static function ensureIndexes(): void
    {
        ShmChannels::ensureIndexes();
        ShmChannelMessages::ensureIndexes();
    }

    public static function createChannel(CreateChannelInput $input): object
    {
        return ShmChatService::createChannel($input);
    }

    public static function findOrCreateDirect(ChatMember $a, ChatMember $b, ?string $space = null): object
    {
        return ShmChatService::findOrCreateDirect($a, $b, $space);
    }

    public static function getChannel(string $channelId): ?object
    {
        return ShmChatService::getChannel($channelId);
    }

    public static function addMember(string $channelId, ChatMember $member): bool
    {
        return ShmChatService::addMember($channelId, $member);
    }

    public static function addReference(string $channelId, ChannelReference $ref): bool
    {
        return ShmChatService::addReference($channelId, $ref);
    }

    public static function removeReference(string $channelId, ChannelReference $ref): bool
    {
        return ShmChatService::removeReference($channelId, $ref);
    }

    /**
     * @return list<object>
     */
    public static function findChannels(FindChannelsInput $input): array
    {
        return ShmChatService::findChannels($input);
    }

    public static function findChannel(FindChannelsInput $input): ?object
    {
        return ShmChatService::findChannel($input);
    }

    /**
     * @return list<object>
     */
    public static function findChannelsByReference(
        ChannelReference $ref,
        ?string $type = null,
        ?bool $closed = null,
    ): array {
        return ShmChatService::findChannelsByReference($ref, $type, $closed);
    }

    public static function findChannelByReference(
        ChannelReference $ref,
        ?string $type = null,
        ?bool $closed = null,
    ): ?object {
        return ShmChatService::findChannelByReference($ref, $type, $closed);
    }

    public static function closeChannel(string $channelId, ?ChatMember $by = null): bool
    {
        return ShmChatService::closeChannel($channelId, $by);
    }

    public static function sendMessage(SendMessageInput $input): object
    {
        return ShmChatService::sendMessage($input);
    }

    public static function sendSystemMessage(string $channelId, string $text, ?ChatMember $by = null): object
    {
        return ShmChatService::sendSystemMessage($channelId, $text, $by);
    }

    public static function markRead(string $channelId, ChatMember $reader, ?string $lastReadMessageId = null): void
    {
        ShmChatService::markRead($channelId, $reader, $lastReadMessageId);
    }

    /**
     * @return array{data?: array<int, mixed>, hash: string}
     */
    public static function listChannelsForMember(ChatMember $member, ListQueryInput $query): array
    {
        return ShmChatService::listChannelsForMember($member, $query);
    }

    /**
     * @return array{data?: array<int, mixed>, hash: string}
     */
    public static function listJoinableChannels(ListQueryInput $query): array
    {
        return ShmChatService::listJoinableChannels($query);
    }

    /**
     * @return array{data?: array<int, mixed>, hash: string}
     */
    public static function listMessages(string $channelId, ListQueryInput $query): array
    {
        return ShmChatService::listMessages($channelId, $query);
    }

    public static function togglePinnedMessage(string $messageId, ChatMember $by): bool
    {
        return ShmChatService::togglePinnedMessage($messageId, $by);
    }

    public static function toggleReaction(
        string $channelId,
        string $messageId,
        string $reaction,
        ChatMember $user,
    ): bool {
        return ShmChatService::toggleReaction($channelId, $messageId, $reaction, $user);
    }

    public static function deleteMessage(string $channelId, string $messageId, ChatMember $by): bool
    {
        return ShmChatService::deleteMessage($channelId, $messageId, $by);
    }

    public static function channel(string $channelId): ChatChannelContext
    {
        return new ChatChannelContext($channelId);
    }

    public static function rpc(array $authStructures = [])
    {
        self::ensureIndexes();

        if (!isset($_GET['schema']) && $_SERVER['REQUEST_METHOD'] === 'GET') {
            header_remove("X-Frame-Options");
            $html = self::html();

            header('Content-Type: text/html; charset=utf-8');
            echo $html;
            exit;
        }

        ShmChatBlueprintsClientRPC::init($authStructures);
    }
}