<?php

declare(strict_types=1);

namespace app;

use think\App;
use think\exception\ValidateException;
use think\Validate;
use app\exceptions\ParamsValidateException;
use app\exceptions\NotLoginException;
use think\facade\Log;
use think\exception\ErrorException;

/**
 * 控制器基础类
 */
abstract class BaseController
{
    protected $user_id = null;
    protected $user_info = null;
    protected $check_actions = [];
    protected $className = 'ACTION_NOT_SET';
    /**
     * Request实例
     * @var \think\Request
     */
    protected $request;

    /**
     * 应用实例
     * @var \think\App
     */
    protected $app;

    /**
     * 是否批量验证
     * @var bool
     */
    protected $batchValidate = false;

    /**
     * 控制器中间件
     * @var array
     */
    protected $middleware = [];

    /**
     * 构造方法
     * @access public
     * @param  App  $app  应用对象
     */
    public function __construct(App $app)
    {
        $this->app = $app;
        $this->request = $this->app->request;

        // 参数校验
        $this->valid_params();
        // 控制器初始化
        $this->initialize();
    }

    // 初始化
    protected function initialize()
    {
      if(isset($this->ignore_log_params) && $this->ignore_log_params) return;
      $action_name = $this->request->action();
      $this->log_notice(['请求参数', $this->request->param(false)], '记录动作', 'action-log:' . $action_name);
    }

    /**
     * 验证数据
     * @access protected
     * @param  array        $data     数据
     * @param  string|array $validate 验证器名或者验证规则数组
     * @param  array        $message  提示信息
     * @param  bool         $batch    是否批量验证
     * @return array|string|true
     * @throws ValidateException
     */
    protected function validate(array $data, $validate, array $message = [], bool $batch = false)
    {
        if (is_array($validate)) {
            $v = new Validate();
            $v->rule($validate);
        } else {
            if (strpos($validate, '.')) {
                // 支持场景
                [$validate, $scene] = explode('.', $validate);
            }
            $class = false !== strpos($validate, '\\') ? $validate : $this->app->parseClass('validate', $validate);
            $v = new $class();
            if (!empty($scene)) {
                $v->scene($scene);
            }
        }

        $v->message($message);

        // 是否批量验证
        if ($batch || $this->batchValidate) {
            $v->batch(true);
        }
        $result = $v->failException(false)->check($data);
        if (!$result) {
            throw new ParamsValidateException($v->getError());
        }
        return true;
    }


    protected function valid_params()
    {

        $is_logined = false;
        $cookie_user_id = cookie('user_id');
        if (!empty($cookie_user_id)) {
            if ($cookie_user_id) {
                $cookie_user_id = \a_decode($cookie_user_id);
                if ($cookie_user_id) {
                    $cookie_user_id_sp = explode('|', $cookie_user_id);
                    //查看是否有这个用户
                    // c_debug($cookie_user_id_sp[0]);
                    // if($cookie_user_id_sp[0] == 3){
                    //     $cookie_user_id_sp[0] = 13;
                    // }
                    $db_user = D('user');
                    $user = $db_user->where(array('id' => $cookie_user_id_sp[0]))->find();
                    if (!empty($user)) {
                        $is_logined = true;
                        $this->user_id = $cookie_user_id_sp[0];
                        $this->user_info = $user;
                    }
                }
            }
        } else {
            // $is_logined = true;
            // $this->user_id = 1;
            // $this->user_info = [];
        }


        $request = $this->app->request;
        $action_name = $request->action();
        //没有列举出来的action也不校验登录
        //带#的action_name是不校验是否登录,但是要校验参数
        if (array_key_exists($action_name, $this->check_actions)) {
            //判断是否登录了
            if ($is_logined) {
                //logined
            } else {
                //not login
                throw new NotLoginException();
            }
        }
        //校验参数
        $checks = array();
        if (array_key_exists($action_name, $this->check_actions)) {
            $checks = $this->check_actions[$action_name];
        }
        if (array_key_exists('#' . $action_name, $this->check_actions)) {
            $checks = $this->check_actions['#' . $action_name];
        }
// echo json_encode($checks);
        if (!empty($checks)) {
            $valid_rule = [];
            $valid_msg = [];
            $valid_data = [];
            foreach ($checks as $k => $v) {
                if (\substr($k, 0, 1) === '#') {
                    $k = \substr($k, 1);
                    if (!isset($v[0])) {
                        $v = [];
                    }
                } else {
                    if (isset($v[0])) {
                        if (strpos($v[0], 'require') === false) {
                            $v[0] = 'require|' . $v[0];
                        }
                    } else {
                        $v[] = 'require';
                    }
                }
                if(empty($v)){
                  continue;
                }
                $valid_data[$k] = input($k . '');
                $valid_rule[$k] = $v[0];
                if (count($v) > 1) {
                    $msg = $v[1];
                    foreach ($msg as $k1 => $v1) {
                        $valid_msg[$k . '.' . $k1] = $k . $v1;
                    }
                }
            }
            $this->validate($valid_data, $valid_rule, $valid_msg);
        }
    }

    protected function log_notice($any, $msg = '', $tag = 'log_notice')
    {
        if ($any instanceof ErrorException || $any instanceof Exception) {
            $str = c_formate_exception($any);
        } else {
            $str = json_encode($any, JSON_UNESCAPED_UNICODE);
        }
        Log::write('[' . $this->className . ']' . '[' . $tag . ']' . '[' . $msg . ']' . '[' . $str . ']', 'NOTICE');
    }
    protected function log_warn($any, $msg = '', $tag = 'log_warn')
    {
        if ($any instanceof ErrorException || $any instanceof Exception) {
            $str = c_formate_exception($any);
        } else {
            $str = json_encode($any, JSON_UNESCAPED_UNICODE);
        }
        Log::write('[' . $this->className . ']' . '[' . $tag . ']' . '[' . $msg . ']' . '[' . json_encode($any, JSON_UNESCAPED_UNICODE) . ']', 'WARN');
    }
    protected function log_error($any, $msg = '', $tag = 'log_error')
    {
        if ($any instanceof ErrorException || $any instanceof Exception) {
            $str = c_formate_exception($any);
        } else {
            $str = json_encode($any, JSON_UNESCAPED_UNICODE);
        }
        Log::write('[' . $this->className . ']' . '[' . $tag . ']' . '[' . $msg . ']' . '[' . json_encode($any, JSON_UNESCAPED_UNICODE) . ']', 'ERROR');
    }
}
