package com.malk.mc.controller;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.malk.controller.DDCallbackController;
import com.malk.mc.service.McYdService;
import com.malk.server.dingtalk.DDConf;
import com.malk.server.dingtalk.crypto.DingCallbackCrypto;
import com.malk.service.dingtalk.DDClient_Event;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.*;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

@Slf4j
@RestController
@Component
@RequestMapping("/callBack")
public class McCallBackController extends DDCallbackController {
    @Autowired
    private DDConf ddConf;

    @Autowired
    private McYdService mcYdService;

    @GetMapping("/test")
    public String test(){
        return "test";
    }

    /**
     * 钉钉审批回调: [依赖包方案已弃用]
     * -
     * DingCallbackCrypto 方案: 官网案例 DingCallbackCrypto 不在钉钉架包, 需要单独引用
     * 在钉钉开放平台重新保存回调地址后, 所有的注册事件会被关闭:: 通过代码注册不成功; 官方回复, 要么使用调用注册的方式 要么是后台的方式, 二选一
     */
    @SneakyThrows
    public Map<String, String> invokeCallback(@RequestParam(value = "signature", required = false) String signature,
                                              @RequestParam(value = "timestamp", required = false) String timestamp,
                                              @RequestParam(value = "nonce", required = false) String nonce,
                                              @RequestBody(required = false) JSONObject json) {
        log.info("signature：{}",signature);
        log.info("timestamp：{}",timestamp);
        log.info("nonce：{}",nonce);
        log.info("json：{}",json);

        DingCallbackCrypto callbackCrypto = new DingCallbackCrypto(ddConf.getToken(), ddConf.getAesKey(), ddConf.getAppKey());
        final String decryptMsg = callbackCrypto.getDecryptMsg(signature, timestamp, nonce, json.getString("encrypt"));
        JSONObject eventJson = JSON.parseObject(decryptMsg);
        Map success = callbackCrypto.getEncryptedMap(DDConf.CALLBACK_RESPONSE, System.currentTimeMillis(), DingCallbackCrypto.Utils.getRandomStr(8));

        String eventType = eventJson.getString("EventType");
        if (DDConf.CALLBACK_CHECK.equals(eventType)) {
            log.info("----- [DD]验证注册 -----");
            return success;
        }
        if ("check_in".equals(eventType)) {
            String eventId = eventJson.getString("eventId");//事件id

            log.info("[DD]签到回调, {}", eventJson);

            // 检查回调事件是否已经处理过，如果是，则忽略该回调
            if (isCallbackProcessed(eventId)) {
                log.info("----- [DD]该签到回调事件已处理过 忽略该回调 -----");
                return success;
            }else {
                // 将回调事件和当前时间戳添加到已处理集合中
                long currentTime = System.currentTimeMillis();
                eventList.put(eventId, currentTime);
            }

            mcYdService.getCheckInData(eventJson);

            return success;
        }
        log.info("----- [DD]已注册, 未处理的其它回调 -----, {}", eventJson);
        return success;
    }

    //保存10s内已处理的回调事件
    private Map<String, Long> eventList = new HashMap<>();

    /**
     * 检查该回调事件在10s内是否处理过，应对钉钉瞬间重复回调
     *
     * @param eventId 回调事件id
     * @return 是否处理过
     */
    private boolean isCallbackProcessed(String eventId) {
        // 清理超过10s的回调事件
        long currentTime = System.currentTimeMillis();
        long expirationTime = currentTime - TimeUnit.MINUTES.toMillis(10);
        eventList.entrySet().removeIf(entry -> entry.getValue() < expirationTime);

        return eventList.containsKey(eventId);
    }
}
