<?php

namespace Shm\ShmAddons\EventTicketAddon\Types\HallType;

use Shm\Shm;
use Shm\ShmDB\mDB;
use Shm\ShmRPC\ShmRPCCodeGen\TSType;
use Shm\ShmTypes\BaseType;
use Traversable;

class HallType extends BaseType
{
    public string $type = 'hall';


    public bool $compositeType = true;




    private static function isTempClientId(mixed $id): bool
    {
        return is_string($id) && str_contains($id, 'tml_');
    }

    /**
     * @return \MongoDB\BSON\ObjectId|null
     */
    private static function toMongoObjectId(mixed $id): ?\MongoDB\BSON\ObjectId
    {
        if ($id instanceof \MongoDB\BSON\ObjectId) {
            return $id;
        }

        $converted = mDB::id($id);

        return $converted instanceof \MongoDB\BSON\ObjectId ? $converted : null;
    }

    /**
     * @param array<string, mixed> $document
     * @return array{updateOne: array{0: array, 1: array}}
     */
    private static function bulkUpdateOneOp(array $document): array
    {
        $filter = mDB::replaceStringToObjectIds(['_id' => $document['_id']]);
        $set = $document;
        unset($set['_id']);

        return [
            'updateOne' => [
                $filter,
                ['$set' => $set],
            ],
        ];
    }

    /**
     * @param list<array{updateOne: array{0: array, 1: array}}> $operations
     */
    private static function flushBulkUpdates(array $operations): void
    {
        if ($operations === []) {
            return;
        }

        HallElements::_collection()->bulkWrite($operations);
    }


    public function tsType(): TSType
    {



        $TSType = new TSType('string');
        $TSType->comment($this->title);

        return $TSType;
    }



    public function normalize(mixed $values, $addDefaultValues = false, string | null $processId = null): mixed
    {



        if (!$values) return null;


        $isArray = is_array($values) || $values instanceof Traversable;


        if (!$isArray && is_string($values)) {
            return $values;
        }





        $hallUUID = null;
        //Проверяем что у всех элементов есть поле hallUUID, если нет то возвращаем null
        foreach ($values as $value) {
            if (!isset($value['hallUUID'])) {
                Shm::error('У элементов зала отсутствует идентификатор зала');
            }
            $hallUUID = $value['hallUUID'];
        }


        $tmpIdToMongoId = [];

        $sectorDocsToInsert = [];
        $sectorTmpIds = [];
        $sectorBulkUpdates = [];

        foreach ($values as $value) {
            if (!is_array($value) || ($value['type'] ?? null) !== 'sector') {
                continue;
            }

            if (self::isTempClientId($value['_id'] ?? null)) {
                $doc = $value;
                unset($doc['_id']);
                $sectorDocsToInsert[] = $doc;
                $sectorTmpIds[] = $value['_id'];
            } else {
                $sectorBulkUpdates[] = self::bulkUpdateOneOp($value);
            }
        }

        if ($sectorDocsToInsert !== []) {
            $insertResult = HallElements::_collection()->insertMany($sectorDocsToInsert);
            $insertedIds = $insertResult->getInsertedIds();
            foreach ($sectorTmpIds as $i => $tmpId) {
                $tmpIdToMongoId[$tmpId] = $insertedIds[$i];
            }
        }

        self::flushBulkUpdates($sectorBulkUpdates);

        $otherDocsToInsert = [];
        $otherTmpIds = [];
        $otherBulkUpdates = [];

        foreach ($values as $value) {
            if (!is_array($value) || ($value['type'] ?? null) === 'sector') {
                continue;
            }

            $doc = $value;
            if (isset($doc['sector']) && self::isTempClientId($doc['sector'])) {
                $doc['sector'] = $tmpIdToMongoId[$doc['sector']];
            }

            if (self::isTempClientId($doc['_id'] ?? null)) {
                $tmpKey = $doc['_id'];
                unset($doc['_id']);
                $otherDocsToInsert[] = $doc;
                $otherTmpIds[] = $tmpKey;
            } else {
                $otherBulkUpdates[] = self::bulkUpdateOneOp($doc);
            }
        }

        if ($otherDocsToInsert !== []) {
            $insertResult = HallElements::_collection()->insertMany($otherDocsToInsert);
            $insertedIds = $insertResult->getInsertedIds();
            foreach ($otherTmpIds as $i => $tmpId) {
                $tmpIdToMongoId[$tmpId] = $insertedIds[$i];
            }
        }

        self::flushBulkUpdates($otherBulkUpdates);

        $allMongoIds = [];
        foreach ($values as $value) {
            if (!is_array($value) || !isset($value['_id'])) {
                continue;
            }

            $clientId = $value['_id'];
            if (self::isTempClientId($clientId)) {
                if (!isset($tmpIdToMongoId[$clientId])) {
                    continue;
                }
                $mongoId = self::toMongoObjectId($tmpIdToMongoId[$clientId]);
            } else {
                $mongoId = self::toMongoObjectId($clientId);
            }

            if ($mongoId !== null) {
                $allMongoIds[] = $mongoId;
            }
        }



        HallElements::_collection()->deleteMany(['hallUUID' => $hallUUID, '_id' => ['$nin' => $allMongoIds]]);



        return  $hallUUID;
    }
}
