<?php

namespace Shm\ShmChat;

use Shm\ShmChat\SchemaChat\ShmChannelMessages;
use Shm\ShmChat\SchemaChat\ShmChannels;
use Shm\ShmChat\ShmChatBlueprints\ShmChatBlueprintsClientRPC;
use Shm\ShmUtils\ShmInit;
use Shm\ShmUtils\ShmTwig;

/**
 * Фабрика каналов и точка входа RPC.
 *
 * @example
 * ```php
 * $user = Member::of($order->userId, 'users');
 * $support = Member::of($adminId, 'admins')->admin();
 * $orderLink = Link::to($order->_id, 'orders');
 *
 * $chat = ShmChat::findOrCreate(
 *     members: [$user, $support],
 *     links: [$orderLink],
 *     name: 'Заказ #' . $order->number,
 * );
 *
 * $chat->system('Обращение создано', $support);
 * $chat->send($support, 'Здравствуйте!');
 * ```
 */
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 get(string $channelId): Channel
    {
        return new Channel($channelId);
    }

    /**
     * @param list<Member> $members
     * @param list<Link> $links
     */
    public static function find(
        array $members = [],
        array $links = [],
        ?string $space = null,
        ?bool $closed = null,
    ): ?Channel {
        $doc = ShmChatService::findChannel($members, $links, $space, $closed);

        if (!$doc) {
            return null;
        }

        return new Channel((string) $doc->_id);
    }

    /**
     * @param list<Member> $members
     * @param list<Link> $links
     * @return list<Channel>
     */
    public static function findAll(
        array $members = [],
        array $links = [],
        ?string $space = null,
        ?bool $closed = null,
    ): array {
        $docs = ShmChatService::findChannels($members, $links, $space, $closed);

        return array_map(
            static fn (object $doc) => new Channel((string) $doc->_id),
            $docs,
        );
    }

    /**
     * @param list<Member> $members
     * @param list<Link> $links
     * @param list<Member> $invites
     * @param array<string, mixed> $payload
     */
    public static function create(
        array $members,
        array $links = [],
        string $name = '',
        string $space = '',
        array $invites = [],
        array $payload = [],
        bool $closed = false,
    ): Channel {
        $doc = ShmChatService::createChannel(
            $members,
            $links,
            $name,
            $space,
            $invites,
            $payload,
            $closed,
        );

        return new Channel((string) $doc->_id);
    }

    /**
     * Найти канал по критериям или создать новый.
     *
     * Поиск: links и/или members (+ optional space/closed).
     * Если не найден — создаёт с теми же members/links и name/space/invites/payload.
     *
     * @param list<Member> $members
     * @param list<Link> $links
     * @param list<Member> $invites
     * @param array<string, mixed> $payload
     */
    public static function findOrCreate(
        array $members,
        array $links = [],
        string $name = '',
        string $space = '',
        array $invites = [],
        array $payload = [],
        ?bool $closed = null,
    ): Channel {
        $existing = ShmChatService::findChannel(
            $members,
            $links,
            $space !== '' ? $space : null,
            $closed,
        );

        if ($existing) {
            return new Channel((string) $existing->_id);
        }

        return self::create(
            members: $members,
            links: $links,
            name: $name,
            space: $space,
            invites: $invites,
            payload: $payload,
            closed: $closed ?? false,
        );
    }

    public static function direct(Member $a, Member $b, string $space = ''): Channel
    {
        $doc = ShmChatService::findOrCreateDirect($a, $b, $space !== '' ? $space : null);

        return new Channel((string) $doc->_id);
    }

    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);
    }
}
