<?php
/**
 *
 * @author：llbjj
 * @DateTime：2022/5/4 13:23
 * @Description：
 *
 */

namespace Application\Mvc\Controller;

use Application\Common\Container;
use Application\Common\StatusCode;
use Application\Mvc\Controller\Plugins\RenderApiJson;
use Application\Service\Extension\Document\Document;
use Application\Service\Extension\Helper\DocumentHelper;
use Application\Service\Extension\Params\Params;
use Application\Service\Extension\Validator\ValidatorApplication;
use Application\Service\Login\Adapter\AccoutPwd;
use Laminas\Db\Sql\Predicate\Operator;
use Laminas\Mvc\Controller\AbstractActionController;
use Laminas\Mvc\MvcEvent;
use Laminas\Validator\Exception\InvalidArgumentException;

/**
 * Class BasicController
 * @package Application\Mvc\Controller
 * @method Container|mixed LocalService()
 * @method RenderApiJson RenderApiJson()
 * @property ValidatorApplication $validator
 */
class BasicController extends AbstractActionController
{
    public function __get($name)
    {
        if ($name === 'validator') {
            $this->validator = new ValidatorApplication();
            return $this->validator;
        }
    }

    public function onDispatch(MvcEvent $e)
    {
        try {
            // 初始化 Params 组件
            new Params($this->params()->fromPost());

            $rf = new \ReflectionClass($this);
            $matchedAction = $e->getRouteMatch()->getParams()['action'];
            $documentString = $rf->getMethod("{$matchedAction}Action")->getDocComment();
            // 初始化 document 组件
            new Document($documentString);

//            SDMHelper::app()->log->handleDocument($doc);
            DocumentHelper::load($documentString);
        } catch (\Throwable $e) {
            var_dump($e->getMessage());die;
        }

        return parent::onDispatch($e);
    }

    /**
     * Notes: 绑定默认的监听事件
     * User: llbjj
     * DateTime: 2022/5/4 13:40
     *
     */
    protected function attachDefaultListeners()
    {
        $event = $this->getEventManager();
        // 检测路由的访问方式['POST', 'GET', 'PUT', 'DELETE'], 未设置，默认为POST
        $event->attach(MvcEvent::EVENT_DISPATCH, [$this, 'checkRouterMethod'], 98);
        // 检测用户是否被锁定
        $event->attach(MvcEvent::EVENT_DISPATCH, [$this, 'checkLocked'], 100);
        // 检测用户登录信息
        $event->attach(MvcEvent::EVENT_DISPATCH, [$this, 'checkLogin'], 99);
        parent::attachDefaultListeners(); // TODO: Change the autogenerated stub
    }

    public function checkLocked() {
        $redisExtend = $this->LocalService()->redisExtend->setNamespace(AccoutPwd::LOGIN_LOCKED_NAMESPACE);

        // 验证IP是否锁定
        $ipAddressKey = AccoutPwd::formatRedisKey(AccoutPwd::IP_ADDRESS_KEY, $_SERVER['REMOTE_ADDR']);
        if( $redisExtend->getItem($ipAddressKey) ) {
            throw new \Application\Service\Exceptions\InvalidArgumentException(
                sprintf("您的IP地址已被锁定，请%s分钟后重试",  call_user_func(function() use (&$redisExtend, &$ipAddressKey) {
                        $ttl = $redisExtend->getRedisInstance()->ttl(sprintf("%s:%s", AccoutPwd::LOGIN_LOCKED_NAMESPACE, $ipAddressKey)) ?? 0;
                        return ceil( $ttl / 60 );
                    })
                )
            );
        }

        // 验证账户是否锁定
        $loginAccountKey = AccoutPwd::formatRedisKey(AccoutPwd::LOGIN_ACCOUNT_KEY, $this->LocalService()->identity->getMobile());
        if( $redisExtend->getItem($loginAccountKey) ) {
            throw new \Application\Service\Exceptions\InvalidArgumentException(sprintf("账户已被锁定，请%s分钟后重试!", call_user_func(function() use(&$redisExtend, &$loginAccountKey) {
                $ttl = $redisExtend->getRedisInstance()->ttl(sprintf("%s:%s", AccoutPwd::LOGIN_LOCKED_NAMESPACE, $loginAccountKey)) ?? 0;
                return ceil( $ttl / 60 );
            })));
        }
    }

    /**
     * Notes: 检测路由的访问方式
     * User: llbjj
     * DateTime: 2022/9/6 11:53
     *
     * @return \Laminas\View\Model\JsonModel|void
     */
    function checkRouterMethod() {
        $allowMethod = $this->getEvent()->getRouteMatch()->getParam('http_method');
        $allowMethod = $allowMethod ?: ['post'];
        // 全部转换为小写
        foreach($allowMethod as $k => $v) {
            $allowMethod[$k] = strtolower($v);
        }

        if(!in_array(strtolower($this->getRequest()->getMethod()), $allowMethod)) throw  new InvalidArgumentException(StatusCode::E_ACCESS['msg']);
    }

    /**
     * Notes: 检测用户是否登录
     * User: llbjj
     * DateTime: 2022/5/4 13:41
     *
     * @param MvcEvent $event
     */
    function checkLogin(MvcEvent $event){
        $headers = $this->getRequest()->getHeaders()->toArray();
        if(!isset($headers['Token'])){
            $defaultTokenData = $this->LocalService()->config['defaultToken'];
            if($defaultTokenData['is_open']) $headers['Token'] = $defaultTokenData['default_token'];
            $headersObj = new \Laminas\Http\Headers();
            $headersObj->addHeaders($headers);
            $this->getRequest()->setHeaders($headersObj);
        }
        //验证token的有效性
        $this->LocalService()->identity->getIdentityData();
    }
    //获取用户ID
    public function GetUserId(){
        return $this->LocalService()->identity->getId();
    }


    /**
     * 新增项目时，批量添加real角色
     * param $itemId 项目id
     * param $userId 添加人的id
     */
    public function itemRealRoleAction($itemId,$userId){
        $time = time();
        $sortNum = 10;
        $whereArr['where'] = [
            'is_del' => 0,
            'item_id' => $itemId,
        ];
        $realSortArr = $this->LocalService()->realRole->getAdminRealRoleData($whereArr['where'],3,'sort');
        !empty($realSortArr) && $sortNum = max($realSortArr)+10;

        //默认角色信息
        $itemRealRoles = [
            ['name'=>'研究医生','code'=>'yjys'],
            ['name'=>'研究助理','code'=>'yjzl'],
            ['name'=>'申办者','code'=>'sbz'],
            ['name'=>'医学','code'=>'yx'],
            ['name'=>'PM','code'=>'pm'],
            ['name'=>'CRA','code'=>'cra'],
            ['name'=>'CRC','code'=>'crc'],
            ['name'=>'DM','code'=>'dm']
        ];

        //查询real端菜单
        $whereMArr['where'] = [
            'is_del' => 0,
            'menu_type' => 1,
            new Operator('parent_id', Operator::OP_GT, 0)
        ];
        $whereMArr['order'] = 'menu_order';
        $menuLists = $this->LocalService()->adminMenu->getAdminMenuData($whereMArr,1);

        //增加默认角色以及权限
        foreach($itemRealRoles as $k=>$itemRealRole){
            $v = $itemRealRole['name'];
            $role_code = $itemRealRole['code'];
            $realRoleArr = [
                'status' => 0,
                'is_del' => 0,
                'update_time' => $time,
                'create_time' => $time,
                'update_user_id' => $userId,
                'create_user_id' => $userId,
                'item_id' => $itemId,
                'sort' => $sortNum,
                'code' => $role_code,
            ];
            $realRoleArr['role_name'] = $v;
            if ($k > 1){
                $realRoleArr['source_type'] = 1;
            }
            $sortNum = $sortNum+10;
            $realRoleId = $this->LocalService()->realRole->save($realRoleArr);
            //新增项目时 默认角色权限
            if (!empty($menuLists)){
                foreach ($menuLists as $menuList) {
                    $value = $menuList['id'];
                    $role_power_arr = !is_null($menuList['role_code_power']) && !empty($menuList['role_code_power']) ? json_decode($menuList['role_code_power'],true) : [];
                    $role_power = isset($role_power_arr[$role_code]) && !empty($role_power_arr[$role_code]) ? intval($role_power_arr[$role_code]) : 0;
                    if(!empty($role_power)){
                        $look_write = 0;
                        if($role_power == 2){
                            $look_write = 1;
                        }
                        $realRolemodulerelationArr = [
                            'role_id'=>$realRoleId,
                            'module_id'=>$value,
                            'item_id'=>$itemId,
                            'look_write'=>$look_write
                        ];
                        $this->LocalService()->realRolemodulerelation->save($realRolemodulerelationArr);
                    }
                }
            }
        }
        return $realRoleId;
    }

    /**
     * 新增项目时，批量添加real角色
     * param $itemId 项目id
     * param $userId 添加人的id
     */
    public function OLDitemRealRoleAction($itemId,$userId){
        $time = time();
        $sortNum = 10;
        $whereArr['where'] = [
            'is_del' => 0,
            'item_id' => $itemId,
        ];
        $realSortArr = $this->LocalService()->realRole->getAdminRealRoleData($whereArr['where'],3,'sort');
        !empty($realSortArr) && $sortNum = max($realSortArr)+10;
        $itemRealRoleName = ['研究医生','研究助理','PM','CRA','CRC','DM'];
        $itemRealRoleCode = ['yjys','yjzl','pm','cra','crc','dm'];
        $whereMArr['where'] = ['is_del' => 0, 'menu_type' => 1];
        $whereMArr['order'] = 'menu_order';
        $menuList = $this->LocalService()->adminMenu->getAdminMenuData($whereMArr,1);
        $menuIdArr = [];
        if (!empty($menuList)){
            $menuIdArr = array_column($menuList,'id');
        }
        foreach($itemRealRoleName as $k=>$v){
            $realRoleArr = [
                'status' => 0,
                'is_del' => 0,
                'update_time' => $time,
                'create_time' => $time,
                'update_user_id' => $userId,
                'create_user_id' => $userId,
                'item_id' => $itemId,
                'sort' => $sortNum,
                'code' => $itemRealRoleCode[$k],
            ];
            $realRoleArr['role_name'] = $v;
            if ($k > 1){
                $realRoleArr['source_type'] = 1;
            }
            $sortNum = $sortNum+10;
            $realRoleId = $this->LocalService()->realRole->save($realRoleArr);
            if (!empty($menuIdArr)){
                foreach ($menuIdArr as $key => $value) {
                    //新增项目时 默认角色没有揭盲、紧急揭盲权限
                    if($value == 53 || $value == 54) continue;
                    $realRolemodulerelationArr['role_id'] = $realRoleId;
                    $realRolemodulerelationArr['module_id'] = $value;
                    $realRolemodulerelationArr['item_id'] = $itemId;
                    if(($k < 2) || ($k == 4)){
                        $realRolemodulerelationArr['look_write'] = 1;
                    }else{
                        $realRolemodulerelationArr['look_write'] = 0;
                    }
                    $realRolemodulerelationId = $this->LocalService()->realRolemodulerelation->save($realRolemodulerelationArr);
                }
            }
        }
        return $realRoleId;
    }
    //验证

    /**
     * @param $config
     * @throws \Exception
     */
    public function Check($config, array $fnParams = [], array $postData = []){

        $target = '';
        if(strpos($config, '.')){
            list($config, $target) = explode('.', $config);
        }
        $validator= new ValidatorApplication($postData);
        $validator->attach(
            [[], 'form', 'config' => ucfirst($config), 'target' => $target, 'fnParams' => $fnParams]
//            ['form', 'class' => new FormValidator([
//                'config' => ucfirst($config)
//            ]), 'target' => $target, 'fnParams' => $fnParams]
        );
        if(!$validator->isValid()){
            throw new InvalidArgumentException($validator->getFirstErrorToString());
        }
    }
    //引入
    public function Introduce($formValidator, array $params = []){
        $path=APP_PATH.'/formData/';
        $fromMap=include $path.'formMap.php';
        $fromData=include $path.ucfirst($formValidator).'Data.php';
        if (!empty($fromData)){
            if(is_callable($fromData)) return $fromData($params);
            return $fromData;
        }else{
            return [];
        }
    }

    //数据返回
    public function return_data($code='200',$msg='ok',$data=[],$FormFileData=[],$FormInfo=[]){
        exit(
            json_encode([
                'code'=>$code,
                'msg'=>$msg,
                'data'=>$data,
                'FormFileData'=>$FormFileData,
                'FormInfo'=>$FormInfo,
            ])
        );
    }

    /**
     * 获取id
     * param $arr 要处理的数据
     * param $field 字段
     */
    public function GetSelectStr(array $arr,$field){
        $field_str='';
        foreach ($arr as $k=>$v){
            if(!empty($v[$field])){
                $field_str.=$v[$field].',';
            }
        }
        $field_str=trim($field_str,',');
        return $field_str;
    }

}