<?php
/**
 * Created by PhpStorm.
 * User: PHPStorm
 * Date: 18-10-22
 * Time: 下午3:17
 */

namespace Mainto\RpcServer\Providers;

use Doctrine\Common\Annotations\AnnotationReader;
use Doctrine\Common\Annotations\AnnotationRegistry;
use Mainto\RpcServer\Command\RpcChildCommand;
use Mainto\RpcServer\Command\RpcChildFastMqCommand;
use Mainto\RpcServer\Command\RpcSidecarCommand;
use Mainto\RpcServer\Command\RpcServerCommand;
use Mainto\RpcServer\RpcClient\RpcClass;
use Mainto\RpcServer\RpcServer\RpcInvoke;
use Mainto\RpcServer\RpcServer\RpcRouter;
use Mainto\RpcServer\RpcServer\RpcSessionHandlerInterface;
use Mainto\RpcServer\RpcUtil\SessionHandler\SessionTestHandler;
use Mainto\RpcServer\RpcUtil\Tool\RpcLog;
use Mainto\RpcServer\RpcUtil\Tool\RpcMutexProviderInterface;
use Mainto\RpcServer\Util\Language;

class ServiceProvider extends \Illuminate\Support\ServiceProvider {
    /**
     * Bootstrap the application services.
     *
     * @return void
     */
    public function boot () {
        if ($this->app->runningInConsole()) {

            $this->publishes([
                __DIR__.'/../config.php' => config_path('rpc-server.php'),
            ], 'config');
        }
    }

    /**
     * Register the application services.
     *
     * @return void
     */
    public function register () {
        $this->mergeConfigFrom(__DIR__.'/../config.php', 'rpc-server');

        $this->app->bind('command.rpc.sidecar', RpcSidecarCommand::class);
        $this->app->bind('command.rpc.server', RpcServerCommand::class);
        $this->app->bind('command.rpc.child', RpcChildCommand::class);
        $this->app->bind('command.rpc.child-fastmq', RpcChildFastMqCommand::class);

        $this->commands([
            'command.rpc.sidecar',
            'command.rpc.server',
            'command.rpc.child',
            'command.rpc.child-fastmq',
        ]);

        $this->app->singleton('rpc-log', function () {
            return RpcLog::getInstance();
        });

        $this->app->singleton('rpc-server', fn() => RpcRouter::getInstance());

        $loader = new RpcAnnotationLoader();
        // todo remove
        AnnotationRegistry::registerLoader([$loader, "loadClass"]);

        $this->app->singleton(AnnotationReader::class, function () {
            return new AnnotationReader();
        });

        $this->app->singleton(RpcMutexProviderInterface::class, function () {
            return new class implements RpcMutexProviderInterface {
                private static function getLockCli() {
                    return RpcClass::getClass("CoreGear", "Lock");
                }

                public static function getLock (string $lockName, int $expireTime = 600) {
                    return self::getLockCli()->getLock([
                        "lockName"   => $lockName,
                        "expireTime" => $expireTime,
                    ]);
                }

                public static function unLock (string $lockName, string $password): bool {
                    return self::getLockCli()->unlock([
                        "lockName" => $lockName,
                        "password" => $password,
                    ]);
                }
            };
        });

        if (config('rpc-server.session_driver') == 'gear-store') {
            $this->app->singleton(RpcSessionHandlerInterface::class, function () {
                return new class implements RpcSessionHandlerInterface {
                    private function getStore() {
                        return RpcClass::getClass("CoreGear", "Store");
                    }

                    public function getSessionStringBySessionId ($sessionId): ?string {
                        return $this->getStore()->get([
                            "key" => $sessionId,
                        ]);
                    }

                    public function updateSession ($sessionId, $sessionString, $seconds): void {
                        $this->getStore()->set([
                            "key"        => $sessionId,
                            "value"      => $sessionString,
                            "expireTime" => $seconds,
                        ]);
                    }

                    public function deleteSession ($sessionId): void {
                        $this->getStore()->delete([
                            "key" => $sessionId,
                        ]);
                    }
                };
            });
        } else {
            $this->app->singleton(RpcSessionHandlerInterface::class, SessionTestHandler::class);
        }

        // init service
        RpcInvoke::initCacheResponse();
        Language::init();
    }
}
