<?php

namespace Shm\ShmAdmin\AdminRPC;

use Shm\Shm;
use Shm\ShmAdmin\AdminPanel;
use Shm\ShmAuth\Auth;
use Shm\ShmRPC\ShmRPC;
use Shm\ShmTypes\Classes\EventClasses\ShmEventPostInsertPayload;
use Shm\ShmTypes\Classes\EventClasses\ShmEventPostUpdatePayload;
use Shm\ShmTypes\Classes\EventClasses\ShmEventPreInsertPayload;
use Shm\ShmTypes\Classes\EventClasses\ShmEventPreUpdatePayload;
use Shm\ShmTypes\Classes\ShmEventPayload;
use Shm\ShmUtils\I18n;
use Shm\ShmUtils\Response;

class AdminRPCUpdate
{
    public static function rpc()
    {

        return ShmRPC::lazy(function () {

            return [
                'type' => Shm::structure(
                    [
                        'data' => Shm::arrayOf(Shm::structure([
                            "_id" => Shm::ID(),
                            "*" => Shm::mixed(),
                        ])),
                    ]
                ),
                'args' => Shm::structure([

                    "_ids" => Shm::IDs()->default(null),
                    "collection" => Shm::nonNull(Shm::string()),
                    'values' => Shm::mixed(),

                ]),
                'resolve' => function ($root, $args) {

                    Auth::authenticateOrThrow(...AdminPanel::$authStructures);

                    if (!isset($args['collection'])) {
                        Response::validation(I18n::get('data_not_available_for_view'));
                    }




                    $structure = AdminPanel::fullSchema()->findItemByCollection($args['collection']);







                    if (!$structure) {
                        Response::validation(I18n::get('data_not_available_for_view'));
                    }


                    $rootType = $root->getType();
                    $rootType->items['data'] = Shm::arrayOf($structure);

                    $root->setType($rootType);




                    $values = $args['values'] ?? null;


                    if (!$values) {
                        Response::validation(I18n::get('no_data_to_update'));
                    }

                    $values = $structure->normalize($values);


                    $values = $structure->removeOtherItems($values);




                    //remove _id
                    if (isset($values['_id'])) {
                        unset($values['_id']);
                    }

                    $ids = $args['_ids'] ?? null;



                    if ($structure->single) {

                        $pipeline = $structure->getPipeline();

                        $pipeline = [
                            ...$pipeline,
                            [
                                '$limit' => 1
                            ],
                        ];

                        $result = $structure->aggregate($pipeline)->toArray() ?? null;

                        $id = $result[0]['_id'] ?? null;



                        if (!$id) {

                            $eventPayload = new ShmEventPayload();
                            $eventPayload->preInsertPayload = new ShmEventPreInsertPayload();
                            $eventPayload->preInsertPayload->insertDocuments = [$values];
                            $structure->callEventPreInsertAdmin($eventPayload);


                            $insert = $structure->insertOne($values);

                            if (!$insert) {
                                Response::validation(I18n::get('add_data_error'));
                            }

                            $eventPayload->postInsertPayload = new ShmEventPostInsertPayload();
                            $eventPayload->postInsertPayload->insertDocuments = [$values];
                            $eventPayload->postInsertPayload->insertIDs = [$insert->getInsertedId()];
                            $structure->callEventPostInsertAdmin($eventPayload);



                            return [
                                'data' => $structure->find([
                                    '_id' => $insert->getInsertedId(),
                                ])
                            ];
                        } else {

                            $eventPayload = new ShmEventPayload();
                            $eventPayload->preUpdatePayload = new ShmEventPreUpdatePayload();
                            $eventPayload->preUpdatePayload->filter = [
                                "_id" => $id,
                            ];
                            $eventPayload->preUpdatePayload->update = [
                                '$set' => $values
                            ];
                            $structure->callEventPreUpdateAdmin($eventPayload);

                            $update =  $structure->updateOne(
                                [
                                    "_id" => $id,
                                ],
                                [
                                    '$set' => $values
                                ]
                            );

                            $eventPayload->postUpdatePayload = new ShmEventPostUpdatePayload();
                            $eventPayload->postUpdatePayload->filter = [
                                "_id" => $id,
                            ];
                            $eventPayload->postUpdatePayload->update = [
                                '$set' => $values
                            ];
                            $structure->callEventPostUpdateAdmin($eventPayload);

                            return [
                                'data' => $structure->find([
                                    '_id' => $id
                                ]),
                            ];
                        }
                    }




                    if ($ids) {

                        $eventPayload = new ShmEventPayload();
                        $eventPayload->preUpdatePayload = new ShmEventPreUpdatePayload();
                        $eventPayload->preUpdatePayload->filter = [
                            "_id" => ['$in' => $ids],
                        ];
                        $eventPayload->preUpdatePayload->update = [
                            '$set' => $values
                        ];
                        $structure->callEventPreUpdateAdmin($eventPayload);


                        $update = $structure->updateMany(
                            [
                                "_id" => ['$in' => $ids],
                            ],
                            [
                                '$set' => $values
                            ]
                        );

                        $eventPayload->postUpdatePayload = new ShmEventPostUpdatePayload();
                        $eventPayload->postUpdatePayload->filter = [
                            "_id" => ['$in' => $ids],
                        ];
                        $eventPayload->postUpdatePayload->update = [
                            '$set' => $values
                        ];
                        $structure->callEventPostUpdateAdmin($eventPayload);

                        return [
                            'data' => $structure->find([
                                '_id' => ['$in' => $ids],
                            ]),
                        ];
                    } else {

                        $eventPayload = new ShmEventPayload();
                        $eventPayload->preInsertPayload = new ShmEventPreInsertPayload();
                        $eventPayload->preInsertPayload->insertDocuments = [$values];
                        $structure->callEventPreInsertAdmin($eventPayload);

                        $insert =  $structure->insertOne($values);

                        if (!$insert) {
                            Response::validation(I18n::get('add_data_error'));
                        }

                        $eventPayload->postInsertPayload = new ShmEventPostInsertPayload();
                        $eventPayload->postInsertPayload->insertDocuments = [$values];
                        $eventPayload->postInsertPayload->insertIDs = [$insert->getInsertedId()];
                        $structure->callEventPostInsertAdmin($eventPayload);

                        $result = $structure->findOne([
                            '_id' => $insert->getInsertedId(),
                        ]);

                        return [
                            'data' => [$result],
                        ];
                    }
                }

            ];
        });
    }
}
