<?php

namespace onespace\tools\activeApi\components\clients;

use onespace\tools\activeApi\components\clients\base\BaseOneSpaceClient;
use onespace\tools\rabbit\components\Rabbit;
use thamtech\uuid\helpers\UuidHelper;
use Yii;
use yii\helpers\ArrayHelper;
use yii\helpers\Json;
use yii\web\BadRequestHttpException;

class CommunicationsClient extends BaseOneSpaceClient {
    public function serverUrl(): string {
        return Yii::$app->params['serviceUrls']['communications'];
    }

    public const int MESSAGE_CHUNK_MAX_SIZE = 48000;

    /**
     * Emit a message to the communications microservice for sending
     */
    public function sendViaRabbit(?array $how, string|array $who, array $what, ?string $when, string $userId, string $siteId, ?int $type = 0, ?int $ttl = null): void {
        /** @var Rabbit $rabbit */
        $rabbit = Yii::$app->rabbit;

        $timestamp = time();
        $payload = Json::encode([
            'event' => [
                'type' => 'create',
                'timestamp' => $timestamp,
            ],
            'entity' => [
                'type' => 'sendMessage',
                'message' => [
                    'how' => $how,
                    'who' => $who,
                    'what' => $what,
                    'when' => $when,
                ],
                'sender' => $userId, // User OSID
                'site' => $siteId, // site GUID
                'messageType' => $type,
                'ttl' => $ttl,
            ],
        ]);

        $originalPayloadBytes = strlen($payload);
        if ($originalPayloadBytes > self::MESSAGE_CHUNK_MAX_SIZE) {
            $batchId = UuidHelper::uuid();
            $chunks = str_split($payload, self::MESSAGE_CHUNK_MAX_SIZE);
            $totalChunks = count($chunks);
            $ttl = 60 * 60 * 3; // 3 hours

            foreach ($chunks as $index => $chunk) {
                $chunkPayload = Json::encode([
                    'event' => [
                        'type' => 'create',
                        'timestamp' => $timestamp,
                    ],
                    'entity' => [
                        'type' => 'sendChunk',
                        'chunkedMessage' => [
                            'batchId' => $batchId,
                            'sequence' => $index,
                            'total' => $totalChunks,
                            'payloadBytes' => $originalPayloadBytes,
                            'chunkBytes' => strlen($chunk),
                            'data' => $chunk,
                            'ttl' => $ttl,
                            'notify' => $userId,
                            'site' => $siteId,
                            'title' => $what['title'] ?? "Message",
                        ],
                    ],
                ]);

                $routingKey = implode('.', [
                    "v1.json.message.send.batch",
                    $index,
                    $batchId,
                    $timestamp,
                ]);
                $rabbit->outboxSendMessage("onespace.system", $chunkPayload, $routingKey, timestamp: $timestamp);
            }
        } else {
            $routingKey = "v1.json.message.send." . $timestamp;
            $rabbit->outboxSendMessage("onespace.system", $payload, $routingKey, timestamp: $timestamp);
        }
    }

    /**
     * Create a new message via API call
     */
    public function sendViaEndpoint(?array $how, string|array $who, array $what, ?string $when, string $userId, string $siteId, ?int $type = 0, ?int $ttl = null): bool {
        $response = self::goPost('api/v1/add', [
            'message' => [
                'how' => $how,
                'who' => $who,
                'what' => $what,
                'when' => $when,
            ],
            'sender' => $userId,
            'site' => $siteId,
            'type' => $type,
            'ttl' => $ttl,
        ]);

        /** @var bool $success */
        $success = ArrayHelper::getValue($response, "data.success", false);
        return $success;
    }

    /**
     * Cancel a specified message if possible
     */
    public function cancel(string $messageId): bool {
        $response = self::goPost('api/v1/cancel', ['messageId' => $messageId]);

        /** @var bool $success */
        $success = ArrayHelper::getValue($response, "data.success", false);
        return $success;
    }

    /**
     * Get a specified message
     *
     * @param string $id    The Recipient OR Message ULID. It is generally expected for the ID to be a Recipient ID.
     *                      If passing a message ID, it must be accompanied by the user ID, and be from a CONNECT request.
     * @param string|null $userId   Only request on a CONNECT request.
     */
    public function getMessage(string $id, ?string $userId = null): array|false {
        $inConnect = Yii::$app->session->get('IN_CONNECT', false);
        if ($inConnect) {
            // A Connect Request
            if ($userId === null) {
                throw new BadRequestHttpException("You must pass a user GUID for this request");
            }
            $response = self::goGet('api/v1/view/connect?id=' . $id . '&user=' . $userId);
            $message = ArrayHelper::getValue($response, "data.message", false);
            return $message;
        }

        // A Standard Web Request
        $response = self::goGet('api/v1/view?id=' . $id);
        $message = ArrayHelper::getValue($response, "data.message", false);
        return $message;
    }

    /**
     * Get a list of messages for the user
     *
     * @todo    Currently limitted to the last 50. Revamp for gridview data
     */
    public function listMessages(string $osid, ?string $siteId = null): array|false {
        $url = 'api/v1/view/list?id=' . $osid;
        if ($siteId !== null) {
            $url .= '&siteId=' . $siteId;
        }

        $response = self::goGet($url);

        $message = ArrayHelper::getValue($response, "data.results", false);
        return $message;
    }

    /**
     * Get a message via it's public ID
     */
    public function getMessageViaPublicId(string $publicId): string|false {
        $response = self::goGet('api/v1/view/public?id=' . $publicId);

        $message = ArrayHelper::getValue($response, "data", false);
        return $message;
    }
}
