package cn.com.qmth.stmms.ms.admin.api;

import cn.com.qmth.stmms.ms.commons.utils.SqlUtil;
import cn.com.qmth.stmms.ms.core.domain.Level;
import cn.com.qmth.stmms.ms.core.domain.MarkLogOperType;
import cn.com.qmth.stmms.ms.core.domain.MarkStage;
import cn.com.qmth.stmms.ms.core.domain.task.MarkTask;
import cn.com.qmth.stmms.ms.core.repository.LevelRepo;
import cn.com.qmth.stmms.ms.core.repository.MarkTaskRepo;
import cn.com.qmth.stmms.ms.core.vo.Subject;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import javax.persistence.criteria.Predicate;
import java.math.BigDecimal;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @Description: 质量分析报表controller
 * @Param:
 * @return:
 * @Author: wangliang
 * @Date: 2019/11/8
 */
//@Api(tags = "质量分析报表接口controller")
@RestController
@RequestMapping("api/quality")
public class QualityAnalyseController {

    @Autowired
    private LevelRepo levelRepo;

    @Autowired
    private SqlUtil sqlUtil;

    @Autowired
    MarkTaskRepo markTaskRepo;

    /**
     * 档位占比报表
     *
     * @param workId
     * @param subject
     * @param areaCode
     * @param startTime
     * @param endTime
     */
//    @ApiOperation(value = "档位占比报表接口")
    @RequestMapping(value = "levelsPropReport", method = RequestMethod.GET)
    public Object levelsPropReport(
//            @ApiParam(value = "workId", required = true)
            @RequestParam Long workId,
//            @ApiParam(value = "科目", required = false)
            @RequestParam(required = false) Subject subject,
//            @ApiParam(value = "考点", required = false)
            @RequestParam(required = false) String areaCode,
//            @ApiParam(value = "开始时间", required = false)
            @RequestParam(required = false) String startTime,
//            @ApiParam(value = "结束时间", required = false)
            @RequestParam(required = false) String endTime) {
        List fList = new ArrayList();
        List<Level> levels = levelRepo.findByWorkId(workId);
        levels.forEach(l -> {
            StringBuffer sql = new StringBuffer();
            sql.append("  SELECT                                                        ");
            sql.append("      mu.id markerId,                                           ");
            sql.append("      mu.name markerName,                                       ");
            sql.append("      SUM(IF(mt.result = '" + l.getCode() + "', 1, 0)) levelCount,  ");
            sql.append("      COUNT(1) total                                            ");
            sql.append("  FROM                                                          ");
            sql.append("      mark_user mu                                              ");
            sql.append("          LEFT JOIN                                             ");
            sql.append("      (SELECT                                                   ");
            sql.append("          m.*                                                     ");
            sql.append("      FROM                                                      ");
            sql.append("          mark_task m                                           ");
            sql.append("          left join paper p on m.paper_id = p.id                ");
            sql.append("      WHERE                                                     ");
            sql.append("          stage = " + MarkStage.LEVEL.ordinal() + "             ");
            if (!Objects.isNull(areaCode)) {
                sql.append(" and p.area_code = " + areaCode);
            }
            if (!Objects.isNull(startTime)) {
                sql.append(" and m.updated_on >= '" + startTime + "'");
            }
            if (!Objects.isNull(endTime)) {
                sql.append(" and m.updated_on <= '" + endTime + "'");
            }
            sql.append("          ) mt ON mu.work_id = mt.work_id                       ");
            sql.append("          AND mu.subject = mt.subject                           ");
            sql.append("          AND mu.id = mt.marker_id                              ");
            sql.append("  WHERE                                                         ");
            sql.append("      mu.work_id = " + workId);
            if (Objects.nonNull(subject)) {
                sql.append(" AND mu.subject = '" + subject.toString() + "' ");
            }
            sql.append("          AND mu.role = 'MARKER'                                ");
            sql.append("  GROUP BY mu.id , mu.name                                      ");
            sql.append("  ORDER BY mu.id                                                ");

            List list = sqlUtil.execSqlForMap(sql.toString());
            Map map = new HashMap();
            List<Map> data = new ArrayList();
            map.put("name", l.getCode());
            for (Object o : list) {
                Map m = (Map) o;
                //该档任务数
                BigDecimal levelCount = BigDecimal.valueOf(Long.parseLong(m.get("levelCount").toString()));
                //总任务数
                BigDecimal total = BigDecimal.valueOf(Long.parseLong(m.get("total").toString()));
                //占比
                BigDecimal propBig = BigDecimal.ZERO.compareTo(total) == 0 ? BigDecimal.ZERO : levelCount.divide(total, 4, BigDecimal.ROUND_HALF_UP);
                double prop = propBig.doubleValue();
                Map temp = new HashMap();
                temp.put("markerId", m.get("markerId"));
                temp.put("markerName", m.get("markerName"));
                temp.put("prop", prop * 100);
                data.add(temp);
            }
            //排序
            Collections.sort(data, Comparator.comparing(o -> o.get("markerId").toString()));
            map.put("data", data);
            fList.add(map);
        });
        return fList;
    }

    /**
     * 打回次数报表
     *
     * @param workId
     * @param subject
     * @param areaCode
     * @param startTime
     * @param endTime
     * @return
     */
//    @ApiOperation(value = "打回次数报表接口")
    @RequestMapping(value = "callbackReport", method = RequestMethod.GET)
    public List callbackReport(
//            @ApiParam(value = "workId", required = true)
            @RequestParam Long workId,
//            @ApiParam(value = "科目", required = false)
            @RequestParam(required = false) Subject subject,
//            @ApiParam(value = "考点", required = false)
            @RequestParam(required = false) String areaCode,
//            @ApiParam(value = "开始时间", required = false)
            @RequestParam(required = false) String startTime,
//            @ApiParam(value = "结束时间", required = false)
            @RequestParam(required = false) String endTime) {
        List list = new ArrayList();
        Specification<MarkTask> specification = (root, query, builder) -> {
            List<Predicate> predicates = new ArrayList<>();
            predicates.add(builder.equal(root.get("workId"), workId));
            if (Objects.nonNull(subject)) {
                predicates.add(builder.equal(root.get("subject"), subject));
            }
            if (Objects.nonNull(areaCode)) {
                predicates.add(builder.equal(root.get("paper").get("areaCode"), areaCode));
            }
            return builder.and(predicates.toArray(new Predicate[predicates.size()]));
        };
        List<MarkTask> markTasks = markTaskRepo.findAll(specification);
        if (Objects.nonNull(markTasks) && markTasks.size() > 0) {
            Map<Long, MarkTask> markerMap = markTasks.stream().collect(Collectors.toMap(MarkTask::getMarkerId, Function.identity(), (dto1, dto2) -> dto1));
            List<Long> markerIdList = markerMap.values().stream().map(i -> i.getMarkerId()).collect(Collectors.toList());
            Object o = StringUtils.join(markerIdList.toArray(), ",");
            String sql = new StringBuffer("select t.create_user_name as userName, count(t.create_user_id) as sumCount,t.create_user_id as userId from mark_log t where t.oper_type BETWEEN ").append(MarkLogOperType.SYSTEM_CALLBACK_LEVEl.getId()).append(" and ").append(MarkLogOperType.HANDLE_LEVEl.getId()).append(" and t.create_user_id in (").append(o).append(")").toString();
            if (Objects.nonNull(startTime)) {
                sql = sqlUtil.sqlConditionAnd(sql, new String[]{"t.create_time"}, new String[]{startTime}, new String[]{">="});
            }
            if (Objects.nonNull(endTime)) {
                sql = sqlUtil.sqlConditionAnd(sql, new String[]{"t.create_time"}, new String[]{endTime}, new String[]{"<="});
            }
            sql = sqlUtil.sqlGroupBy(sql, "t.create_user_id");
            list = sqlUtil.execSqlForMap(sql);
            list = distinctCommon(list, markerIdList, markerMap);
        }
        return list;
    }

    /**
     * 差值和报表
     *
     * @param workId
     * @param subject
     * @param areaCode
     * @param startTime
     * @param endTime
     */
//    @ApiOperation(value = "差值和报表接口")
    @RequestMapping(value = "distanceReport", method = RequestMethod.GET)
    public List distanceReport(
//            @ApiParam(value = "workId", required = true)
            @RequestParam Long workId,
//            @ApiParam(value = "科目", required = true)
            @RequestParam(required = false) Subject subject,
//            @ApiParam(value = "考点", required = true)
            @RequestParam(required = false) String areaCode,
//            @ApiParam(value = "开始时间", required = false)
            @RequestParam(required = false) String startTime,
//            @ApiParam(value = "结束时间", required = false)
            @RequestParam(required = false) String endTime) {
        List list = new ArrayList();
        Specification<MarkTask> specification = (root, query, builder) -> {
            List<Predicate> predicates = new ArrayList<>();
            predicates.add(builder.equal(root.get("workId"), workId));
            if (Objects.nonNull(subject)) {
                predicates.add(builder.equal(root.get("subject"), subject));
            }
            if (Objects.nonNull(areaCode)) {
                predicates.add(builder.equal(root.get("paper").get("areaCode"), areaCode));
            }
            return builder.and(predicates.toArray(new Predicate[predicates.size()]));
        };
        List<MarkTask> markTasks = markTaskRepo.findAll(specification);
        if (Objects.nonNull(markTasks) && markTasks.size() > 0) {
            Map<Long, MarkTask> markerMap = markTasks.stream().collect(Collectors.toMap(MarkTask::getMarkerId, Function.identity(), (dto1, dto2) -> dto1));
            List<Long> markerIdList = markerMap.values().stream().map(i -> i.getMarkerId()).collect(Collectors.toList());
            Object o = StringUtils.join(markerIdList.toArray(), ",");
            String sql = new StringBuffer("select t.create_user_name as userName, sum(t.oper_data_after) as sumCount,t.create_user_id as userId from mark_log t where t.oper_type = ").append(MarkLogOperType.LEVEl_DIFFERENCE.getId()).append(" and t.create_user_id in (").append(o).append(")").toString();
            if (Objects.nonNull(startTime)) {
                sql = sqlUtil.sqlConditionAnd(sql, new String[]{"t.create_time"}, new String[]{startTime}, new String[]{">="});
            }
            if (Objects.nonNull(endTime)) {
                sql = sqlUtil.sqlConditionAnd(sql, new String[]{"t.create_time"}, new String[]{endTime}, new String[]{"<="});
            }
            sql = sqlUtil.sqlGroupBy(sql, "t.create_user_id");
            list = sqlUtil.execSqlForMap(sql);
            list = distinctCommon(list, markerIdList, markerMap);
        }
        return list;
    }

    /**
     * 累计误差报表
     *
     * @param workId
     * @param subject
     * @param areaCode
     * @param startTime
     * @param endTime
     */
    @RequestMapping(value = "deviationReport", method = RequestMethod.GET)
    public List cumulativeReport(
            @RequestParam Long workId,
            @RequestParam(required = false) Subject subject,
            @RequestParam(required = false) String areaCode,
            @RequestParam(required = false) String startTime,
            @RequestParam(required = false) String endTime) {
        List list = new ArrayList();
        Specification<MarkTask> specification = (root, query, builder) -> {
            List<Predicate> predicates = new ArrayList<>();
            predicates.add(builder.equal(root.get("workId"), workId));
            if (Objects.nonNull(subject)) {
                predicates.add(builder.equal(root.get("subject"), subject));
            }
            if (Objects.nonNull(areaCode)) {
                predicates.add(builder.equal(root.get("paper").get("areaCode"), areaCode));
            }
            return builder.and(predicates.toArray(new Predicate[predicates.size()]));
        };
        List<MarkTask> markTasks = markTaskRepo.findAll(specification);
        if (Objects.nonNull(markTasks) && markTasks.size() > 0) {
            Map<Long, MarkTask> markerMap = markTasks.stream().collect(Collectors.toMap(MarkTask::getMarkerId, Function.identity(), (dto1, dto2) -> dto1));
            List<Long> markerIdList = markerMap.values().stream().map(i -> i.getMarkerId()).collect(Collectors.toList());
            Object o = StringUtils.join(markerIdList.toArray(), ",");
            String sql = new StringBuffer("select t.create_user_name as userName, sum(t.oper_data_after) as sumCount,t.create_user_id as userId from mark_log t where t.oper_type = ").append(MarkLogOperType.LEVEl_DEVIATION.getId()).append(" and t.create_user_id in (").append(o).append(")").toString();
            if (Objects.nonNull(startTime)) {
                sql = sqlUtil.sqlConditionAnd(sql, new String[]{"t.create_time"}, new String[]{startTime}, new String[]{">="});
            }
            if (Objects.nonNull(endTime)) {
                sql = sqlUtil.sqlConditionAnd(sql, new String[]{"t.create_time"}, new String[]{endTime}, new String[]{"<="});
            }
            sql = sqlUtil.sqlGroupBy(sql, "t.create_user_id");
            list = sqlUtil.execSqlForMap(sql);
            list = distinctCommon(list, markerIdList, markerMap);
        }
        return list;
    }

    /**
     * 求差值公用
     *
     * @param list
     * @param markerIdList
     * @param markerMap
     * @return
     */
    public List distinctCommon(List list, List<Long> markerIdList, Map<Long, MarkTask> markerMap) {
        if (Objects.nonNull(list) && list.size() > 0) {
            List<Long> dataIdList = new ArrayList<>();
            for (int i = 0; i < list.size(); i++) {
                Map map = (Map) list.get(i);
                dataIdList.add(Long.parseLong(String.valueOf(map.get("userId"))));
            }
            //求差值id集合
            List<Long> distinctIdList = markerIdList.stream().filter(item -> !dataIdList.contains(item)).collect(Collectors.toList());
            if (Objects.nonNull(distinctIdList) && distinctIdList.size() > 0) {
                for (Long l : distinctIdList) {
                    Map map = new HashMap();
                    map.put("userName", markerMap.get(l).getMarkerName());
                    map.put("sumCount", 0);
                    map.put("userId", l);
                    list.add(map);
                }
            }
        }
        //排序
        Collections.sort(list, new Comparator<Map<String, Object>>() {
            @Override
            public int compare(Map<String, Object> o1, Map<String, Object> o2) {
                String o1Value = String.valueOf(o1.get("userName"));
                String o2Value = String.valueOf(o2.get("userName"));
                return o1Value.compareTo(o2Value);
            }
        });
        return list;
    }
}
