/**
 * 
 */
package org.springblade.etl.service.bi;

import cn.hutool.core.date.DateUtil;
import com.alibaba.druid.util.JdbcUtils;
import com.alibaba.fastjson2.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.springblade.core.tool.utils.Func;
import org.springblade.datasource.constants.CubeConstants;
import org.springblade.datasource.enums.DetailColumnTypeEnum;
import org.springblade.datasource.support.DynamicDataSourceSupport;
import org.springblade.etl.dto.DataApiInsertParamDTO;
import org.springblade.etl.entity.bi.ReportDatasource;
import org.springframework.stereotype.Service;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.Timestamp;
import java.util.Date;
import java.util.List;
import java.util.stream.IntStream;
import java.util.stream.Stream;

/**
 * @author wookvn
 *
 */
@Slf4j
@Service
public class DataApiInsertService  {

	/**
	 * 批量入库
	 * @param ds
	 * @throws Exception
	 */
	public void batchSave(ReportDatasource ds, String tableName, DataApiInsertParamDTO[] paramArray, List<JSONObject> dataList) {
		PreparedStatement psStatement = null;
		Connection connection = null;
		try {
			String insertSql = _buildInsertSql(tableName, paramArray);
			connection = DynamicDataSourceSupport.createConnection(ds);//dynamicRoutingDataSource.getConnection();
			psStatement = connection.prepareStatement(insertSql);
			connection.setAutoCommit(false);
			long startTime = System.currentTimeMillis();
			int size = dataList.size();
			int i = 1;
			for(JSONObject dataMap : dataList) {
				for(int j = 0; j < paramArray.length; j ++) {
					int index = j + 1;
					DataApiInsertParamDTO paramDTO = paramArray[j];
					String value = Func.toStr(dataMap.get(paramDTO.getParamName()));
					if(paramDTO.getColumnType() == DetailColumnTypeEnum.DATETIME) {
						java.sql.Timestamp dateValue = null;
						try {
							Date date = DateUtil.parse(value, CubeConstants.DATE_FORMAT_PATTERNS);
							dateValue = new Timestamp(date.getTime());
						} catch (Exception e) {}
						psStatement.setTimestamp(index, dateValue);
					}
					if(paramDTO.getColumnType() == DetailColumnTypeEnum.INT) {
						try {
							value = value.replaceAll(CubeConstants.NUMBER_FORAMT_PATTERNS, "");
							psStatement.setInt(index, Func.toInt(value, 0));
						} catch (Exception e) {
							psStatement.setInt(index, 0);
						}
					}
					if(paramDTO.getColumnType() == DetailColumnTypeEnum.LONG) {
						try {
							value = value.replaceAll(CubeConstants.NUMBER_FORAMT_PATTERNS, "");
							psStatement.setLong(index, Func.toLong(value, 0L));
						} catch (Exception e) {
							psStatement.setLong(index, 0L);
						}
					}
					if(paramDTO.getColumnType() == DetailColumnTypeEnum.FLT) {
						try {
							value = value.replaceAll(CubeConstants.NUMBER_FORAMT_PATTERNS, "");
							psStatement.setFloat(index, Func.toFloat(value, 0F));
						} catch (Exception e) {
							psStatement.setFloat(index, 0F);
						}
					}else{
						psStatement.setString(index, value);
					}
				}
				psStatement.addBatch();
				//达到批量入库的条数,开始入库操作
				if(i % ds.getDsTypeSyl().getBatchSize() == 0 || i == size) {
					log.info("数据建批完成|size:{}, cost:{}ms", i, System.currentTimeMillis() - startTime);
					psStatement.executeBatch();
					connection.commit();
					psStatement.clearBatch();
				}
				i++;
			}
			long endTime = System.currentTimeMillis();
			log.info("批量入库成功|dataSize:{}, cost:{}ms", dataList.size(), endTime - startTime);
		} catch(Exception e) {
			throw new RuntimeException(e.getMessage(), e);
		} finally {
			JdbcUtils.close(psStatement);
			JdbcUtils.close(connection);
		}
	}
	
	private String _buildInsertSql(String tableName, DataApiInsertParamDTO[] paramArray) {
		// 字段
		StringBuilder preFieldSql = new StringBuilder("(");
		Stream.of(paramArray).map(DataApiInsertParamDTO::getColumnName).forEach(f -> preFieldSql.append(f).append(","));
		preFieldSql.deleteCharAt(preFieldSql.length() - 1).append(")");

		// 数值占位符
		StringBuilder preValueSql = new StringBuilder("(");
		IntStream.range(0, paramArray.length).forEach(f -> preValueSql.append("?,"));
		preValueSql.deleteCharAt(preValueSql.length() - 1).append(")");
		return String.format(CubeConstants.INSERT_INTO_SQL_FORMAT, tableName, preFieldSql.toString(),
				preValueSql.toString());
	}
}
