<?php

declare(strict_types=1);

namespace app\control\controller\exam;

use app\BaseController;
use app\common\model\exam\Question;
use app\control\model\User;
use app\Request;
use mb\helper\Collection;
use think\response\Json;
use app\common\model\exam\Paper;
use app\common\model\exam\paper\Record;

/**
 * Class Exam
 * @package app\control\controller\exam
 */
class Exam extends BaseController
{
    /**
     * @param Request $request
     * @return Json
     * @api {post} /exam/exam/search 个人事务--试卷列表
     * @apiGroup Exam-exam
     * @apiName sort1
     * @apiVersion 1.0.0
     *
     * @apiDescription 试卷列表
     *
     * @apiParam {String} type 考试类型<br>competition -- 竞赛级别<br>promote -- 提升级<br>beginner -- 入门级<br>simulate -- 模拟考
     * @apiParam {Number} [current]  页码
     * @apiParam {Number} [pageSize]  页数
     *
     * @apiSuccess {Number} code    状态码，0：请求成功
     * @apiSuccess {String} message   提示信息
     * @apiSuccess {Object} dataSet    返回数据
     *
     * @apiSuccessExample {json} Success-Response:
     * {"code":0,"message":"","dataSet":[], "total" : 0}
     *
     * @apiErrorExample {json} Error-Response:
     * {"code":5001,"message":"接口异常"}
     */
    public function search(Request $request)
    {
        $input = $request->post();
        $pageIndex = empty($input['current']) ? 1 : intval($input['current']);
        $pageSize = empty($input['pageSize']) ? 10 : intval($input['pageSize']);
        $total = 0;
        $filter = [];
        $filter['type'] = empty($input['type']) ? '' : $input['type'];
        $papers = Paper::userWatch();
        if (empty($papers)) {
            return payload(['dataSet' => [], 'total' => 0]);
        }
        $filter['ids'] = implode(',', $papers);
        $filter['timeStart'] = date('Y-m-d H:i:s', time());
        $filter['timeEnd'] = date('Y-m-d H:i:s', time());
        $dataSet = Paper::search($filter, $pageIndex, $pageSize, $total);
        $dataSet = array_map(
            function ($val) {
                $val['questionType'] = unserialize($val['questionType']);
                $totalNum = 0;
                foreach ($val['questionType'] as $item) {
                    $totalNum += $item['questionNum'];
                }
                unset($val['questionType']);
                $val['totalQuestionNum'] = $totalNum;
                return $val;
            },
            $dataSet
        );
        return payload(['dataSet' => $dataSet, 'total' => $total]);
    }

    /**
     * @param Request $request
     * @return Json
     * @throws \think\Exception
     * @api {post} /exam/exam/create 个人事务--开始考试
     * @apiGroup Exam-exam
     * @apiName sort2
     * @apiVersion 1.0.0
     *
     * @apiDescription 开始考试
     *
     * @apiParam {Number} id  试卷id
     *
     * @apiSuccess {Number} code    状态码，0：请求成功
     * @apiSuccess {String} message   提示信息
     * @apiSuccess {Object} dataSet    返回数据
     *
     * @apiSuccessExample {json} Success-Response:
     * {"code":0,"message":"","dataSet":[], "total" : 0}
     *
     * @apiErrorExample {json} Error-Response:
     * {"code":5001,"message":"接口异常"}
     */
    public function create(Request $request)
    {
        $user = User::fetchCurrent();
//        $user['id'] = mt_rand(1000, 10000);
        $input = $request->param();
//        $input['id'] = 1;
        if (empty($input['id'])) {
            return payload(error(-1, '参数不完整'));
        }
        $record = Record::fetchRec(['paper' => intval($input['id']), 'user' => $user['id']]);
        $paper = Paper::fetch(intval($input['id']));
        if ((!empty($record) && ($record['status'] == 'end')) && ($paper['multiple'] != 1)) {
            return payload(error(-1, '该试卷不允许多次考试'));
        }
        if (!empty($record) && ($record['status'] == 'start')) {
            $recData['time_beat'] = time();
            Record::update(['id' => $record['id']], $recData);
            return payload([]);
        }
        $data = [
            'paper_id' => intval($input['id']),
            'user_id' => $user['id'],
            'status' => 'start',
            'total_points' => $paper['total_points'],
            'score' => 0,
            'mark_id' => 0,
            'exam_time' => 0,
            'mark_status' => 'await',
            'result' => '',
            'time_beat' => time(),
            'time_end' => 0
        ];
        if ($paper['way'] == 'question') {
            $question = Paper::make(unserialize($paper['strategies']));
            if (is_error($question)) {
                return payload(error(-1, '题库发生变更，请联系管理员修改试卷内容'));
            }
            $data['question'] = serialize($question);
        } else {
            $question = unserialize($paper['question']);
            $check = Paper::checkQuestionExist($question);
            if (is_error($check)) {
                return payload(error(-1, '题库发生变更，请联系管理员修改试卷内容'));
            }
            $data['question'] = '';
        }
        $res = Record::add($data);
        if ($res) {
            return payload([]);
        }
        return payload(error(-3, '系统故障，请重试'));
    }

    /**
     * @param Request $request
     * @return Json
     * @throws \think\Exception
     * @api {post} /exam/exam/detail 个人事务--试卷详情
     * @apiGroup Exam-exam
     * @apiName sort3
     * @apiVersion 1.0.0
     *
     * @apiDescription 试卷详情
     *
     * @apiParam {Number} id  试卷id
     *
     * @apiSuccess {Number} code    状态码，0：请求成功
     * @apiSuccess {String} message   提示信息
     * @apiSuccess {Object} dataSet    返回数据
     *
     * @apiSuccessExample {json} Success-Response:
     * {"code":0,"message":"","dataSet":[], "total" : 0}
     *
     * @apiErrorExample {json} Error-Response:
     * {"code":5001,"message":"接口异常"}
     */
    public function detail(Request $request)
    {
        $user = User::fetchCurrent();
//        $user['id'] = 70;
        $input = $request->post();
        if (empty($input['id'])) {
            return payload(error(-1, '参数不完整'));
        }
        $paper = Paper::fetch(intval($input['id']));
        $record = Record::fetchRec(['paper' => intval($input['id']), 'user' => $user['id']]);
        if (!empty($record) && ($paper['way'] == 'question')) {
            $dataSet = Paper::preview(intval($input['id']), unserialize($record['question']));
        } else {
            $dataSet = Paper::preview(intval($input['id']));
        }
        if (is_error($dataSet)) {
            return payload(error(-11, $dataSet->getMessage()));
        }
        if (empty($record)) {
            $dataSet['remainTime'] = Paper::secToTime($paper['time']);
        } else {
            $dataSet['remainTime'] = Paper::secToTime(($paper['time'] * 60) - $record['exam_time']);
        }
        $answers = [];
        $question = [];
        foreach ($dataSet['question'] as $v) {
            $question = array_merge($question, $v);
        }
        $questionArr = Question::search(['ids' => $question], 0);
        $questionArr = Collection::key($questionArr, 'id');
        foreach ($dataSet['question'] as &$val) {
            foreach ($val as &$v) {
                if (isset($questionArr[$v])) {
                    $v = $questionArr[$v];
                    $v = Collection::elements(['id', 'type', 'name', 'options', 'knowledge', 'answer'], $v);
                    if ($v['type'] == 'handel') {
                        $v['handel'] = $v['answer'];
                    } else {
                        $v['handel'] = '';
                    }
                    if ($v['type'] == 'typing') {
                        $v['handel'] = $v['answer'];
                    }
                    unset($v['answer'], $v['type']);
                } else {
                    continue;
                }
            }
        }
        if (empty($record['result'])) {
            foreach ($dataSet['question'] as $k => $item) {
                $type = [];
                foreach ($item as $tmp) {
                    $type[$tmp['id']] = [
                        'id' => $tmp['id'],
                        'answer' => '',
                        'score' => 0,
                        'knowledge' => $tmp['knowledge'],
                        'handel' => $tmp['handel']
                    ];
                }
                $answers[$k] = $type;
            }
        } else {
            $answers = unserialize($record['result']);
        }
        $dataSet['result'] = $answers;
        $dataSet['consequence'] = $paper['result'];
        $dataSet['save'] *= 60;
        unset($questionArr);
        return payload(['dataSet' => $dataSet]);
    }

    /**
     * @param Request $request
     * @return Json
     * @throws \think\Exception
     * @api {post} /exam/exam/save 个人事务--保存试卷
     * @apiGroup Exam-exam
     * @apiName sort4
     * @apiVersion 1.0.0
     *
     * @apiDescription 保存试卷
     *
     * @apiParam {Number} id  试卷id
     * @apiParam {String} type writing -- 考试中 end -- 考试完成
     * @apiParam {String[]} result 答案
     *
     * @apiSuccess {Number} code    状态码，0：请求成功
     * @apiSuccess {String} message   提示信息
     * @apiSuccess {Object} dataSet    返回数据
     *
     * @apiSuccessExample {json} Success-Response:
     * {"code":0,"message":"","dataSet":[], "total" : 0}
     *
     * @apiErrorExample {json} Error-Response:
     * {"code":5001,"message":"接口异常"}
     */
    public function save(Request $request)
    {
        $input = $request->post();
        if (empty($input['type']) || empty($input['result']) || empty($input['id'])) {
            return payload(error(-1, '参数不完整'));
        }
        $user = User::fetchCurrent();
//        dump($input['result']);
//        die;
        $paper = Paper::fetch(intval($input['id']));
        $record = Record::fetchRec(['paper' => $input['id'], 'user' => $user['id']]);
        if ($record['status'] == 'end') {
            return payload(error(-99, '考试已结束'));
        }
        $data = [
            'result' => $input['result'],
            'time_beat' => time(),
        ];
        $examTime = (time() - $record['time_beat']) + $record['exam_time'];
        $remainTime = ($paper['time'] * 60) - $examTime;
        if (($remainTime <= 0) || ($input['type'] == 'end')) {
            $data['status'] = 'end';
            $data['exam_time'] = $paper['time'] * 60;
            $data['time_end'] = time();
            $fillIn = $paper['completion'] ? true : false;
            $questionType = unserialize($paper['question_type']);
            $questionType = array_map(function ($val) {
                $val = $val['point'];
                return $val;
            }, $questionType);
            $grade = Record::grade($data['result'], $questionType, $fillIn);
            $data['result'] = $grade['result'];
            $data['score'] = $grade['score'];
            $questionType = unserialize($paper['question_type']);
            $type = array_keys($questionType);
            $markType = Question::MARKTYPE;
            if ($fillIn) {
                unset($markType[array_search('fillIn', $markType)]);
            }
            $useMark = [];
            foreach ($type as $value) {
                if (in_array($value, $markType)) {
                    array_push($useMark, $value);
                }
            }
            if (empty($useMark)) {
                $data['mark_status'] = 'end';
            }
        } else {
            $data['exam_time'] = $examTime;
        }
        $data['result'] = serialize($data['result']);
        $res = Record::update(['id' => $record['id']], $data);
        if (!$res) {
            return payload(error(-1, '保存失败'));
        }
        if (isset($data['status']) && ($data['status'] == 'end') && ($input['type'] != 'end')) {
            return payload(error(-10, '考试结束'));
        }
        return payload(['id' => $record['id']]);
    }
}