package com.rf.psychological.scale.rest;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.rf.psychological.base.rest.BaseController;
import com.rf.psychological.dao.dto.InstitutionRecordingUsersDTO;
import com.rf.psychological.enums.UserRole;
import com.rf.psychological.file.excel.ExcelClass;
import com.rf.psychological.dao.model.*;
import com.rf.psychological.institution.service.InstitutionService;
import com.rf.psychological.opLog.annotation.OperationLogAnnotation;
import com.rf.psychological.plan.dao.model.TestPlanEntity;
import com.rf.psychological.plan.dao.model.TestPlanUserEntity;
import com.rf.psychological.plan.service.TestPlanContendService;
import com.rf.psychological.plan.service.TestPlanService;
import com.rf.psychological.plan.service.TestPlanUserService;
import com.rf.psychological.scale.dao.dto.SubjectEntityDto2;
import com.rf.psychological.scale.dao.model.*;
import com.rf.psychological.scale.service.*;
import com.rf.psychological.security.AesEncryptUtils;
import com.rf.psychological.security.SafetyProcess;
import com.rf.psychological.user.dao.model.UserEntity;
import com.rf.psychological.user.dao.model.UserFileEntity;
import com.rf.psychological.user.service.UserFileService;
import com.rf.psychological.user.service.UserService;
import com.rf.psychological.utils.*;
import com.rf.psychological.utils.DateUtil;
import com.rf.psychological.wxpay.model.PromotionInfo;
import com.rf.psychological.wxpay.service.PromotionInfoService;
import com.rf.psychological.wxpay.service.WxPayService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import jodd.util.StringUtil;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

import static com.rf.psychological.utils.FileUtil.html2pdf;

/**
 * @author zsf
 * {@code @description:接收测试结果计算结果--量表测试}
 * @date 2021/1/21 16:07
 */
@Slf4j
@RestController
@RequestMapping("/result")
@Api(tags = "web端量表测试结果计算")
public class WebScaleResultController extends BaseController {

    @Autowired
    private SubjectService subjectService;

    @Autowired
    private  UserRecordService userRecordService;

    @Autowired
    private UserService userService;

    @Autowired
    private ScaleService scaleService;

    @Autowired
    private AnswerService answerService;

    @Autowired
    private ScaleMarksService scaleMarksService;

    @Autowired
    private DimensionService dimensionService;

    @Autowired
    private ScaleConfigService scaleConfigService;

    @Autowired
    private ScaleScoringVersion scaleScoringVersion;

    @Autowired
    private  TestPlanContendService testPlanContendService;

    @Autowired
    private  TestPlanUserService testPlanUserService;

    @Autowired
    private TestPlanService testPlanService;

    @Autowired
    private WarnService warnService;

    @Autowired
    private DimensionOrgService dimensionOrgService;

    @Autowired
    private InstitutionService institutionService;

    @Autowired
    private ScaleDetailsService scaleDetailsService;

    @SafetyProcess
    @Transactional(rollbackFor = Exception.class)
    @OperationLogAnnotation("保存量表记录")
    @PostMapping("/{flag}")
    @ApiOperation(value = "flag:量表标志，jsonObject：测试结果")
    public Result completeTest(@RequestBody String json, @PathVariable String flag) throws Exception {

        String data = AesEncryptUtils.decrypt(JSONObject.parseObject(json).getString("data"));
        JSONObject jsonObject = JSONObject.parseObject(data);
        System.out.println("----------------result-------------------");
        System.out.println(jsonObject);
        String testPlanId = "0";
        UserEntity userEntity = this.userService.getOne(jsonObject.getString("userId"));
        if (userEntity == null) {
            return fail("用户不存在");
        }
        String userName = userEntity.getPetName();
        String userBirthday = userEntity.getBirthday();
        String userSex = userEntity.getGender();
        String institutionNo = userEntity.getInstitutionNo();
        //提交是校验测试次数是否达到上限
        if (institutionService.checkTestNum(institutionNo)){
            return fail(Constant.DEFAULT_VALUE_ZERO,"测试次数已达上限，请联系机构管理员");
        }
        if (userSex.equals("0")) {
            userSex = "男";
        } else if (userSex.equals("1")) {
            userSex = "女";
        }else {
            userSex = "性别";
        }
        String phone = userEntity.getPhone();
        if (jsonObject.containsKey("testPlanId") && StringUtils.isNotBlank(jsonObject.getString("testPlanId"))) {
            testPlanId = jsonObject.getString("testPlanId");
            TestPlanEntity testPlanEntity = this.testPlanService.findById(testPlanId);
            if (testPlanEntity == null) {
                return fail("测试计划不存在");
            }
            if (testPlanEntity.getStatus() == Constant.TEST_PLAN_STATUS_UNSTART)
                return fail("测试计划尚未开始");
            if (testPlanEntity.getStatus() < Constant.TEST_PLAN_STATUS_UNSTART)
                return fail("测试计划已结束");
            UserRecordEntity checkTestPlanId = userRecordService.findByPhoneAndTestPlanIdAndInstitution(institutionNo, phone, testPlanId, flag);
            if (checkTestPlanId != null) {
                return fail("", "该测试已完成");
            }
            //更新测试计划状态
            updateUserPlanStatus(testPlanId, institutionNo, phone, flag, userEntity.getId(), testPlanContendService, testPlanUserService);
        }

        String testTime = new SimpleDateFormat("yyyy年MM月dd日HH时mm分ss秒").format(new Date());
        if (jsonObject.containsKey("startTime")) {
            testTime = new SimpleDateFormat("yyyy年MM月dd日HH时mm分ss秒").format(jsonObject.getDate("startTime"));
        }
        String fileName = userName + Constant.SPLIT_CHAR + userBirthday + Constant.SPLIT_CHAR + userSex + Constant.SPLIT_CHAR + testTime;
        String testResult = "";
        JSONArray jsonArray = jsonObject.getJSONArray("scale_result");

        // 创建返回的json对象
        JSONObject resultJson = new JSONObject(true);
        //根据flag获取全部选项
        List<ScaleEntity> scaleEntities = this.scaleService.getScaleByFlag(flag);
        //根据flag获取全部答案
        List<AnswerEntity> answerEntities = this.answerService.getAnswerByFlag(flag);
        //根据flag获取全部评分规则
        List<ScaleMarksEntity> scaleMarksEntities = this.scaleMarksService.getScaleMarksByFlag(flag);
        //根据flag获取全部维度信息
        List<DimensionEntity> dimensionEntities = this.dimensionService.getDimensionByFlag(flag);
        //根据flag获取量表名称
        //List<SubjectEntity> subjectEntities = this.subjectService.getSubjectByFlag(flag);
        ScaleDetailsEntity detailsEntity = this.scaleDetailsService.getSubjectDetailsByFlag(flag);
        resultJson.put("scaleEntities", scaleEntities);
        resultJson.put("answerEntities", answerEntities);
        resultJson.put("scaleMarksEntities", scaleMarksEntities);
        resultJson.put("dimensionEntities", dimensionEntities);
        //性别，用于MMPI量表计算
        resultJson.put("gender", userEntity.getGender());
        //机构编号，用于预警信息判断
        resultJson.put("institutionNo", institutionNo);
        //用户id用于预警信息保存
        resultJson.put("userId", userEntity.getId());
        resultJson.put("dimensionOrgService", dimensionOrgService);
        //答题结果列表
        List<ScaleEntity> dataList = jsonArray.toJavaList(ScaleEntity.class);
        ScaleConfigEntity scaleConfigByFlag = scaleConfigService.findScaleConfigByFlag(flag);
        String className = (scaleConfigByFlag == null ? "com.rf.psychological.scale.resultBusiness.scaleResult.COMMONScale" : scaleConfigByFlag.getResultConfig());
        Class<?> cls; // 取得Class对象
        try {
            cls = Class.forName(className);
            Constructor<?> cons = cls.getConstructor(JSONArray.class, JSONObject.class);
//            Object obj = cons.newInstance(); // 为构造方法传递参数
            Object obj = cons.newInstance(jsonArray, resultJson);
            //cls.getDeclaredMethods();
            Method method = null;
            //通过配置文件获取量表计分规则使用的版本
            ObjectMapper objectMapper = new ObjectMapper();
            String str = objectMapper.writeValueAsString(scaleScoringVersion.getVersionmap());
            HashMap mapScale = JSON.parseObject(str, HashMap.class);
            Set<Map.Entry<String, String>> en = mapScale.entrySet();
            for (Map.Entry<String, String> entry : en) {
                String[] flags = entry.getValue().split(", ");
                for (String obtainFlag : flags) {
                    if (obtainFlag.equals(flag)) {
                        method = cls.getDeclaredMethod(entry.getKey());
                        break;
                    }
                }
            }
            if (method == null) {
                method = cls.getDeclaredMethod("scaleCalculate");
            }
            resultJson = (JSONObject) method.invoke(obj);
        } catch (ClassNotFoundException | NoSuchMethodException | IllegalAccessException | InstantiationException |
                 InvocationTargetException e) {
            e.printStackTrace();
        }
        JSONObject dimensionScore = null;

        if (resultJson.getJSONObject("resultJson").containsKey("dimensionScoreMap")) {
            dimensionScore = resultJson.getJSONObject("resultJson").getJSONObject("dimensionScoreMap");
            resultJson.getJSONObject("resultJson").remove("dimensionScoreMap");
        }
        resultJson.getJSONObject("resultJson").remove("scaleEntities");
        resultJson.getJSONObject("resultJson").remove("answerEntities");
        resultJson.getJSONObject("resultJson").remove("scaleMarksEntities");
        resultJson.getJSONObject("resultJson").remove("dimensionEntities");
        resultJson.getJSONObject("resultJson").remove("gender");

        resultJson.getJSONObject("resultJson").remove("institutionNo");
        resultJson.getJSONObject("resultJson").remove("userId");
        resultJson.getJSONObject("resultJson").remove("dimensionOrgService");

        if (resultJson.getJSONObject("resultJson").containsKey("resultJson") && resultJson.getJSONObject("resultJson").get("测试结果指导").equals("请认真按照实际情况如实回答")) {
            resultJson = resultJson.getJSONObject("resultJson");
            return success(resultJson, "完成");
        }
        fileName = fileName + "-" + detailsEntity.getScaleName() + ".xlsx";
        //导出文件
        ExcelUtil.createExcelFile(ScaleEntity.class, dataList, (List<Map<String, String>>) resultJson.get("resultMapList"), new ExcelClass().contentExcel(), fileName, detailsEntity.getScaleName());

        //计算结果
        JSONArray dbJsonList = new JSONArray();
        JSONObject dbJson = new JSONObject(true);
        boolean versionFlag = false;
        Map<String, Object> newResultJson = null;
        if (!resultJson.containsKey("newResultJson")) {
            dbJson.put("version", 1.0);
            dbJson.put("newTableContext", "");
        } else {
            newResultJson = (Map<String, Object>) resultJson.get("newResultJson");
            dbJson.put("version", 2.0);
            dbJson.put("newTableContext", newResultJson);
            versionFlag = true;
        }

        resultJson = resultJson.getJSONObject("resultJson");
        List<WarnEntity> warnEntityList = new ArrayList<WarnEntity>();
        if(resultJson.containsKey("warnEntityList")) {
            warnEntityList = resultJson.getJSONArray("warnEntityList").toJavaList(WarnEntity.class);
            resultJson.remove("warnEntityList");
        }
        // 获取JSON第一层所有的key
        Set<String> keys = resultJson.keySet();

        //列名
        List colNames = new ArrayList();
        colNames.add("项目");
        colNames.add("内容");
        dbJson.put("colNames", colNames);
        JSONArray tableContext = new JSONArray();

        // 获取第一层每个key对应的值 的类型
        for (String key : keys) {
            //列值
            List colValue = new ArrayList();
            colValue.add(resultJson.get(key));
            JSONObject row = new JSONObject();
            row.put("name", key);
            row.put("value", colValue);
            tableContext.add(row);
        }

        dbJson.put("tableContext", tableContext);

        dbJsonList.add(dbJson);

        //测试记录
        int i = 1;
        // 获取第一层每个key对应的值 的类型
        for (String key : keys) {
            if (i == keys.size()) {
                testResult += key + ":" + resultJson.get(key);
            } else {
                testResult += key + ":" + resultJson.get(key) + ";";
            }
            i++;
        }
        String filePath;
        filePath = "./心理检测/检测结果/" + new SimpleDateFormat("yyyy-MM-dd").format(new Date()) + "/" + detailsEntity.getScaleName() + "/" + fileName;
        UserRecordEntity userRecordEntity = testRecord(flag, phone, institutionNo, testTime, filePath, JSON.toJSONString(dbJsonList, SerializerFeature.DisableCircularReferenceDetect), detailsEntity.getScaleName(), JSON.toJSONString(dataList, SerializerFeature.DisableCircularReferenceDetect), testResult, testPlanId);
        //预警信息处理
        if (dimensionScore != null && dimensionScore.size() > 0) {
            if (dimensionEntities != null && dimensionEntities.size() > 0) {
                for (int y = 0; y < dimensionEntities.size(); y++) {
                    //计算维度逻辑是否需要预警
                    DimensionOrgEntity byInstitutionNoAndDimensionId = dimensionOrgService.findByInstitutionNoAndDimensionId(institutionNo, dimensionEntities.get(y).getId());
                    if (byInstitutionNoAndDimensionId != null) {

                        switch (byInstitutionNoAndDimensionId.getLogic()) {
                            case "lt":
                                if (dimensionScore.getDouble(dimensionEntities.get(y).getId()) < Double.parseDouble(byInstitutionNoAndDimensionId.getThreshold())) {
                                    //添加预警信息
                                    warnEntityList.add(createWarnEntry(dimensionEntities.get(y).getFlag(), institutionNo, jsonObject.getString("userId"), dimensionEntities.get(y).getId(), dimensionScore.getDouble(dimensionEntities.get(y).getId())));
                                }
                                break;
                            case "le":
                                if (dimensionScore.getDouble(dimensionEntities.get(y).getId()) <= Double.parseDouble(byInstitutionNoAndDimensionId.getThreshold())) {
                                    //添加预警信息
                                    warnEntityList.add(createWarnEntry(dimensionEntities.get(y).getFlag(), institutionNo, jsonObject.getString("userId"), dimensionEntities.get(y).getId(), dimensionScore.getDouble(dimensionEntities.get(y).getId())));
                                }
                                break;
                            case "eq":
                                if (dimensionScore.getDouble(dimensionEntities.get(y).getId()) == Double.parseDouble(byInstitutionNoAndDimensionId.getThreshold())) {
                                    //添加预警信息
                                    warnEntityList.add(createWarnEntry(dimensionEntities.get(y).getFlag(), institutionNo, jsonObject.getString("userId"), dimensionEntities.get(y).getId(), dimensionScore.getDouble(dimensionEntities.get(y).getId())));
                                }
                                break;
                            case "ne":
                                if (dimensionScore.getDouble(dimensionEntities.get(y).getId()) != Double.parseDouble(byInstitutionNoAndDimensionId.getThreshold())) {
                                    //添加预警信息
                                    warnEntityList.add(createWarnEntry(dimensionEntities.get(y).getFlag(), institutionNo, jsonObject.getString("userId"), dimensionEntities.get(y).getId(), dimensionScore.getDouble(dimensionEntities.get(y).getId())));
                                }
                                break;
                            case "ge":
                                if (dimensionScore.getDouble(dimensionEntities.get(y).getId()) >= Double.parseDouble(byInstitutionNoAndDimensionId.getThreshold())) {
                                    //添加预警信息
                                    warnEntityList.add(createWarnEntry(dimensionEntities.get(y).getFlag(), institutionNo, jsonObject.getString("userId"), dimensionEntities.get(y).getId(), dimensionScore.getDouble(dimensionEntities.get(y).getId())));
                                }
                                break;
                            case "gt":
                                if (dimensionScore.getDouble(dimensionEntities.get(y).getId()) > Double.parseDouble(byInstitutionNoAndDimensionId.getThreshold())) {
                                    //添加预警信息
                                    warnEntityList.add(createWarnEntry(dimensionEntities.get(y).getFlag(), institutionNo, jsonObject.getString("userId"), dimensionEntities.get(y).getId(), dimensionScore.getDouble(dimensionEntities.get(y).getId())));
                                }
                                break;
                        }

                    }
                }
//            resultJson.put("warnEntityList",warnEntityList);
            }
            if (warnEntityList.size() > 0) {
                warnEntityList.forEach(item -> {
                    item.setResultId(userRecordEntity.getId());
                    item.setCreateTime(userRecordEntity.getTestDate());
                    DimensionOrgEntity dimensionOrgEntity = this.dimensionOrgService.findByInstitutionNoAndDimensionId(institutionNo,item.getDimensionId());
                    item.setThreshold(dimensionOrgEntity.getThreshold());
                    item.setLogic(dimensionOrgEntity.getLogic());
                    this.warnService.save(item);
                });
            }
        }
        //获取下测试记录
        userRecordService.getUserRecordById(userRecordEntity.getId());
        return success(userRecordEntity.getId(), "完成");

    }


    private UserRecordEntity testRecord(String flag, String phone, String institutionNo, String testTime, String fileName, String testResult, String name, String dataList, String testResults, String testPlanId) {
        //根据flag记录测试数
        this.subjectService.addTestNum(flag);
        //添加用户测试记录
        UserRecordEntity userRecordEntity = new UserRecordEntity();
        userRecordEntity.setFlag(flag);
        userRecordEntity.setPhone(phone);
        userRecordEntity.setInstitutionNo(institutionNo);
        userRecordEntity.setTestDate(testTime);
        userRecordEntity.setTestResult(testResult);
        userRecordEntity.setType("0");
        userRecordEntity.setFileName(fileName);
        userRecordEntity.setName(name);
        if (!flag.equals("20230327160727")) {
            userRecordEntity.setTestRecord(dataList);
        }
        userRecordEntity.setTestResults(testResults);
        if (testPlanId == null || testPlanId.equals("")) {
            userRecordEntity.setTestPlanId("0");
        } else {
            userRecordEntity.setTestPlanId(testPlanId);
        }
        this.userRecordService.save(userRecordEntity);
        return userRecordEntity;
    }

    public static void updateUserPlanStatus(String testPlanId, String institutionNo, String phone, String flag, String uId,TestPlanContendService testPlanContendService,TestPlanUserService testPlanUserService){
        if (!"0".equals(testPlanId) && !StringUtils.isEmpty(testPlanId)) {
            //检查测试内容里的任务是否完成

            //测试计划任务总数
            int contentCount = testPlanContendService.countContent(testPlanId);
            //用户已完成测试总数
            int completedCount = testPlanContendService.getUserDoTestPlanContendNum(institutionNo,phone,testPlanId)+1;
            if(contentCount == completedCount){
                //更新用户状态为完成状态
                Optional<TestPlanUserEntity> testPlanUserByTestIdAndUserId = testPlanUserService.findTestPlanUserByTestIdAndUserId(testPlanId, uId);
                TestPlanUserEntity entity = testPlanUserByTestIdAndUserId.orElse(null);
                if(entity != null){
                    entity.setIsComplete(Constant.USER_PLAN_STATUS_COMPLETED);
                    testPlanUserService.save(entity);
                }
            }
        }
    }

    private WarnEntity createWarnEntry(String flag, String institutionNo, String userId, String id, double score) {
        WarnEntity warn = new WarnEntity();

        warn.setFlag(flag);
        warn.setInstitutionNo(institutionNo);
        warn.setUserId(userId);
        warn.setDimensionId(id);
        warn.setScore(String.valueOf(score));
        return warn;
    }

}
