package com.malk.service.dingtalk.impl;

import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson.JSONObject;
import com.malk.delegate.DDEvent;
import com.malk.server.dingtalk.DDConf;
import com.malk.server.dingtalk.DDR;
import com.malk.service.dingtalk.DDClient_Event;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;

/**
 * 事件订阅
 *
 * @apiNote https://open.dingtalk.com/document/orgapp/obtain-the-event-list-of-failed-push-messages
 */
@Slf4j
@Service
public class DDImplClient_Event implements DDClient_Event {

    // 子项目实现接口 [静态代理]
    @Autowired
    private DDEvent event_delegate;

    /**
     * 钉钉审批回调事件
     *
     * @apiNote https://open.dingtalk.com/document/orgapp/approval-events
     */
    @Override
    public void callBackEvent_Workflow(JSONObject eventJson) {

        String eventType = eventJson.getString("EventType");
        String type = eventJson.getString("type");
        String processInstanceId = eventJson.getString("processInstanceId");
        String processCode = eventJson.getString("processCode");
        boolean isAgree = "agree".equals(eventJson.getString("result"));

        // 根据回调数据类型做不同的业务处理
        if (DDConf.BPMS_TASK_CHANGE.equals(eventType)) {
            if ("start".equals(type)) {
                log.info("[开始]审批任务回调, {}", eventJson);
                event_delegate.executeEvent_Task_Start(processInstanceId, processCode);
                return;
            }
            // 任务回调: 审批任务开始、结束、转交 -> finish：审批正常结束（同意或拒绝）, terminate：审批终止（发起人撤销审批单）
            if ("finish".equals(type)) {
                if (eventJson.getString("result").equals("redirect")) {
                    log.info("[转交]审批任务回调, {}", eventJson);
                    event_delegate.executeEvent_Task_Redirect(processInstanceId, processCode);
                    return;
                }
                log.info("[结束]审批任务回调, {}", eventJson);
                // 任务可获取到拒绝原因, 审批实例不能
                String remark = eventJson.getString("remark");
                event_delegate.executeEvent_Task_Finish(processInstanceId, processCode, isAgree, remark);
            }
            return;
        }
        if (DDConf.BPMS_INSTANCE_CHANGE.equals(eventType)) {
            if ("start".equals(type)) {
                log.info("[开始]审批实例回调, {}", eventJson);
                event_delegate.executeEvent_Instance_Start(processInstanceId, processCode);
                return;
            }
            // 审批终止（发起人撤销审批单） - result 为空
            boolean isTerminate = "terminate".equals(type);
            if (isTerminate) {
                log.info("[终止]审批实例回调, {}", eventJson);
                event_delegate.executeEvent_Instance_Finish(processInstanceId, processCode, isAgree, isTerminate, eventJson.getString("staffId"));
                return;
            }
            // 实例回调: 审批实例开始、结束 -> finish：审批正常结束（同意或拒绝）, terminate：审批终止（发起人撤销审批单）
            if ("finish".equals(type)) {
                log.info("[结束]审批实例回调, {}", eventJson);
                event_delegate.executeEvent_Instance_Finish(processInstanceId, processCode, isAgree, isTerminate, eventJson.getString("staffId"));
            }
            return;
        }
    }

    /**
     * 同步推送失败记录定时处理
     */
    @Override
    public void syncFailedList(String access_token) {
        List<JSONObject> failedList = getFailedList_all(access_token);
        log.info("###### [DD]开始同步推送失败记录 ######, {}", failedList.size());
        for (JSONObject record : failedList) {
            String eventType = String.valueOf(record.get("call_back_tag"));
            if (Arrays.asList(DDConf.BPMS_INSTANCE_CHANGE, DDConf.BPMS_TASK_CHANGE).contains(eventType)) {
                JSONObject eventJson = record.getJSONObject(eventType).getJSONObject("bpmsCallBackData");
                log.info("[DD]审批失败记录, {}", eventJson);
                callBackEvent_Workflow(eventJson);
                continue;
            }
            log.info("[DD]未处理失败记录, {}", record);
        }
        log.info("###### [DD]同步推送失败记录结束 ######");
    }

    ////////////////////////////////////////////////////////////////////////////

    /**
     * 获取推送失败列表
     */
    @Override
    public List<Map> getFailedList(String access_token) {
        return _queryFailedList(access_token, null);
    }

    /**
     * 获取推送失败列表_全部
     */
    @Override
    public List getFailedList_all(String access_token) {
        return _queryFailedList(access_token, new ArrayList<>());
    }

    // 递归查询 | 单次查询
    private List<Map> _queryFailedList(String access_token, List<Map> records) {
        DDR ddr = DDR.doGet("https://oapi.dingtalk.com/call_back/get_call_back_failed_result", null, DDConf.initTokenParams(access_token));
        if (ObjectUtil.isNull(records)) {
            return ddr.getFailedList();
        }
        records.addAll(ddr.getFailedList());
        if (ddr.isHasMore()) {
            _queryFailedList(access_token, records);
        }
        return records;
    }
}
