package com.qmth.teachcloud.common.sync;

import cn.hutool.http.HttpStatus;
import com.alibaba.fastjson.JSONObject;
import com.qmth.boot.api.exception.ApiException;
import com.qmth.boot.tools.signature.SignatureType;
import com.qmth.teachcloud.common.SignatureEntityTest;
import com.qmth.teachcloud.common.config.DictionaryConfig;
import com.qmth.teachcloud.common.contant.SystemConstant;
import com.qmth.teachcloud.common.entity.BasicSchool;
import com.qmth.teachcloud.common.enums.ExceptionResultEnum;
import com.qmth.teachcloud.common.service.CommonCacheService;
import com.qmth.teachcloud.common.util.HttpUtil;
import com.qmth.teachcloud.common.util.JacksonUtil;
import com.qmth.teachcloud.common.util.ResultUtil;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;

/**
 * 同步教研分析接口工具类
 * <p>
 * Date: 2021/10/29.
 */
@Component
public class TeachCloudReportTaskUtils {
    private static final Logger log = LoggerFactory.getLogger(TeachCloudReportTaskUtils.class);

    // 所有请求方法默认为"POST"
    private static final String POST_METHOD = "POST";

    @Resource
    private CommonCacheService commonCacheService;

    @Resource
    private DictionaryConfig dictionaryConfig;

    /**
     * 学期创建/更新接口
     *
     * @param thirdSemesterId
     * @param semesterName    学期名称
     * @param startTime       学期开始时间
     * @param endTime         学期结束时间
     * @param enable          启用/禁用，ture：启用，false：禁用，默认启用
     */
    public Long syncSemester(Long schoolId, Long thirdSemesterId, String semesterName, Long startTime, Long endTime, Boolean enable) {
        String hostUrl = dictionaryConfig.reportOpenDomain().getHostUrl();
        String saveUrl = dictionaryConfig.reportOpenDomain().getSemesterApi();
        validUrl(hostUrl, saveUrl);
        String postUrl = hostUrl.concat(saveUrl);
        long timestamp = System.currentTimeMillis();
        //参数
        try {
            Map<String, Object> map = new HashMap<>();
            map.put("id", validParam(thirdSemesterId, null, false, "学期ID"));
            map.put("semesterName", validParam(semesterName, null, true, "学期名称"));
            map.put("startTime", validParam(startTime, null, true, "学期开始时间"));
            map.put("endTime", validParam(endTime, null, true, "学期结束时间"));
            map.put("enable", validParam(enable, true, true, "是否启用标记"));

            String accessToken = createSign(schoolId, timestamp, saveUrl);
            String result = HttpUtil.postJson(postUrl, JacksonUtil.parseJson(map), accessToken, timestamp);

            JSONObject jsonObject = JSONObject.parseObject(result);
            if (jsonObject.containsKey("code")) {
                String code = jsonObject.getString("code");
                if ("200".equals(code)) {
                    return jsonObject.getLong("data");
                } else {
                    throw ExceptionResultEnum.ERROR.exception(jsonObject.getString("error"));
                }
            } else {
                throw ExceptionResultEnum.ERROR.exception("学期同步失败");
            }
        } catch (IOException e) {
            log.error(SystemConstant.LOG_ERROR, e);
            throw ExceptionResultEnum.ERROR.exception(e.getMessage());
        }
    }

    /**
     * 考试创建/更新接口
     *
     * @param schoolId   学校ID
     * @param id         考试id
     * @param examName   考试名称
     * @param examTime   考试时间
     * @param semesterId 学期id
     * @param enable     启用/禁用，ture：启用，false：禁用，默认启用
     */
    public Long syncExam(Long schoolId, Long id, String examName, Long examTime, String semesterId, Boolean enable) {
        String hostUrl = dictionaryConfig.reportOpenDomain().getHostUrl();
        String saveUrl = dictionaryConfig.reportOpenDomain().getExamApi();
        validUrl(hostUrl, saveUrl);
        String postUrl = hostUrl.concat(saveUrl);
        long timestamp = System.currentTimeMillis();
        try {
            //参数
            Map<String, Object> map = new HashMap<>();
            map.put("id", validParam(id, null, false, "考试ID"));
            map.put("examName", validParam(examName, null, true, "考试名称"));
            map.put("examTime", validParam(examTime, null, true, "考试时间"));
            map.put("semesterId", validParam(semesterId, null, true, "学期ID"));
            map.put("enable", validParam(enable, null, true, "是否启用标记"));

            String accessToken = createSign(schoolId, timestamp, saveUrl);
            String result = HttpUtil.postJson(postUrl, JacksonUtil.parseJson(map), accessToken, timestamp);
            JSONObject jsonObject = JSONObject.parseObject(result);
            if (jsonObject.containsKey("code")) {
                String code = jsonObject.getString("code");
                if ("200".equals(code)) {
                    return jsonObject.getLong("data");
                } else {
                    throw ExceptionResultEnum.ERROR.exception(jsonObject.getString("error"));
                }
            } else {
                throw ExceptionResultEnum.ERROR.exception("考试同步失败");
            }
        } catch (Exception e) {
            throw ExceptionResultEnum.ERROR.exception(e.getMessage());
        }
    }

    /**
     * @param schoolId         学校ID
     * @param examId           考试ID
     * @param courseCode       分析试卷的唯一标识
     * @param courseName       分析试卷名称
     * @param paperType        试卷类型
     * @param teachCollegeName 开课机构名称
     * @param enable           是否启用标记
     */
    public boolean syncCourse(Long schoolId, String examId, String courseCode, String courseName,
                              String paperType, String teachCollegeName, Boolean enable) {
        String hostUrl = dictionaryConfig.reportOpenDomain().getHostUrl();
        String saveUrl = dictionaryConfig.reportOpenDomain().getCourseEditApi();
        validUrl(hostUrl, saveUrl);
        String postUrl = hostUrl.concat(saveUrl);
        long timestamp = System.currentTimeMillis();
        try {
            //参数
            Map<String, Object> map = new HashMap<>();
            map.put("examId", validParam(examId, null, true, "考试ID"));
            map.put("courseCode", validParam(courseCode, null, true, "分析试卷的唯一标识"));
            map.put("courseName", validParam(courseName, null, true, "分析试卷名称"));
            map.put("paperType", validParam(paperType, "#", true, "试卷类型"));
            map.put("teachCollegeName", validParam(teachCollegeName, null, true, "开课机构名称"));
            map.put("enable", validParam(enable, true, true, "是否启用标记"));

            String accessToken = createSign(schoolId, timestamp, saveUrl);
            String result = HttpUtil.postJson(postUrl, JacksonUtil.parseJson(map), accessToken, timestamp);
            JSONObject jsonObject = JSONObject.parseObject(result);
            if (jsonObject.containsKey("code")) {
                String code = jsonObject.getString("code");
                if ("200".equals(code)) {
                    JSONObject successJson = JSONObject.parseObject(jsonObject.getString("data"));
                    return successJson.getBoolean("success");
                } else {
                    throw ExceptionResultEnum.ERROR.exception(jsonObject.getString("error"));
                }
            } else {
                throw ExceptionResultEnum.ERROR.exception("分析课程同步失败");
            }
        } catch (Exception e) {
            throw ExceptionResultEnum.ERROR.exception(e.getMessage());
        }
    }

    /**
     * @param schoolId    学校ID
     * @param examId      考试ID
     * @param courseCodes 分析试卷的唯一标识
     */
    public boolean startCalc(Long schoolId, Long examId, List<String> courseCodes) {
        String hostUrl = dictionaryConfig.reportOpenDomain().getHostUrl();
        String saveUrl = dictionaryConfig.reportOpenDomain().getCalculateApi();
        validUrl(hostUrl, saveUrl);
        String postUrl = hostUrl.concat(saveUrl);
        long timestamp = System.currentTimeMillis();
        try {
            Map<String, Object> map = new HashMap<>();
            map.computeIfAbsent("examId", v -> examId);
            map.computeIfAbsent("courseCode", v -> courseCodes);//试卷编号+卷型
            String accessToken = createSign(schoolId, timestamp, saveUrl);
            String result = HttpUtil.postJson(postUrl, JacksonUtil.parseJson(map), accessToken, timestamp);
            if (Objects.nonNull(result)) {
                JSONObject jsonObject = JSONObject.parseObject(result);
                if (Objects.nonNull(jsonObject.get("code")) && jsonObject.getIntValue("code") != HttpStatus.HTTP_OK) {
                    throw ExceptionResultEnum.ERROR.exception(jsonObject.getString("error"));
                }
                return true;
            }
            return false;
        } catch (Exception e) {
            log.error(SystemConstant.LOG_ERROR, e);
            if (e instanceof ApiException) {
                ResultUtil.error((ApiException) e, e.getMessage());
            } else {
                ResultUtil.error(e.getMessage());
            }
        }
        return false;
    }

    /**
     * 发布
     *
     * @param schoolId        学校ID
     * @param thirdExamId     考试ID
     * @param gradeCourseCode 课程
     * @param publishStatus   发布状态
     * @return
     */
    public boolean publish(Long schoolId, Long thirdExamId, String gradeCourseCode, boolean publishStatus) {
        String hostUrl = dictionaryConfig.reportOpenDomain().getHostUrl();
        String saveUrl = dictionaryConfig.reportOpenDomain().getPublishApi();
        validUrl(hostUrl, saveUrl);
        String postUrl = hostUrl.concat(saveUrl);
        long timestamp = System.currentTimeMillis();
        try {
            Map<String, Object> map = new HashMap<>();
            map.computeIfAbsent("examId", v -> thirdExamId);
            map.computeIfAbsent("courseCode", v -> gradeCourseCode);//试卷编号+卷型
            map.computeIfAbsent("publishStatus", v -> publishStatus);//发布（默认true）
            String accessToken = createSign(schoolId, timestamp, saveUrl);
            String result = HttpUtil.postJson(postUrl, JacksonUtil.parseJson(map), accessToken, timestamp);
            JSONObject jsonObject = JSONObject.parseObject(result);
            if (jsonObject.containsKey("code")) {
                String code = jsonObject.getString("code");
                if ("200".equals(code)) {
                    JSONObject successJson = JSONObject.parseObject(jsonObject.getString("data"));
                    return successJson.getBoolean("success");
                } else {
                    throw ExceptionResultEnum.ERROR.exception(jsonObject.getString("error"));
                }
            } else {
                throw ExceptionResultEnum.ERROR.exception("分析课程同步失败");
            }
        } catch (Exception e) {
            log.error(SystemConstant.LOG_ERROR, e);
            throw ExceptionResultEnum.ERROR.exception(e.getMessage());
        }
    }

    /**
     * http请求头
     *
     * @param url 请求URL
     */
    private Map<String, String> getHeaders(Long schoolId, String url) {
        long time = System.currentTimeMillis();
        Map<String, String> header = new HashMap<>();
        header.put(SystemConstant.HEADER_AUTHORIZATION, createSign(schoolId, time, url));
        header.put(SystemConstant.HEADER_TIME, String.valueOf(time));
        return header;
    }

    /**
     * 签名
     *
     * @param time 时间戳
     * @param url  请求URL
     */
    private String createSign(Long schoolId, long time, String url) {
        BasicSchool basicSchool = commonCacheService.schoolCache(schoolId);
        if (basicSchool == null) {
            throw ExceptionResultEnum.ERROR.exception("学校不存在");
        }
        if (!basicSchool.getEnable()) {
            throw ExceptionResultEnum.ERROR.exception("学校已禁用");
        }

        return SignatureEntityTest.build(SignatureType.SECRET, POST_METHOD, url, time, basicSchool.getAccessKey(), basicSchool.getAccessSecret());
    }

    /**
     * 校验参数值并返回（字符型）
     *
     * @param value        参数值
     * @param defaultValue 默认值
     * @param require      是否必填（true：是，false：否）
     * @param name         参数名称
     */
    private String validParam(String value, String defaultValue, boolean require, String name) {
        if (require && StringUtils.isAllBlank(value, defaultValue)) {
            throw ExceptionResultEnum.ERROR.exception((StringUtils.isBlank(name) ? "" : name) + "值必填");
        }
        return StringUtils.isBlank(value) ? defaultValue : value;

    }

    /**
     * 校验参数值并返回（Long型）
     *
     * @param value        参数值
     * @param defaultValue 默认值
     * @param require      是否必填（true：是，false：否）
     * @param name         参数名称
     */
    private Long validParam(Long value, Long defaultValue, boolean require, String name) {
        if (require && Objects.isNull(value) && Objects.isNull(defaultValue)) {
            throw ExceptionResultEnum.ERROR.exception((StringUtils.isBlank(name) ? "" : name) + "值必填");
        }
        return Objects.isNull(value) ? defaultValue : value;

    }

    /**
     * 校验参数值并返回 （布尔型）
     *
     * @param value        参数值
     * @param defaultValue 默认值
     * @param require      是否必填
     * @param name         描述
     */
    private Boolean validParam(Boolean value, Boolean defaultValue, Boolean require, String name) {
        if (require && value == null && defaultValue == null) {
            throw ExceptionResultEnum.ERROR.exception((StringUtils.isBlank(name) ? "" : name) + "值必填");
        }
        return value == null ? defaultValue : value;

    }

    /**
     * 校验url是否配置
     *
     * @param urls URL数组
     */
    private void validUrl(String... urls) {
        if (StringUtils.isAnyBlank(urls)) {
            throw ExceptionResultEnum.ERROR.exception("云阅卷同步接口未正确配置");
        }
    }

}
