package com.lutao.cloud.consume.factory;

import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.fasterxml.jackson.databind.JsonNode;
import com.lutao.cloud.collect.vo.DataAddVO;
import com.lutao.cloud.common.core.kafka.MessageCommandEnum;
import com.lutao.cloud.common.core.util.CollectionUtil;
import com.lutao.cloud.common.core.util.MessageInfo;
import com.lutao.cloud.consume.service.ProcessParameterTagService;
import com.lutao.cloud.consume.util.TimeUtil;
import com.lutao.entity.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.BoundHashOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

@Component
@Slf4j
public class ProcessParametersTagStrategy implements CommandStrategy<ProcessParameterTag> {

    @Resource
    private ProcessParameterTagService processParameterTagService;

    @Resource(name = "redisTemplateAlias")
    private RedisTemplate redisTemplate;


    private static ProcessParametersTagStrategy processParametersTagStrategy;

    private List<ProcessParameterTag> processParameterTags = new ArrayList<>();


    @PostConstruct
    public void init() {
        processParametersTagStrategy = this;
        processParametersTagStrategy.processParameterTagService = this.processParameterTagService;
        processParametersTagStrategy.processParameterTags = this.processParameterTags;
        processParametersTagStrategy.redisTemplate = this.redisTemplate;
    }

    @Override
    public MessageInfo execute(String command, JsonNode data, DataAddVO dataAddVO) {

        if (MessageCommandEnum.MESSAGE_ADD.getCommand().equals(command)) {
            ProcessParameterTag processParameterTag = JSONUtil.toBean(data.toString(), ProcessParameterTag.class);
            processParameterTag.setAppId(dataAddVO.getAppId());
            add(processParameterTag);

        } else if (MessageCommandEnum.MESSAGE_DEL.getCommand().equals(command)) {
            ProcessParameterTag processParameterTag = JSONUtil.toBean(data.toString(), ProcessParameterTag.class);
            processParameterTag.setAppId(dataAddVO.getAppId());
            del(processParameterTag);

        } else if (MessageCommandEnum.MESSAGE_upd.getCommand().equals(command)) {
            ProcessParameterTag processParameterTag = JSONUtil.toBean(data.toString(), ProcessParameterTag.class);
            processParameterTag.setAppId(dataAddVO.getAppId());
            upd(processParameterTag);

        } else if (MessageCommandEnum.MESSAGE_FIND.getCommand().equals(command)) {

            List<String> idList = new ArrayList<>();
            for (JsonNode node : data) {
                String id = node.get("id").asText();
                idList.add(id);
            }

            log.info("processParametersTagStrategy 进行find操作 .......");
            List<ProcessParameterTag> list = processParametersTagStrategy.processParameterTagService.list(
                    Wrappers.lambdaQuery(ProcessParameterTag.class).in(ProcessParameterTag::getOriginId, idList)
                            .eq(ProcessParameterTag::getAppId, dataAddVO.getAppId())
            );
            return MessageInfo.ok(list);
        }

        return null;
    }

    @Override
    public MessageInfo executeBatch(List<DataAddVO> dataAddVOS) {
        String command = dataAddVOS.get(0).getCommand();

        List<ProcessParameterTag> processParameterTags = new ArrayList<>();

        for (DataAddVO dataAddVO : dataAddVOS) {
            ProcessParameterTag processParameterTag = JSONUtil.toBean(dataAddVO.getJsonDate().toString(), ProcessParameterTag.class);
            processParameterTag.setAppId(dataAddVO.getAppId());
            processParameterTags.add(processParameterTag);
        }

        if (MessageCommandEnum.MESSAGE_ADD.getCommand().equals(command)) {
            log.info("processParametersTagStrategy 进行add-batch操作 ......添加数量为：" + processParameterTags.size());
            for (ProcessParameterTag processParameterTag : processParameterTags) {
                add(processParameterTag);
            }
        } else if (MessageCommandEnum.MESSAGE_DEL.getCommand().equals(command)) {
            log.info("processParametersTagStrategy 进行del-batch操作 .......删除数量为：" + processParameterTags.size());
            for (ProcessParameterTag processParameterTag : processParameterTags) {

            }
        } else if (MessageCommandEnum.MESSAGE_upd.getCommand().equals(command)) {
            log.info("processParametersTagStrategy 进行upd-batch操作 .......更新数量为：" + processParameterTags.size());
            for (ProcessParameterTag processParameterTag : processParameterTags) {
                upd(processParameterTag);
            }
        }

        return null;
    }

    /**
     * @Description: 指标停用
     * @Param: [java.lang.String, java.lang.String, java.lang.String]
     * @Return: void
     * @Author: vincent.zhao
     * @Date: 2024/6/20 16:01
     */
    private void stopTag(String appId, String platformCode, String tagCode) {
        //停用 接口收到指标停用的变更后， 在线率停止计算，应收到次数以变更时间为节点，计算在线率
        //启用 接口收到指标启用的变更后，如果初始化中没有，则新增，开始时间以变更时间为准，计算在线率。 如果初始化中有（一天内多次停用启用，在线率分段计算，只计算启用段内的。
        BoundHashOperations parametersTagCache = processParametersTagStrategy.redisTemplate.boundHashOps(LocalDate.now() + ":" + PerceptionMonitorInfo.TABLE_NAME + ":" + appId + ":" + platformCode + ":" + tagCode);
        Integer count = (Integer) parametersTagCache.get("received_count");

        if (Objects.nonNull(count)) {
            //这个指标信息已经存在 且收到信息的情况
            parametersTagCache.put("end_time", LocalDateTime.now().toString());
            // 计算每分钟应该接受的数据量
            LocalDateTime beginTime = LocalDateTime.parse(parametersTagCache.get("begin_time").toString(), DateTimeFormatter.ISO_LOCAL_DATE_TIME);
            Long shouldAcceptCount = TimeUtil.getTimeDifference(beginTime, LocalDateTime.now());
            parametersTagCache.put("should_accept_count", shouldAcceptCount);
            parametersTagCache.put("enable", 1);

        }
    }

    private void startTag(String appId, String platformCode, String tagCode) {
        //停用 接口收到指标停用的变更后， 在线率停止计算，应收到次数以变更时间为节点，计算在线率
        //启用 接口收到指标启用的变更后，如果初始化中没有，则新增，开始时间以变更时间为准，计算在线率。 如果初始化中有（一天内多次停用启用，在线率分段计算，只计算启用段内的。
        BoundHashOperations parametersTagCache = processParametersTagStrategy.redisTemplate.boundHashOps(LocalDate.now() + ":" + PerceptionMonitorInfo.TABLE_NAME + ":" + appId + ":" + platformCode + ":" + tagCode);
        Integer count = (Integer) parametersTagCache.get("received_count");

        if (Objects.nonNull(count) && count < 1) {
            parametersTagCache.put("should_accept_count", 0);
            parametersTagCache.put("received_count", 0);
            parametersTagCache.put("begin_time", LocalDateTime.now().toString());
            parametersTagCache.put("enable", 0);
        }else{
            //有的情况下
            parametersTagCache.put("begin_time", LocalDateTime.now().toString());
            parametersTagCache.delete("end_time");
            parametersTagCache.put("enable", 0);
        }
    }

    /**
     * @Description: 指标添加
     * @Param: [java.lang.String, java.lang.String, java.lang.String]
     * @Return: void
     * @Author: vincent.zhao
     * @Date: 2024/6/20 16:01
     */
    private void addTag(String appId, String platformCode, String tagCode) {
        BoundHashOperations parametersTagCache = processParametersTagStrategy.redisTemplate.boundHashOps(LocalDate.now() + ":" + PerceptionMonitorInfo.TABLE_NAME + ":" + appId + ":" + platformCode + ":" + tagCode);
        Integer count = (Integer) parametersTagCache.get("received_count");

        if (Objects.nonNull(count)) {
            parametersTagCache.put("begin_time", LocalDateTime.now().toString());
            parametersTagCache.put("resource", PerceptionMonitorFireInfo.TABLE_NAME);
            parametersTagCache.put("received_count", 0);
            parametersTagCache.put("should_accept_count", 0);
            parametersTagCache.put("enable", 0);
            parametersTagCache.expire(48, TimeUnit.HOURS);
        }
    }

    /**
     * @Description: 添加
     * @Param: [com.lutao.entity.ProcessParameterTag]
     * @Return: void
     * @Author: vincent.zhao
     * @Date: 2024/6/21 15:14
     */
    private void add(ProcessParameterTag processParameterTag) {
        List<ProcessParameterTag> tempList = processParametersTagStrategy.processParameterTagService.list(Wrappers.lambdaQuery(ProcessParameterTag.class)
                .eq(ProcessParameterTag::getAppId, processParameterTag.getAppId())
                .eq(ProcessParameterTag::getOriginId, processParameterTag.getOriginId()));

        // 新增指标
        if (CollectionUtil.isNotEmpty(tempList)) {
            addTag(processParameterTag.getAppId(), processParameterTag.getPlatformCode(), processParameterTag.getTagCode());
        }

        log.info("processParametersTagStrategy 进行add操作 ......");
        int count = processParametersTagStrategy.processParameterTagService.count(Wrappers.lambdaQuery(ProcessParameterTag.class).eq(ProcessParameterTag::getAppId, processParameterTag.getAppId())
                .eq(ProcessParameterTag::getTagCode, processParameterTag.getTagCode()));
        if (count>1){
            processParametersTagStrategy.processParameterTagService.remove(Wrappers.lambdaQuery(ProcessParameterTag.class).eq(ProcessParameterTag::getAppId, processParameterTag.getAppId())
                    .eq(ProcessParameterTag::getTagCode, processParameterTag.getTagCode()));
        }
        processParametersTagStrategy.processParameterTagService.saveOrUpdate(processParameterTag,
                Wrappers.lambdaQuery(ProcessParameterTag.class)
                        .eq(ProcessParameterTag::getAppId, processParameterTag.getAppId())
                        .eq(ProcessParameterTag::getOriginId, processParameterTag.getOriginId()));
        //指标停用
        if ("1".equals(processParameterTag.getStatus())) {
            stopTag(processParameterTag.getAppId(), processParameterTag.getPlatformCode(), processParameterTag.getTagCode());
        }

    }

    /**
     * @Description: 更新
     * @Param: [com.lutao.entity.ProcessParameterTag]
     * @Return: void
     * @Author: vincent.zhao
     * @Date: 2024/6/25 15:21
     */
    private void upd(ProcessParameterTag processParameterTag) {
        log.info("processParametersTagStrategy 进行upd操作 .......");
        processParametersTagStrategy.processParameterTagService.update(processParameterTag, Wrappers.lambdaQuery(ProcessParameterTag.class)
                .eq(ProcessParameterTag::getAppId, processParameterTag.getAppId())
                .eq(ProcessParameterTag::getOriginId, processParameterTag.getOriginId()));

        //指标停用
        if ("1".equals(processParameterTag.getStatus())) {
            stopTag(processParameterTag.getAppId(), processParameterTag.getPlatformCode(), processParameterTag.getTagCode());
        }
        //启用
        if ("0".equals(processParameterTag.getStatus())) {
            startTag(processParameterTag.getAppId(), processParameterTag.getPlatformCode(), processParameterTag.getTagCode());
        }

    }

    /**
     * @Description: 删除
     * @Param: [com.lutao.entity.ProcessParameterTag]
     * @Return: void
     * @Author: vincent.zhao
     * @Date: 2024/6/20 16:01
     */
    private void del(ProcessParameterTag processParameterTag) {

        log.info("processParametersTagStrategy 进行del操作 .......");
        processParametersTagStrategy.processParameterTagService.remove(Wrappers.lambdaQuery(ProcessParameterTag.class)
                .eq(ProcessParameterTag::getAppId, processParameterTag.getAppId())
                .eq(ProcessParameterTag::getOriginId, processParameterTag.getOriginId()));

        //指标停用
        stopTag(processParameterTag.getAppId(), processParameterTag.getPlatformCode(), processParameterTag.getTagCode());
    }

}
