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.GasParametersTagService;
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 GasParametersTagStrategy implements CommandStrategy<GasParametersTag> {

    @Resource
    private GasParametersTagService gasParametersTagService;

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


    private static GasParametersTagStrategy gasParametersTagStrategy;

    private List<GasParametersTag> gasParametersTags = new ArrayList<>();


    @PostConstruct
    public void init() {
        gasParametersTagStrategy = this;
        gasParametersTagStrategy.gasParametersTagService = this.gasParametersTagService;
        gasParametersTagStrategy.gasParametersTags = this.gasParametersTags;
        gasParametersTagStrategy.redisTemplate = this.redisTemplate;
    }

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

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

            List<GasParametersTag> tempList = gasParametersTagStrategy.gasParametersTagService.list(Wrappers.lambdaQuery(GasParametersTag.class)
                    .eq(GasParametersTag::getAppId, gasParametersTag.getAppId())
                    .eq(GasParametersTag::getOriginId, gasParametersTag.getOriginId()));

            if (CollectionUtil.isNotEmpty(tempList)) {
                upd(gasParametersTag);
            } else {
                // 新增指标
                this.checkData4Add(gasParametersTag);
                add(gasParametersTag);
            }

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


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


        } 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("gasParametersTagStrategy 进行find操作 .......");
            List<GasParametersTag> list = gasParametersTagStrategy.gasParametersTagService.list(
                    Wrappers.lambdaQuery(GasParametersTag.class).in(GasParametersTag::getOriginId, idList)
                            .eq(GasParametersTag::getAppId, dataAddVO.getAppId())
            );
            return MessageInfo.ok(list);
        }

        return null;
    }

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

        List<GasParametersTag> gasParametersTags = new ArrayList<>();

        for (DataAddVO dataAddVO : dataAddVOS) {
            GasParametersTag gasParametersTag = JSONUtil.toBean(dataAddVO.getJsonDate().toString(), GasParametersTag.class);
            gasParametersTag.setAppId(dataAddVO.getAppId());
            gasParametersTags.add(gasParametersTag);
        }

        if (MessageCommandEnum.MESSAGE_ADD.getCommand().equals(command)) {
            log.info("gasParametersTagStrategy 进行add-batch操作 ......添加数量为：" + gasParametersTags.size());
            for (GasParametersTag gasParametersTag : gasParametersTags) {
                List<GasParametersTag> tempList = gasParametersTagStrategy.gasParametersTagService.list(Wrappers.lambdaQuery(GasParametersTag.class)
                        .eq(GasParametersTag::getAppId, gasParametersTag.getAppId())
                        .eq(GasParametersTag::getOriginId, gasParametersTag.getOriginId()));


                if (CollectionUtil.isNotEmpty(tempList)) {
                    // TODO: 2024/8/22 启用
                    this.upd(gasParametersTag);
                } else {
                    // 新增指标
                    this.checkData4Add(gasParametersTag);
                    add(gasParametersTag);
                }
            }
        } else if (MessageCommandEnum.MESSAGE_DEL.getCommand().equals(command)) {
            log.info("gasParametersTagStrategy 进行del-batch操作 .......删除数量为：" + gasParametersTags.size());
            for (GasParametersTag gasParametersTag : gasParametersTags) {
                del(gasParametersTag);
            }
        } else if (MessageCommandEnum.MESSAGE_upd.getCommand().equals(command)) {
            log.info("gasParametersTagStrategy 进行upd-batch操作 .......更新数量为：" + gasParametersTags.size());
            for (GasParametersTag gasParametersTag : gasParametersTags) {
                upd(gasParametersTag);
            }
        }

        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 stopTagCache(String appId, String platformCode, String tagCode) {
        log.info("gasParametersTagStrategy 进行stopTag操作 .......");
        //停用 接口收到指标停用的变更后， 在线率停止计算，应收到次数以变更时间为节点，计算在线率
        //启用 接口收到指标启用的变更后，如果初始化中没有，则新增，开始时间以变更时间为准，计算在线率。 如果初始化中有（一天内多次停用启用，在线率分段计算，只计算启用段内的。
        BoundHashOperations parametersTagCache = gasParametersTagStrategy.redisTemplate.boundHashOps(LocalDate.now() + ":" + PerceptionMonitorGasInfo.TABLE_NAME + ":" + appId + ":" + platformCode + ":" + tagCode);

        // 2024/11/14 删除时候-判断缓存是否存在
        Boolean hasKey = gasParametersTagStrategy.redisTemplate.hasKey(LocalDate.now() + ":" + PerceptionMonitorGasInfo.TABLE_NAME + ":" + appId + ":" + platformCode + ":" + tagCode);
        if (Boolean.FALSE.equals(hasKey)){
            return;
        }
        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 startTagCache(GasParametersTag gasParametersTag) {
        log.info("gasParametersTagStrategy 进行startTag操作 ......");
        //停用 接口收到指标停用的变更后， 在线率停止计算，应收到次数以变更时间为节点，计算在线率
        //启用 接口收到指标启用的变更后，如果初始化中没有，则新增，开始时间以变更时间为准，计算在线率。 如果初始化中有（一天内多次停用启用，在线率分段计算，只计算启用段内的。
        BoundHashOperations parametersTagCache = gasParametersTagStrategy.redisTemplate.boundHashOps(LocalDate.now() + ":"
                + PerceptionMonitorGasInfo.TABLE_NAME + ":"
                + gasParametersTag.getAppId() + ":"
                + gasParametersTag.getPlatformCode() + ":"
                + gasParametersTag.getTagCode());
        Integer count = (Integer) parametersTagCache.get("received_count");

        if (!Objects.nonNull(count)) {
            // 初始化
            parametersTagCache.put("should_accept_count", 0);
            parametersTagCache.put("received_count", 0);
            parametersTagCache.put("begin_time", LocalDateTime.now().toString());
            parametersTagCache.put("enable", 0);
            parametersTagCache.put("resource", PerceptionMonitorGasInfo.TABLE_NAME);
            parametersTagCache.put("tagInfo", JSONUtil.toJsonStr(gasParametersTag));
            parametersTagCache.expire(48, TimeUnit.HOURS);
        } else {
            // 恢复缓存
            parametersTagCache.put("begin_time", LocalDateTime.now().toString());
            parametersTagCache.delete("end_time");
            parametersTagCache.put("enable", 0);
            parametersTagCache.put("resource", PerceptionMonitorGasInfo.TABLE_NAME);
            parametersTagCache.put("tagInfo", JSONUtil.toJsonStr(gasParametersTag));
            parametersTagCache.expire(48, TimeUnit.HOURS);
        }
    }

    /**
     * @Description: 指标添加
     * @Param: [java.lang.String, java.lang.String, java.lang.String]
     * @Return: void
     * @Author: vincent.zhao
     * @Date: 2024/6/20 16:01
     */
    private void addTagCache(String appId, String platformCode, String tagCode) {
        log.info("gasParametersTagStrategy 进行addTag操作 .......");
        BoundHashOperations parametersTagCache = gasParametersTagStrategy.redisTemplate.boundHashOps(LocalDate.now() + ":" + PerceptionMonitorGasInfo.TABLE_NAME + ":" + appId + ":" + platformCode + ":" + tagCode);

        parametersTagCache.put("begin_time", LocalDateTime.now().toString());
        parametersTagCache.put("resource", PerceptionMonitorGasInfo.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.GasParametersTag]
     * @Return: void
     * @Author: vincent.zhao
     * @Date: 2024/6/21 15:14
     */
    private void add(GasParametersTag gasParametersTag) {
        log.info("gasParametersTagStrategy 进行add操作 ......");
        gasParametersTagStrategy.gasParametersTagService.save(gasParametersTag);
        if (!"1".equals(gasParametersTag.getStatus())) {
            addTagCache(gasParametersTag.getAppId(), gasParametersTag.getPlatformCode(), gasParametersTag.getTagCode());
        }

    }

    /**
     * @Description: 更新
     * @Param: [com.lutao.entity.GasParametersTag]
     * @Return: void
     * @Author: vincent.zhao
     * @Date: 2024/6/25 15:21
     */
    private void upd(GasParametersTag gasParametersTag) {
        log.info("gasParametersTagStrategy 进行upd操作 .......");
        List<GasParametersTag> gasParametersTagTemps = gasParametersTagStrategy.gasParametersTagService.list(Wrappers.lambdaQuery(GasParametersTag.class)
                .eq(GasParametersTag::getAppId, gasParametersTag.getAppId())
                .eq(GasParametersTag::getOriginId, gasParametersTag.getOriginId()));
        GasParametersTag gasParametersTagTemp = gasParametersTagTemps.get(0);
        gasParametersTagStrategy.gasParametersTagService.update(gasParametersTag, Wrappers.lambdaQuery(GasParametersTag.class)
                .eq(GasParametersTag::getAppId, gasParametersTag.getAppId())
                .eq(GasParametersTag::getOriginId, gasParametersTag.getOriginId()));
        /**
         * 1.当前状态有效0，新指标状态有效0，不操作缓存；
         * 2.当前状态有效0，新指标状态无效1，停止缓存；->stopTagCache()
         * 3.当前状态无效1，新指标状态有效0，恢复缓存；->startTagCache()
         * 4.当前状态无效1，新指标状态无效1，不操作缓存；
         */
        // 指标缓存停用
        if ("1".equals(gasParametersTag.getStatus()) && !"1".equals(gasParametersTagTemp.getStatus())) {
            stopTagCache(gasParametersTag.getAppId(), gasParametersTag.getPlatformCode(), gasParametersTag.getTagCode());
        }
        // 指标缓存启用
        if ("0".equals(gasParametersTag.getStatus()) && ("1".equals(gasParametersTagTemp.getStatus()))) {
            startTagCache(gasParametersTag);
        }
    }

    /**
     * @Description: 删除
     * @Param: [com.lutao.entity.GasParametersTag]
     * @Return: void
     * @Author: vincent.zhao
     * @Date: 2024/6/20 16:01
     */
    private void del(GasParametersTag gasParametersTag) {
        log.info("gasParametersTagStrategy 进行del操作 .......");
        gasParametersTag.setDelFlag("1");
        gasParametersTagStrategy.gasParametersTagService.update(Wrappers.lambdaQuery(GasParametersTag.class)
                .eq(GasParametersTag::getAppId, gasParametersTag.getAppId())
                .eq(GasParametersTag::getOriginId, gasParametersTag.getOriginId()));

        //指标停用
        stopTagCache(gasParametersTag.getAppId(), gasParametersTag.getPlatformCode(), gasParametersTag.getTagCode());
    }

    /**
     * 添加时校验tag_code
     *
     * @param gasParametersTag 气体参数标签
     * @author yx
     * @date 2024/11/11
     */
    public void checkData4Add(GasParametersTag gasParametersTag) {
        int count = gasParametersTagStrategy.gasParametersTagService.count(Wrappers.lambdaQuery(GasParametersTag.class).eq(GasParametersTag::getAppId, gasParametersTag.getAppId())
                .eq(GasParametersTag::getTagCode, gasParametersTag.getTagCode()));
        if (count > 1) {
            // 重复删除
            gasParametersTagStrategy.gasParametersTagService.remove(Wrappers.lambdaQuery(GasParametersTag.class).eq(GasParametersTag::getAppId, gasParametersTag.getAppId())
                    .eq(GasParametersTag::getTagCode, gasParametersTag.getTagCode()));
        }

    }

}
