<?php


namespace Mainto\RpcServer\Protocol\Response\Extend;


use Mainto\RpcServer\Protocol\Response\Extend;
use Mainto\RpcServer\Protocol\Response\HeaderExtend;
use Mainto\RpcServer\Util\Binary;
use Mainto\RpcServer\Util\Bytes\Bytes;
use Mainto\RpcServer\Util\IO\Reader;
use Mainto\RpcServer\Util\IO\Writer;
use Mainto\RpcServer\Util\Reader\LittleEndianReader;

class ResponseExtendError implements HeaderExtend {
    private string $traceId = "";
    private string $errMsg = "";
    private int $errorCode = 0;

    public function magicNum () {
        return Extend::MagicNumErrorExtend;
    }

    public function writeHeaderTo (Writer $writer): int {
        $buffer = Bytes::newBuffer();

        $buffer->writeString($this->traceId);

        $buffer->writeByte(Binary::$littleEndian::intToUint64($this->errorCode));
        $buffer->writeString(Binary::$littleEndian::intToUint16(strlen($this->errMsg)));

        $buffer->writeString($this->errMsg);

        return $buffer->writeTo($writer);
    }

    public function readHeaderFrom (Reader $reader): int {
        $littleEndianReader = new LittleEndianReader($reader);

        $this->traceId = $littleEndianReader->read(16);

        $this->errorCode = $littleEndianReader->readerUint64();

        $msgLen = $littleEndianReader->readerUint16();
        $this->errMsg = $littleEndianReader->read($msgLen);

        return $littleEndianReader->getTotalReaderSize();
    }

    /**
     * @return string
     */
    public function getTraceId (): string {
        return $this->traceId;
    }

    /**
     * @param string $traceId
     */
    public function setTraceId (string $traceId): void {
        if (strlen($traceId) < 16) {
            $traceId = str_repeat("0", 16 - strlen($traceId)).$traceId;
        } else {
            $traceId = substr($traceId, 0, 16);
        }
        $this->traceId = $traceId;
    }

    /**
     * @return string
     */
    public function getErrMsg (): string {
        return $this->errMsg;
    }

    /**
     * @param string $errMsg
     */
    public function setErrMsg (string $errMsg): void {
        $this->errMsg = $errMsg;
    }

    /**
     * @return int
     */
    public function getErrorCode (): int {
        return $this->errorCode;
    }

    /**
     * @param int $errorCode
     */
    public function setErrorCode (int $errorCode): void {
        $this->errorCode = $errorCode;
    }

    public function toArray (): array {
        return [
            'type'       => 'ResponseExtendError',
            'trace id'   => $this->traceId,
            'error code' => $this->errorCode,
            'error msg'  => $this->errMsg,
        ];
    }

    public function dumpToWriter (Writer $writer) {
        return json_encode($this->toArray(), JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE);
    }
}