package com.artfess.sysConfig.service.impl;

import com.artfess.base.constants.TenantConstant;
import com.artfess.base.context.BaseContext;
import com.artfess.base.util.BeanUtils;
import com.artfess.base.util.JsonUtil;
import com.artfess.base.util.StringUtil;
import com.artfess.sysConfig.persistence.manager.SysLogsManager;
import com.artfess.sysConfig.persistence.model.SysLogs;
import com.artfess.sysConfig.service.SysLogsBatchService;
import com.fasterxml.jackson.databind.node.ObjectNode;
import io.jsonwebtoken.lang.Assert;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextClosedEvent;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Service
public class SysLogsBatchServiceImpl implements SysLogsBatchService, ApplicationListener<ContextClosedEvent>{
	private static final Map<String, List<SysLogs>> map = new HashMap<>();

	@Value("${system.batch.max-size:500}")
	private Integer maxSize;
	@Value("${system.batch.max-time:30}")
	private int maxTime;
	// 上一次写入库的时间
	private long lastWriteTime = 0L;

	@Resource
	SysLogsManager sysLogsManager;
	@Resource
	BaseContext baseContext;

	// 按照租户ID分组存放
	private void push(String tenantId, SysLogs sysLogs) {
		List<SysLogs> list = null;
		if(!map.containsKey(tenantId)) {
			list = new ArrayList<>();
			map.put(tenantId, list);
		}
		list = map.get(tenantId);
		list.add(sysLogs);
	}

	// 数量是否超限
	private boolean countOver() {
		int [] count = new int[1];
		map.forEach((key, list) -> {
			count[0] += list.size();
		});
		return count[0] > maxSize;
	}

	// 时间是否超期
	private boolean timeExpire() {
		long now = System.currentTimeMillis();
		if(lastWriteTime == 0L) {
			lastWriteTime = now;
			return false;
		}
		return (now - lastWriteTime) > maxTime * 1000;
	}

	@Override
	public void reader(ObjectNode objectNode) throws Exception {
		SysLogs sysLogs = JsonUtil.toBean(objectNode, SysLogs.class);
		Assert.isTrue(BeanUtils.isNotEmpty(sysLogs), "记录日志时出错，日志数据序列化时失败。");
		String tenantId = JsonUtil.getString(objectNode, "tenantId");
		if(StringUtil.isEmpty(tenantId)) {
			tenantId = TenantConstant.PLATFORM_TENANT_ID;
		}
		push(tenantId, sysLogs);
		process();
	}

	@Override
	public void process() {
		// 待插入记录超限 或者 最大等待时间到期 时 写入数据库
		if(countOver() || timeExpire()) {
			write();
		}
	}

	public void write() {
		// 刷新最后一次写入时间
		lastWriteTime = System.currentTimeMillis();
		map.forEach((key, list) -> {
			if(list.size() > 0) {
				try {
					baseContext.setTempTenantId(key);
					sysLogsManager.saveBatch(list);
				}
				finally {
					// 出错时也抛弃这些日志，避免错误的日志数据导致反复出错。
					list.clear();
				}
			}
		});
	}

	@Override
	public void onApplicationEvent(ContextClosedEvent event) {
		write();
	}
}
