package com.sagacloud.endpoints;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.sagacloud.dict.TlStaticInfo;
import com.sagacloud.utils.*;
import com.sagacloud.utils.jsonHelper.infoPoint.InfoPoint;
import com.sagacloud.utils.objectLog.ActivityLogObject;
import com.sagacloud.utils.objectLog.ActivityLogRunnable;
import com.sagacloud.utils.objectLog.ActivityLogUtil;
import com.sagacloud.utils.objects.CommonQueryCriteria;
import com.sagacloud.utils.objects.ObjectIdName;
import com.sagacloud.utils.objects.ObjectType;
import com.sagacloud.utils.qrCode.QRCodeRunnable;

import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.container.ResourceContext;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import java.util.*;

/**
 * Created by wo on 10/10/19.
 */
@Path("tool")
public class Tool {
    @Context
    private ResourceContext resourceContext;

    @Path("/batch/create")
    @POST
    @Produces(MediaType.APPLICATION_JSON)
    public String batchCreate(@QueryParam(Const.PROJECT_ID) String projectId, String jsonStr){
        JSONObject postBody = JSONObject.parseObject(jsonStr);
        return batchCreate(projectId, postBody);
    }

    public String batchCreate(@QueryParam(Const.PROJECT_ID) String projectId, JSONObject postBody){
        try{
            String imageUrl = postBody.getString("innerImageUrl");
            Boolean genPersagyQr = postBody.getBoolean("genPersagyQr");
            if(genPersagyQr == null){
                genPersagyQr = false;
            }
            JSONArray criterias = postBody.getJSONArray("criterias");
            if(criterias == null || criterias.size() == 0){
                return DpUtils.returnJSONArray(new JSONArray(), "");
            }
            JSONArray errors = new JSONArray();
            String pjId = projectId.substring(2);
//            一. 准备数据
//            1. 为每个对象生成id, 或者检验指定的id符不符合规则, 检验是否有重复指定的id.
//            2. 获取每个类型下的信息点列表. (剔除错误类型)
            Set<String> typeSet = this.checkGenerateId(pjId, criterias, errors);
            //检查不同业务空间的信息点
            HashMap<String, HashMap<String, InfoPoint>> infoCodeMap = InfoCodeUtil.getWholeInfosWithCustomMap(pjId, typeSet.toArray(new String[typeSet.size()]));
//            3. 通过2获取到的信息点列表, 验证信息点的key是否正确(剔除错误)
//            4. 验证信息点节点的格式是否正确.
            this.verifyInfos(criterias, infoCodeMap, errors);
//            5. DefaultQRCode, 有的话不再插入二维码, 没有的话, 添加二维码信息点, 同时记录id(用于接口返回后添加二维码图片).
            Map<String, String> idFileKeyMap = new HashMap<>();
            JSONCheckUtil.addQRCodeInfo(projectId, criterias, "DefaultQRCode", idFileKeyMap);
//            二. 插入数据
//            1. 插入对象表 (将失败的剔除)
            String time = CommonUtil.getTime();
            DpUtils.submitToObjectTable(pjId, criterias, time, errors);
            // 补充信息点数据
            ArrayList<ActivityLogObject> logList = new ArrayList<>();
            for(int i = 0; i < criterias.size(); ++i) {
                JSONObject single = criterias.getJSONObject(i);
                String id = single.getString("id");
                ObjectType ot = ObjectType.tool;
                String detailedType = single.getString(Const.CATEGORY);
                com.sagacloud.dict.InfosUtil.addIdName(pjId, ot, detailedType, single.getJSONObject("infos"), id, new ObjectIdName());
                // 添加要发送到activeMQ的消息
                ActivityLogUtil.addMessageToQueue(pjId, time, logList, id, ot);
            }
            JSONArray success = new JSONArray();
            PropertyUtil.putIDToInfos(criterias, success);
//            2. 插入信息点
            ObjectUtil.batchUpdate(pjId, criterias, false, true, false, new CommonQueryCriteria());
//            三. 接口返回后
//            1. 发送activeMQ消息, 记录日志
            ActivityLogRunnable activityLog = new ActivityLogRunnable(logList);
            ActivityLogUtil.pool.submit(activityLog);
//            2. 生成二维码文件, 上传到文件服务器
            QRCodeRunnable qrCodeRunnable = new QRCodeRunnable(idFileKeyMap, imageUrl, projectId, genPersagyQr);
            ActivityLogUtil.pool.submit(qrCodeRunnable);
            return PropertyUtil.returnOnCreation(success, errors, "");
        }catch (Exception ex){
            ex.printStackTrace();
            return DpUtils.errorJsonMsg(ex.getMessage() == null? "添加失败!": ex.getMessage());
        }
    }

    /**
     * 检查耗材的id, 并将所有要检查的对象类型(大类型和详细类型)返回
     * @param pjId 项目id
     * @param criterias
     * @param errors
     * @return 添加对象的详细业务空间类型
     */
    private Set<String> checkGenerateId(String pjId, JSONArray criterias, JSONArray errors) {
        Set<String> typeSet = new HashSet<>();
        Set<String> idSet = new HashSet<>();
        for(int i = criterias.size() - 1; i > -1; --i){
            JSONObject obj = criterias.getJSONObject(i);
            if(obj == null){
                criterias.remove(i);
                continue;
            }
            String cate = obj.getString(Const.CATEGORY);
            if(cate == null){
                PropertyUtil.moveToError(criterias, i, errors, "缺少类型编码");
                continue;
            }
            if(cate != null && !TlStaticInfo.getCode2name().keySet().contains(cate)){
                PropertyUtil.moveToError(criterias, i, errors, "类型编码错误");
                continue;
            }

            String prefix = String.join("", Const.OBJ_TYPE_TOOL, pjId);
            String id = obj.getString("id");
            if(id != null && id.length() > 0){
                // 已有id的对象, 验证id
                if(!DpUtils.checkId(pjId, id) || !prefix.startsWith(id.substring(0, 2))){
                    PropertyUtil.moveToError(criterias, i, errors, "指定id错误");
                    continue;
                }
            }else{
                // 没有id的对象, 生成id添加进对象
                id = DpUtils.generateUUID(prefix, true);
                obj.put("id", id);
            }
            if(idSet.contains(id)){
                PropertyUtil.moveToError(criterias, i, errors, "id重复");
                continue;
            }
            typeSet.add(cate);
            idSet.add(id);

        }
        return  typeSet;
    }

    private void verifyInfos(JSONArray criterias, HashMap<String, HashMap<String, InfoPoint>> infoCodeMap, JSONArray errors) {
        for(int i = criterias.size() - 1; i > -1; --i){
            JSONObject obj = criterias.getJSONObject(i);
            String cate = obj.getString("category");
            JSONObject infos = obj.getJSONObject("infos");
            JSONCheckUtil.validInfoCode(criterias, errors, i, ObjectType.tool.name(), infoCodeMap.get(cate), infos);
        }
    }

    @Path("/batch/delete")
    @POST
    @Produces(MediaType.APPLICATION_JSON)
    public String batchDelete(@QueryParam(Const.PROJECT_ID) String projectId, String jsonStr){
        return resourceContext.getResource(Consumable.class).batchDelete(projectId, jsonStr);
    }
}
