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.FireParametersTagService;
import com.lutao.cloud.consume.util.TimeUtil;
import com.lutao.entity.FireParametersTag;
import com.lutao.entity.PerceptionMonitorFireInfo;
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 org.springframework.transaction.annotation.Transactional;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
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 FireParametersTagStrategy implements CommandStrategy<FireParametersTag> {

    @Resource
    private FireParametersTagService fireParametersTagService;

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

    private static FireParametersTagStrategy fireParametersTagStrategy;

    private List<FireParametersTag> fireParametersTags = new ArrayList<>();


    @PostConstruct
    public void init() {
        fireParametersTagStrategy = this;
        fireParametersTagStrategy.fireParametersTagService = this.fireParametersTagService;
        fireParametersTagStrategy.fireParametersTags = this.fireParametersTags;
        fireParametersTagStrategy.redisTemplate = this.redisTemplate;
    }

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

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

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

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

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

        return null;
    }

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

        List<FireParametersTag> fireParametersTags = new ArrayList<>();

        for (DataAddVO dataAddVO : dataAddVOS) {
            FireParametersTag fireParametersTag = JSONUtil.toBean(dataAddVO.getJsonDate().toString(), FireParametersTag.class);
            fireParametersTag.setAppId(dataAddVO.getAppId());
            fireParametersTags.add(fireParametersTag);
        }

        if (MessageCommandEnum.MESSAGE_ADD.getCommand().equals(command)) {
            log.info("fireParametersTagStrategy 进行add-batch操作 ......添加数量为：" + fireParametersTags.size());
            for (FireParametersTag fireParametersTag : fireParametersTags) {
                add(fireParametersTag);
            }
        } else if (MessageCommandEnum.MESSAGE_DEL.getCommand().equals(command)) {
            log.info("fireParametersTagStrategy 进行del-batch操作 .......删除数量为：" + fireParametersTags.size());
            for (FireParametersTag fireParametersTag : fireParametersTags) {
                del(fireParametersTag);
            }
        } else if (MessageCommandEnum.MESSAGE_upd.getCommand().equals(command)) {
            log.info("fireParametersTagStrategy 进行upd-batch操作 .......更新数量为：" + fireParametersTags.size());
            for (FireParametersTag fireParametersTag : fireParametersTags) {
                upd(fireParametersTag);
            }
        }

        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 = fireParametersTagStrategy.redisTemplate.boundHashOps(LocalDate.now() + ":" + PerceptionMonitorFireInfo.TABLE_NAME + ":" + appId + ":" + platformCode + ":" + tagCode);
        Integer count = (Integer) parametersTagCache.get("received_count");

        if (Objects.nonNull(count) && count > 0) {
            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 = fireParametersTagStrategy.redisTemplate.boundHashOps(LocalDate.now() + ":" + PerceptionMonitorFireInfo.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 = fireParametersTagStrategy.redisTemplate.boundHashOps(LocalDate.now() + ":" + PerceptionMonitorFireInfo.TABLE_NAME + ":" + appId + ":" + platformCode + ":" + tagCode);
        Integer count = (Integer) parametersTagCache.get("received_count");

        if (Objects.nonNull(count) && count > 0) {
            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.FireParametersTag]
     * @Return: void
     * @Author: vincent.zhao
     * @Date: 2024/6/21 15:14
     */
    private void add(FireParametersTag fireParametersTag) {
        List<FireParametersTag> tempList = fireParametersTagStrategy.fireParametersTagService.list(Wrappers.lambdaQuery(FireParametersTag.class)
                .eq(FireParametersTag::getAppId, fireParametersTag.getAppId())
                .eq(FireParametersTag::getOriginId, fireParametersTag.getOriginId()));

        // 新增指标
        if (!CollectionUtil.isNotEmpty(tempList)) {
            // TODO: 2024/8/22 启用
            addTag(fireParametersTag.getAppId(), fireParametersTag.getPlatformCode(), fireParametersTag.getTagCode());
        }

        log.info("fireParametersTagStrategy 进行add操作 ......");
        fireParametersTagStrategy.fireParametersTagService.saveOrUpdate(fireParametersTag,
                Wrappers.lambdaQuery(FireParametersTag.class)
                        .eq(FireParametersTag::getAppId, fireParametersTag.getAppId())
                        .eq(FireParametersTag::getOriginId, fireParametersTag.getOriginId()));

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

    }

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

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

    /**
     * @Description: 删除
     * @Param: [com.lutao.entity.FireParametersTag]
     * @Return: void
     * @Author: vincent.zhao
     * @Date: 2024/6/20 16:01
     */
    private void del(FireParametersTag fireParametersTag) {
        log.info("fireParametersTagStrategy 进行del操作 .......");
        fireParametersTagStrategy.fireParametersTagService.remove(Wrappers.lambdaQuery(FireParametersTag.class)
                .eq(FireParametersTag::getAppId, fireParametersTag.getAppId())
                .eq(FireParametersTag::getOriginId, fireParametersTag.getOriginId()));

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


}
