package org.springblade.flow.datalog.common;

import java.io.File;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

import org.springblade.bi.client.model.PageModel;
import org.springblade.flow.datalog.enums.DataExportTaskStatus;
import org.springblade.flow.datalog.model.DataExportTask;
import org.springblade.flow.datalog.service.DataExportTaskService;
import org.springblade.flow.util.JsonUtil;
import org.springblade.flow.visual.base.entity.VisualdevEntity;
import org.springblade.flow.visual.base.service.VisualdevService;
import org.springblade.flow.visual.onlinedev.formdata.opt.FormDataWithTableService;
import org.springblade.flow.visual.onlinedev.formdata.relation.RelationField;
import org.springblade.flow.visual.onlinedev.model.PaginationModel;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.converters.longconverter.LongStringConverter;
import com.alibaba.excel.util.FileUtils;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import lombok.extern.slf4j.Slf4j;

/**
 * 处理导出表单数据的任务
 * 
 * @author William
 * @date 2022年12月2日 下午1:43:17
 */
@Slf4j
@Service
public class ExportService {
	private final static int PAGE_SIZE = 5000;

	@Value("${blade.file.formDir}")
	private String formDir;

	@Autowired
	private DataExportTaskService dataExportTaskService;

	@Autowired
	private FormDataWithTableService formDataWithTableService;

	@Autowired
	private VisualdevService visualdevService;

	final ExecutorService threadPool = new ThreadPoolExecutor(1, 2, 5, TimeUnit.MINUTES,
			// 有界队列5000，超过队列长度，无异常抛弃
			new ArrayBlockingQueue<>(5000), new ThreadFactory() {
				@Override
				public Thread newThread(Runnable r) {
					Thread thread = new Thread(r);
					thread.setDaemon(false);
					thread.setName("ExportFormData-Pool-");
					return thread;
				}
			}, new ThreadPoolExecutor.DiscardPolicy());

	public void excute(DataExportTask task) {
		threadPool.execute(() -> {
			log.info("ExportService::exporting... task id is " + task.getId());
			long start = System.currentTimeMillis();
			File excelFile = new File(getFilePath(task.getFileName()));
			ExcelWriter excelWriter = EasyExcel.write(excelFile)
					.registerConverter(new LongStringConverter())
					.head(buidlHeader(task))
					.build();
			String error = handle(excelWriter, task);
			if (StrUtil.isBlankIfStr(error)) {
				task.setStatus(DataExportTaskStatus.success.getCode());
				log.info("ExportService::export success, task id is " + task.getId());
			} else {
				task.setStatus(DataExportTaskStatus.failure.getCode());
				log.info("ExportService::export failure, task id is " + task.getId());
				deleteCache(task);
			}
			if (excelWriter != null) {
				excelWriter.finish();
			}
			long end = System.currentTimeMillis();
			float takeUpTime = (end - start) / 1000.f;
			task.setExt(error);
			task.setFinishTime(new Date());
			task.setTakeUpTime(BigDecimal.valueOf(takeUpTime));
			dataExportTaskService.saveOrUpdate(task);
			log.info("ExportService::export task take up time is " + takeUpTime + "second");

		});
	}

	private String handle(ExcelWriter excelWriter, DataExportTask task) {
		String error = null;
		try {
			File excelFile = new File(getFilePath(task.getFileName()));
			VisualdevEntity form = visualdevService.getInfo(task.getModelId());
			// 已经查寻的数量
			long total = 0;
			long page = 1;
			while (true) {
				if (total >= 1000000) {
					// 受excel限制最多导出100万条数据
					break;
				}
				PaginationModel pagination = new PaginationModel();
				pagination.setCurrentPage(page);
				pagination.setPageSize(PAGE_SIZE);
				PageModel<JSONObject> pageData = formDataWithTableService.listPage(form, pagination);
				if (pageData != null && CollUtil.isNotEmpty(pageData.getRecords())) {
					// 有数据
					page = pageData.getCurrent() + 1;
					List<JSONObject> dataList = pageData.getRecords();
					total += dataList.size();
					error = writeToExcel(excelWriter, task, dataList);
					if (StrUtil.isBlankIfStr(error)) {
						// 写入excel成功
					} else {
						// 写入excel失败
						break;
					}
				} else {
					// 数据查询完毕
					break;
				}
			}
			task.setFileSize(excelFile.length());
			task.setCount(total);
		} catch (Exception e) {
			error = e.getMessage();
		}
		return error;
	}

	private String writeToExcel(ExcelWriter excelWriter, DataExportTask task,
			List<JSONObject> retList) {
		try {
			List<List<Object>> excelList = new ArrayList<List<Object>>();
			List<RelationField> fieldList = JsonUtil.getJsonToList(task.getRule(), RelationField.class);
			retList.forEach(ret -> {
				List<Object> rowList = new ArrayList<Object>();
				fieldList.forEach(field -> {
					int fieldId = field.getFieldId();
					if (ret.containsKey(String.valueOf(fieldId))) {
						Object value = ret.get(String.valueOf(fieldId));
						rowList.add(value != null ? value : "");
					}
				});
				excelList.add(rowList);
			});
			excelWriter.write(excelList, EasyExcel.writerSheet(task.getName()).build());
		} catch (Exception e) {
			return e.getMessage();
		}
		return null;
	}

	/**
	 * 动态生成表头
	 */
	private List<List<String>> buidlHeader(DataExportTask task) {
		List<RelationField> fieldList = JsonUtil.getJsonToList(task.getRule(), RelationField.class);
		List<List<String>> headerList = new ArrayList<List<String>>();
		fieldList.forEach(column -> {
			List<String> head = new ArrayList<String>();
			head.add(column.getFieldName());
			headerList.add(head);
		});
		return headerList;
	}

	private void deleteCache(DataExportTask task) {
		try {
			dataExportTaskService.saveOrUpdate(task);
			// 删除导出失败的垃圾文件
			FileUtils.delete(new File(getFilePath(task.getFileName())));
		} catch (Exception e) {
			log.info("ExportService::delete cache file failure, task id is" + task.getId() + ", error is "
					+ e.getMessage());
		}
	}

	private String getFilePath(String fileName) {
		File dir = new File(formDir);
		dir.mkdirs();
		return formDir + fileName;
	}

	public static void main(String[] agrs) {
		List<List<String>> headerList = new ArrayList<List<String>>();
		List<String> header1 = new ArrayList<>();
		header1.add("h1");
		headerList.add(header1);

		List<String> header2 = new ArrayList<>();
		header2.add("h2");
		headerList.add(header2);

		List<String> header3 = new ArrayList<>();
		header3.add("h3");
		headerList.add(header3);

		List<List<Object>> excelList = new ArrayList<List<Object>>();
		List<Object> rowList = new ArrayList<Object>();
		rowList.add(1);
		rowList.add("a");
		rowList.add("bbb");
		excelList.add(rowList);

		log.info("headerList is " + JSON.toJSONString(headerList));
		log.info("excelList is " + JSON.toJSONString(excelList));

		// EasyExcel.write(excelFile.getPath()).head(headerList).sheet("模板").doWrite(excelList);
		File excelFile = new File("D://www/upload/form/test.xlsx");
		ExcelWriter excelWriter = EasyExcel.write(excelFile)
				.registerConverter(new LongStringConverter())
				.head(headerList)
				.build();
		excelWriter.write(excelList, EasyExcel.writerSheet("哈哈哈").build());
		if (excelWriter != null) {
			excelWriter.finish();
		}
	}
}
