package com.yida.data.system.collect;

import com.yida.data.common.core.entity.constant.CachePrefixConstant;
import com.yida.data.common.core.entity.system.Log;
import com.yida.data.system.constant.LogConstant;
import com.yida.data.system.constant.PoolConstant;
import com.yida.data.system.service.LogService;

import org.springframework.util.CollectionUtils;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.SynchronousQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

import cc.mrbird.febs.common.redis.service.RedisService;
import lombok.extern.slf4j.Slf4j;

/**
 * redis日志收集类
 *
 * @author ZYJ
 * @date 2021/1/18
 */
@Slf4j
public class RedisLogCollect {

    private final RedisService redisService;
    private final LogService logService;
    private final ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
            PoolConstant.CORE_POOL_SIZE, PoolConstant.MAXIMUM_POOL_SIZE,
            PoolConstant.KEEP_ALIVE_TIME, TimeUnit.SECONDS,
            new SynchronousQueue<>());

    public RedisLogCollect(RedisService redisService, LogService logService) {
        this.redisService = redisService;
        this.logService = logService;
    }

    /**
     * 开启redis数据收集
     *
     * @author ZYJ
     * @date 2021/1/18 10:39
     */
    public void redisServerStart() {
        threadPoolExecutor.execute(this::collectOperationLog);
        log.info("RedisLogCollect启动成功！");
    }

    /**
     * 收集操作日志
     *
     * @author ZYJ
     * @date 2021/1/18 11:11
     */
    @SuppressWarnings({"InfiniteLoopStatement", "BusyWait"})
    private void collectOperationLog() {
        while (true) {
            //操作日志数据集合
            List<Log> systemLogInfoList = new ArrayList<>();
            try {
                Thread.sleep(LogConstant.MAX_INTERVAL);
            } catch (Exception e) {
                log.error("线程休眠失败: {}", e.getMessage(), e);
            }
            try {
                //从redis获取操作数据集合
                systemLogInfoList = getLogList(CachePrefixConstant.OPERATION_LOG_LIST, LogConstant.MAX_SEND_SIZE);
                if (!CollectionUtils.isEmpty(systemLogInfoList)) {
                    //调用es保存方法
                    logService.saveLogList(systemLogInfoList);
                }
            } catch (Exception e) {
                log.error("从redis队列拉取日志失败: {}", e.getMessage(), e);
                if (!CollectionUtils.isEmpty(systemLogInfoList)) {
                    //错误时将日志数据存入redis
                    redisService.lSet(CachePrefixConstant.OPERATION_LOG_LIST, systemLogInfoList);
                }
            }
        }
    }

    private List<Log> getLogList(String key, int size) {
        List<Log> list = new ArrayList<>();

        try {
            //判断集合长度
            long redisSize = redisService.lGetListSize(key);
            if (redisSize < size) {
                size = Math.toIntExact(redisSize);
            }
            if (size == 0) {
                return list;
            }
            //获取数据
            for (int i = 1; i <= size; i++) {
                //删除redis数据
                Object object = redisService.lLeftPop(key);
                if (object != null) {
                    Log systemLogInfo = (Log) object;
                    list.add(systemLogInfo);
                }
            }
        } catch (Exception e) {
            log.error("获取redis集合数据失败: {}", e.getMessage(), e);
        }
        return list;
    }
}
