<?php


namespace Mainto\RpcServer\RpcServer\ConnectionHandler;


use Illuminate\Support\Facades\Log;
use Mainto\RpcServer\Log\LogHandler;
use Mainto\RpcServer\Protocol\Common\Body;
use Mainto\RpcServer\Protocol\Common\Types\RequestHeaderType;
use Mainto\RpcServer\Protocol\Request\Request;
use Mainto\RpcServer\Protocol\Response\Response;
use Mainto\RpcServer\RpcServer\BaseConnectionHandler;
use Mainto\RpcServer\RpcServer\Connection\RpcUnixConnection;
use Mainto\RpcServer\RpcServer\RpcRouter;
use Mainto\RpcServer\Util\Net\Conn;
use Mainto\RpcServer\Util\OS;
use RuntimeException;
use Throwable;

class MasterConnectionHandler extends BaseConnectionHandler {
    private static ?MasterConnectionHandler $instance = null;

    public static function newInstance (): MasterConnectionHandler {
        if (self::$instance == null) {
            OS::setProcessTitle(sprintf("rpc-php [%s] [master] master", config('rpc-server.service_name')));

            self::$instance = new self();
        }

        return self::$instance;
    }

    public function onRequest (Request $request): Response {
        switch ($request->getType()) {
            case RequestHeaderType::SidecarScaleUpType :
                $unixAddress = collect($request->getBody()->getContent())->get("unix");
                $childId = pcntl_fork();
                if ($childId < 0) {
                    throw new RuntimeException("fork fail");
                } elseif ($childId == 0) {
                    try {
                        LogHandler::init(storage_path("logs/service/".now()->format("Y-m-d")), pathinfo($unixAddress, PATHINFO_FILENAME));

                        Log::info("worker start and serve", ['pid' => getmypid(), 'unix' => $unixAddress]);

                        //                    $this->close();
                        OS::setProcessTitle(sprintf("rpc-php [%s] [%s] child", config('rpc-server.service_name'), $unixAddress));

                        $seed = intval(time() + (microtime(true) * 1000));
                        mt_srand($seed);

                        RpcUnixConnection::mustNewInstance($unixAddress, new ChildConnectionHandler(), 3)->start();
                    } catch (Throwable $exception) {
                        Log::warning("child exit by error", ['error' => $exception->getMessage()]);
                    } finally {
                        exit(0);
                    }
                }

                $this->cacheResponse->useReturnOKType();
                $this->cacheResponse->setBody(Body::newJsonBody(json_encode(["pid" => $childId])));
                return $this->cacheResponse;
            case RequestHeaderType::SidecarConfigType:
                return self::serviceConfigResponse();
            case RequestHeaderType::SystemCheckType:

                $this->cacheResponse->useReturnOKType();
                return $this->cacheResponse;
        }

        $this->cacheResponse->useReturnErrType();
        return $this->cacheResponse;
    }

    public function onClose (Conn $socket) {
    }

    public static function serviceConfigResponse () {
        $response = new Response();
        $response->useReturnOKType();

        $body = Body::newJsonBody(json_encode(RpcRouter::getInstance()->getBaseRouterConfig()));
        $response->setBody($body);

        return $response;
    }

    public function beforeStart (Conn $conn) {
        // 忽略子进程退出信号
        pcntl_signal(SIGCHLD, SIG_IGN);
    }
}
