<?php
/**----------------------------------------------------------------------
 * OpenCenter V3
 * Copyright 2014-2018 http://www.ocenter.cn All rights reserved.
 * ----------------------------------------------------------------------
 * Author: wdx(wdx@ourstu.com)
 * Date: 2018/10/15
 * Time: 9:42
 * ----------------------------------------------------------------------
 */

namespace app\index\controller;

use think\Controller;
use app\admin\controller\User;
use think\Db;

class Base extends Controller
{
    protected $userRule;
    protected $actionLimit;
    protected $userLog;
    protected $module;
    protected $controller;
    protected $action;
    protected $uid;
    protected $timeUnit;
    protected $user;
    protected $scoreRule;
    protected $scoreLog;
    protected $scoreType;

    public function initialize()
    {
        parent::initialize(); // TODO: Change the autogenerated stub
        //初始化属性
        $this->uid = get_uid();
        $this->userRule = model('admin/UserRule');
        $this->actionLimit = model('admin/ActionLimit');
        $this->userLog = model('admin/UserLog');
        $this->user = model('admin/User');
        $this->scoreRule = model('admin/ScoreRule');
        $this->scoreLog = model('admin/ScoreLog');
        $this->scoreType = model('admin/ScoreType');
        $this->module = strtolower($this->request->module());
        $this->controller = strtolower($this->request->controller());
        $this->action = strtolower($this->request->action());
        //配置信息
        $this->timeUnit = config('app.time_unit');

        //验证登录
        $this->checkLogin();
        //验证权限
        $this->checkAuth();
        //验证行为限制
        $this->checkActionLimit();
        //积分规则与积分日志
        $this->scoreRule();
    }

    /**
     * 登录验证
     * @return bool
     * @author:wdx(wdx@ourstu.com)
     */
    protected function checkLogin()
    {
        if (is_user_login()) {
            return true;
        } else {
            $this->error('请登录后再试', 'index/user/login');
        }
    }

    /**
     * 权限验证
     * @author:wdx(wdx@ourstu.com)
     */
    protected function checkAuth()
    {
        //TODO 确定模块机制
//        $rule = $this->userRule->where('module', $model)->where('name', $model . '/' . $controller . '/' . $action)->where('status', 1)->find();
        $rule = $this->userRule->where('name', $this->module . '/' . $this->controller . '/' . $this->action)->where('status', 1)->find();
        if ($rule) {
            $user = session('user_auth');
            $hasRule = $user['rules'];
            if (in_array($rule['id'], $hasRule)) {
                return true;
            } else {
                $this->error('越权访问');
            }
        } else {
            return true;
        }
    }

    /**
     * 行为限制验证
     * @author:wdx(wdx@ourstu.com)
     */
    protected function checkActionLimit()
    {
        $ruleId = $this->userRule->where('name', $this->module . '/' . $this->controller . '/' . $this->action)->where('status', 1)->value('id');
        $actionLimit = $this->actionLimit->where('rule_id', $ruleId)->find();
        if ($ruleId && $actionLimit) {
            $timeArea = $this->getTimeArea($actionLimit);
            $count = $this->userLog
                ->where('action', $this->module . '/' . $this->controller . '/' . $this->action)
                ->whereBetween('create_time', $timeArea['begin'], $timeArea['end'])
                ->order('create_time desc')
                ->count();
            if ($count >= $actionLimit['frequency']) {      //行为限制
                $punishes = explode(',', $actionLimit['punish_type']);
                foreach ($punishes as $punish) {
                    //执行惩罚
                    switch ($punish) {
                        case 1:
                            $this->warning($actionLimit);
                            break;
                        case 2:
                            $this->forceLogout();
                            break;
                        case 3:
                            $this->banAccount();
                            break;
                        case 4:
                            $this->banIP();
                            break;
                    }
                }
                unset($punish);
                if ($actionLimit['if_message']) {
                    //TODO 发送站内消息
                }
            } else {
                return true;
            }
        } else {
            return true;
        }
    }

    /**
     * 行为限制-禁用IP
     * @author:wdx(wdx@ourstu.com)
     */
    protected function banIP()
    {
        $data['uid'] = $this->uid;
        $data['ip'] = request()->ip(1);
        $data['create_time'] = time();
        model('admin/IPBlack')->insert($data);
    }

    /**
     * 行为限制-禁用账号
     * @author:wdx(wdx@ourstu.com)
     */
    protected function banAccount()
    {
        $this->user->where('id', $this->uid)->setField('status', 0);
    }

    /**
     * 行为限制-强制退出
     * @author:wdx(wdx@ourstu.com)
     */
    protected function forceLogout()
    {
        $user = new User();
        $user->logout();
    }

    /**
     * 行为限制-警告
     * @param $actionLimit
     * @author:wdx(wdx@ourstu.com)
     */
    protected function warning($actionLimit)
    {
        $time = $this->timeUnit;
        $errorMsg = '操作频繁，请' . $actionLimit['time_number'] . $time[$actionLimit['time_unit']] . '后再试';
        $this->error($errorMsg);
    }

    /**
     * 获取时间区间
     * @param array $actionLimit
     * @return array
     * @author:wdx(wdx@ourstu.com)
     */
    protected function getTimeArea($actionLimit = [])
    {
        $end = time();
        switch ($actionLimit['time_unit']) {
            case 1:
                $begin = $end - $actionLimit['time_number'];
                break;
            case 2:
                $begin = $end - $actionLimit['time_number'] * 60;
                break;
            case 3:
                $begin = $end - $actionLimit['time_number'] * 3600;
                break;
            case 4:
                $begin = $end - $actionLimit['time_number'] * 86400;
                break;
            case 5:
                $begin = $end - $actionLimit['time_number'] * 604800;
                break;
            case 6:
                $begin = $end - $actionLimit['time_number'] * 2592000;
                break;
            case 7:
                $begin = $end - $actionLimit['time_number'] * 31536000;
                break;
        }
        return [
            'begin' => $begin,
            'end' => $end
        ];
    }

    /**
     * 积分规则
     * @return bool
     * @author:wdx(wdx@ourstu.com)
     */
    private function scoreRule()
    {
        $rule = $this->userRule->where('name', $this->module . '/' . $this->controller . '/' . $this->action)->where('status', 1)->find();
        $scoreRule = $this->scoreRule->where('rule_id' ,$rule['id'])->find();
        if ($scoreRule) {
            //验证
            $rs = $this->scoreLog->checkScoreLog($scoreRule);
            if ($rs) {
                //积分变动
                $this->changeScore($scoreRule);
            } else {
                return true;
            }
        } else {
            return true;
        }
    }

    /**
     * 积分日志
     * @param array $scoreRule
     * @return bool
     * @author:wdx(wdx@ourstu.com)
     */
    private function changeScore($scoreRule = [])
    {
        $last = $this->scoreLog
            ->where('uid', $this->uid)
            ->where('score_type', $scoreRule['score_type'])
            ->order('id desc')
            ->find();
        $username = $this->user->where('id', $this->uid)->value('username');
        $scoreTitle = $this->scoreType->where('id', $scoreRule['score_type'])->value('title');
        $changeType = ($scoreRule['change_type'] == 1) ? '+' : '-';
        $remark = $username . $scoreRule['title'] . ',' . $scoreTitle . $changeType . $scoreRule['change_num'];
        if ($last) {
            $finallyScore = ($scoreRule['change_type'] == 1) ? ((float)$last['finally_value'] + (float)$scoreRule['change_num']) : ((float)$last['finally_value'] - (float)$scoreRule['change_num']);
        } else {
            if ($scoreRule['change_type'] == 2) {
                $this->error('积分不够扣了，请充值~');
            } else {
                $finallyScore = $scoreRule['change_num'];
            }
        }
        $data = [
            'uid' => $this->uid,
            'ip' => $this->request->ip(1),
            'score_type' => $scoreRule['score_type'],
            'value' => $changeType . $scoreRule['change_num'],
            'finally_value' => $finallyScore,
            'create_time' => time(),
            'module' => $this->module,
            'rule_id' => $scoreRule['rule_id'],
            'remark' => $remark
        ];
        Db::startTrans();
        try {
            Db::name('score_log')->insert($data);
            Db::name('user_count')->update(array('uid' => $this->uid, 'type' => $scoreRule['score_type'], 'num' => $finallyScore));
            // 提交事务
            Db::commit();
        } catch (\Exception $e) {
            // 回滚事务
            Db::rollback();
            $this->error($this->scoreLog->getError());
        }
        return true;
    }
}