<?php

/**
 * CheckDataSign.php
 * 文件描述
 * Created On 2021/12/15
 * @author yuanb yuanbo0x@gmail.com
 */

namespace Game\Controller;

use Framework\Define\ErrorDefine;
use Framework\Log\LogMark;
use Framework\MVC\ControllerBase;
use Framework\MVC\ModelManager;
use Framework\Network\SendMessage;
use Game\Constant\ModelTypeDefine;
use Game\Logic\CarLogic;
use Game\Protobuf\MD5VerifyRecv;
use Game\Protobuf\MD5VerifySend;
use Game\Protobuf\ModuleId;
use Game\Protobuf\ModuleServerData;
use Game\Protobuf\ModuleVerifyData;
use Game\Protobuf\PacketId;

class CheckDataSign extends ControllerBase
{
    use CarLogic;

    private MD5VerifyRecv $sendMessage;
    private array $sendPacket = array();
    public const MODULE_2_MODEL = array(
        ModuleId::Account => ModelTypeDefine::ACCOUNT,
        ModuleId::Storehouse => ModelTypeDefine::ITEM,
        ModuleId::RacingCar => ModelTypeDefine::CAR,
        ModuleId::SeasonRank => ModelTypeDefine::PAIWEI_LEVEL,
        ModuleId::Friend => ModelTypeDefine::FRIEND,
        ModuleID::ExteriorRefit => ModelTypeDefine::CAR_EXTERIOR_REFIT,
        ModuleID::MyClubInfo => ModelTypeDefine::CLUB,
        ModuleID::Ranking => ModelTypeDefine::RANKING,
    );

    public function __construct()
    {
        $this->message = new MD5VerifySend();
        $this->sendMessage = new MD5VerifyRecv();
        $this->sendMessage->setIsVerifyOk(true);
    }

    public function run(): int
    {
        foreach ($this->message->getPacketList() as $packet) {
            if (!$this->checkSign($packet)) {
                $this->sendMessage->setIsVerifyOk(false);
            }
        }
        if (!empty($this->sendPacket)) {
            $this->sendMessage->setPacketList($this->sendPacket);
        }
        SendMessage::getInstance()->sendClient(PacketId::Verify_Recv, $this->sendMessage);
        //新车消息通知--临时用
        $this->sendNewCarNotice($this->playerId);
        return ErrorDefine::SUCCESS;
    }

    public function checkSign(ModuleVerifyData $data): bool
    {
        $moduleId = $data->getMoudleId();
        $modelData = $this->getModelData($moduleId);
        if (is_null($modelData)) {
            return false;
        }
        $server_sign = $this->getServerMd5Sign($modelData);
        if ($server_sign == $data->getMD5()) {
            return true;
        }
        $packet = new ModuleServerData();
        $packet->setModuleId($moduleId);
        $packet->setModuleData(json_encode($modelData));
        $this->sendPacket[] = $packet;
        return false;
    }

    /***
     * @param $serverData
     * @return string
     * 数据按键名升序排序,把value连接拼成字符串做md5
     * 二维数组,也按照此方法排序,把value连接拼成字符串
     */
    public function getServerMd5Sign($serverData): string
    {
        //检查数组维度
        if (empty($serverData)) {
            return md5("");
        }
        ksort($serverData);
        $str = "";
        foreach ($serverData as $key => $value) {
            if (is_array($value)) {
                ksort($value);
                $vv = array_values($value);
                foreach($vv as $k=>$v) {
                    if(is_array($v)) {
                        ksort($v);
                        $vv[$k] = implode('', $v);
                    } else {
                        $vv[$k] = strval($v);
                    }
                }
                $str .= implode("", $vv);
            } else {
                $str .= strval($value);
            }
        }
        return md5($str);
    }

    //获取需要校验的model数据
    public function getModelData($moduleId)
    {
        if (!array_key_exists($moduleId, self::MODULE_2_MODEL)) {
            return null;
        }
        $modelName = self::MODULE_2_MODEL[$moduleId];
        $model = ModelManager::getInstance()->getModel($modelName);
        if (!is_null($model)) {
            return $model->getSignData();
        }
        return null;
    }
}
