package cn.hmsoft.frame.control;

import java.io.File;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import cn.hmsoft.application.web.Ajax;
import cn.hmsoft.frame.constants.FrameReportType;
import cn.hmsoft.frame.constants.FrameStatus;
import cn.hmsoft.frame.constants.FrameThreadCallbackType;
import cn.hmsoft.frame.constants.FrameThreadStatus;
import cn.hmsoft.frame.data.dao.FrameReportDao;
import cn.hmsoft.frame.data.model.FrameReport;
import cn.hmsoft.frame.data.model.FrameReportDetail;
import cn.hmsoft.frame.data.model.FrameThread;
import cn.hmsoft.frame.exception.BusinessException;
import cn.hmsoft.frame.service.FrameReportService;
import cn.hmsoft.frame.thread.FrameThreadHelper;
import cn.hmsoft.frame.util.FrameAssertUtil;
import cn.hmsoft.frame.util.FrameDictUtil;
import cn.hmsoft.helper.FileHelper;
import cn.hmsoft.helper.JsonHelper;
import cn.hmsoft.helper.LocalDateHelper;
import cn.hmsoft.helper.StringHelper;
import cn.hmsoft.helper.dbf.DbfHelper;
import cn.hmsoft.helper.excel.Excel2007Writer;
import cn.hmsoft.jdbc.entity.DataRecord;

@RestController
public class FrameReportControl extends FrameControl {

	@Autowired
	private FrameReportDao daoReport;
	@Autowired
	private FrameReportService sReport;

	@RequestMapping("frame/report/page")
	public Ajax page(String query, Integer limit, Integer start, String order, String type) {
		order = StringHelper.isEmpty(order) ? "report_name" : order;
		return new Ajax(this.daoReport.pageReport(start, limit, query, getQueryOrder(order, type)));
	}
	
	@RequestMapping("frame/report/add")
	public Ajax add(String report, String json_value) {
		this.authAdminRole();
		List<FrameReportDetail> detailArr = JsonHelper.fromJson(json_value, FrameReportDetail.class);
		List<FrameReport> reportArr = JsonHelper.fromJson(report, FrameReport.class);
		if(reportArr != null && reportArr.size() > 0) {
			this.sReport.addReport(reportArr.get(0), detailArr);
		} else {
			throw new BusinessException("请至少填写一条报表字段！");
		}
		return new Ajax(report);
	}
	@RequestMapping("frame/report/edit")
	public Ajax edit(String report, String json_value) {
		this.authAdminRole();
		FrameAssertUtil.isNotNull(json_value, "请至少填写一条报表字段！");
		List<FrameReportDetail> detailArr = JsonHelper.fromJson(json_value, FrameReportDetail.class);
		List<FrameReport> reportArr = JsonHelper.fromJson(report, FrameReport.class);
		if(reportArr != null && reportArr.size() > 0) {
			this.sReport.editReport(reportArr.get(0), detailArr);
		} else {
			throw new BusinessException("请至少填写一条报表字段！");
		}
		return new Ajax();
	}

	
	@RequestMapping("frame/report/delete")
	public Ajax delete(final String report_name) {
		this.authAdminRole();
		this.sReport.deleteReport(report_name);
		return new Ajax();
	}

	/********************
	 * 下载报表
	 */
	@RequestMapping("frame/report/download")
	public void downloadReport(String report_name, String report_title, HttpServletRequest request) {
		FrameReport report = this.daoReport.find(report_name);
		if (report == null) {
			this.writeAlert("未找到指定的报表，请联系系统管理员！");
			return;
		}

		// 判断权限
		if (report.getRes_id() != null) {
			try {
				this.authOptrRole(report.getRes_id());
			} catch (Exception e) {
				this.writeAlert("鉴权失败，请联系系统管理员！");
				return;
			}
		}

		List<FrameReportDetail> fieldArray = new ArrayList<FrameReportDetail>();
		for (FrameReportDetail r : this.daoReport.listDetail(report_name)) {
			if (FrameStatus.Active.toString().equals(r.getField_status()))
				fieldArray.add(r);
		}
		if (fieldArray.size() == 0) {
			this.writeAlert("未找到该报表的配置信息，请联系系统管理员！");
			return;
		}

		List<Map<String, Object>> vMap = null;
		// 获取参数
		List<Object> params = null;
		if (StringHelper.isNotEmpty(report.getReport_param())) {
			// 参数名称：类型：InActive, 表示可以为空
			List<DataRecord> paramArray = new ArrayList<DataRecord>();
			for (String value : report.getReport_param().trim().split("\r\n")) {
				DataRecord param = new DataRecord();
				String[] array = value.split(":");
				param.setS01(array[0].trim());
				if (array.length > 1) {
					param.setS02(array[1]);
				}
				if (array.length > 2) {
					param.setS03(array[2]);
				}
				paramArray.add(param);
			}
			// params = new Object[paramArray.size()];
			params = new ArrayList<Object>();
			for (int i = 0; i < paramArray.size(); i++) {
				DataRecord dr = paramArray.get(i);
				// String v = dr.getS01().replace("?", "");
				String requestValue = request.getParameter(dr.getS01().replace("?", ""));
				Object paramValue = requestValue;

				if ("LocalDateTime".equals(dr.getS02())) {
					// 需要转换
					paramValue = LocalDateHelper.parseDateTime(requestValue);
				} else if ("LocalDate".equals(dr.getS02())) {
					// 需要转换
					paramValue = LocalDateHelper.parseDate(requestValue);
				}
				if (StringHelper.isEmpty(requestValue)) {
					// 如果允许为空
					if (dr.getS01().endsWith("?")) {
						params.add(null);
						params.add(1);
					} else {
						this.writeAlert("参数丢失，无法下载报表，请联系系统管理员！");
						return;
					}

				} else {
					params.add(paramValue);
					// 不为空
					if (dr.getS01().endsWith("?")) {
						params.add(2);
					}
				}
			}

		}

		try {
			if (params == null || params.size() == 0)
				vMap = this.daoReport.listMapBySql(report.getReport_sql());
			else
				vMap = this.daoReport.listMapBySql(params.toArray(new Object[0]), report.getReport_sql());

			// 生成报表
		} catch (Exception e) {
			e.printStackTrace();
			this.writeAlert("报表配置错误，请联系系统管理员！");
			return;
		}

		Map<String, Integer> titleMap = new LinkedHashMap<String, Integer>();
		// 需要序号
		if (FrameStatus.Active.toString().equals(report.getIndex_flag()))
			titleMap.put("#", vMap.size() > 10000 ? 10 : (vMap.size() > 1000 ? 8 : 5));
		for (FrameReportDetail f : fieldArray) {
			// 增加列
			titleMap.put(f.getField_text(), f.getField_length() == null ? 10 : f.getField_length());
		}

		List<List<Object>> values = new ArrayList<List<Object>>();
		// 添加值
		int index = 1;
		for (Map<String, Object> map : vMap) {
			List<Object> array = new ArrayList<Object>();
			if (FrameStatus.Active.toString().equals(report.getIndex_flag()))
				array.add(index++);
			for (FrameReportDetail f : fieldArray) {
				String field_name = f.getField_name().toLowerCase();
				if (map.containsKey(field_name)) {
					Object value = map.get(field_name);
					if (value == null)
						array.add(null);
					else {
						if ("LocalDateTime".equals(f.getField_date_type())) {
							array.add(
									LocalDateHelper.format(LocalDateHelper.fromTimestamp((java.sql.Timestamp) value)));
						} else if ("LocalDate".equals(f.getField_date_type())) {
							array.add(LocalDateHelper
									.format(LocalDateHelper.fromTimestamp((java.sql.Timestamp) value).toLocalDate()));
						} else if ("HourMinute".equals(f.getField_date_type())) {
							array.add(LocalDateHelper.format(LocalDateHelper.fromTimestamp((java.sql.Timestamp) value),
									LocalDateHelper.HourMinuteFormatter));

						} else if (StringHelper.isNotEmpty(f.getDict_name())) {
							array.add(FrameDictUtil.getFrameDictText(f.getDict_name(), value.toString()));
						} else
							array.add(value);

					}
				} else
					array.add(null);
			}
			values.add(array);
		}
		String file_name = (report_title == null ? "系统报表" : report_title);
		if ("LocalDateTime".equals(report.getReport_suffix()))
			file_name = file_name + "-" + LocalDateHelper.formatLongNoSplit(LocalDateTime.now());
		else if ("LocalDate".equals(report.getReport_suffix()))
			file_name = file_name + "-" + LocalDateHelper.formatNoSplit(LocalDate.now());
		else if ("LocalTime".equals(report.getReport_suffix()))
			file_name = file_name + "-" + LocalDateHelper.formatNoSplit(LocalDate.now());
		else if ("Year".equals(report.getReport_suffix()))
			file_name = file_name + "-" + LocalDate.now().getYear();
		if (FrameReportType.DBF.equalsIgnoreCase(report.getReport_type())) {
			file_name = file_name + ".dbf";
			File file = FileHelper.createWebTempFile();
			DbfHelper.saveAsDbf(file, values, titleMap);
			this.downloadFile(file, file_name, true);
		} else
			Excel2007Writer.downloadAsExcel(this.getResponse(), file_name, values, titleMap);

	}

	/********************
	 * 下载报表
	 */
	@RequestMapping("frame/report/download/thread")
	public Ajax downloadReportThread(String report_name, String report_title, HttpServletRequest request) {
		FrameReport report = this.daoReport.find(report_name);
		if (report == null) {
			throw new BusinessException("未找到该报表配置文件");
		}

		// 判断权限
		if (report.getRes_id() != null) {
			try {
				this.authOptrRole(report.getRes_id());
			} catch (Exception e) {
				throw new BusinessException("鉴权失败，请联系系统管理员");
			}
		}

		List<FrameReportDetail> fieldArray = new ArrayList<FrameReportDetail>();
		for (FrameReportDetail r : this.daoReport.listDetail(report_name)) {
			if (FrameStatus.Active.toString().equals(r.getField_status()))
				fieldArray.add(r);
		}
		if (fieldArray.size() == 0) {
			throw new BusinessException("未找到该报表的配置信息，请联系系统管理员");
		}

		String file_name = (report_title == null ? "系统报表" : report_title);
		if ("LocalDateTime".equals(report.getReport_suffix()))
			file_name = file_name + "-" + LocalDateHelper.formatLongNoSplit(LocalDateTime.now());
		else if ("LocalDate".equals(report.getReport_suffix()))
			file_name = file_name + "-" + LocalDateHelper.formatNoSplit(LocalDate.now());
		else if ("LocalTime".equals(report.getReport_suffix()))
			file_name = file_name + "-" + LocalDateHelper.formatNoSplit(LocalDate.now());
		else if ("Year".equals(report.getReport_suffix()))
			file_name = file_name + "-" + LocalDate.now().getYear();
		File tempFile = FrameThreadHelper.generateTempFile();
		file_name = file_name + ".xlsx";
		// 线程模式
		FrameThread thread = FrameThreadHelper.createThread("报表下载", "报表开始处理......", FrameThreadCallbackType.Download,
				FrameThreadHelper.generateDownloadParam(tempFile, file_name), this.getFrameOptr());
		// new Thread().start();
		new Thread(() -> {
			// this.sMaterial.makeWriteSeat(thread, tempFile, group, param, pageModel,
			// true);
			try {
				List<Map<String, Object>> vMap = null;
				// 获取参数
				List<Object> params = null;
				if (StringHelper.isNotEmpty(report.getReport_param())) {
					// 参数名称：类型：InActive, 表示可以为空
					List<DataRecord> paramArray = new ArrayList<DataRecord>();
					for (String value : report.getReport_param().trim().split("\r\n")) {
						DataRecord param = new DataRecord();
						String[] array = value.split(":");
						param.setS01(array[0].trim());
						if (array.length > 1) {
							param.setS02(array[1]);
						}
						if (array.length > 2) {
							param.setS03(array[2]);
						}
						paramArray.add(param);
					}
					// params = new Object[paramArray.size()];
					params = new ArrayList<Object>();
					for (int i = 0; i < paramArray.size(); i++) {
						DataRecord dr = paramArray.get(i);
						String requestValue = request.getParameter(dr.getS01().replace("?", ""));
						Object paramValue = requestValue;

						if ("LocalDateTime".equals(dr.getS02())) {
							// 需要转换
							paramValue = LocalDateHelper.parseDateTime(requestValue);
						} else if ("LocalDate".equals(dr.getS02())) {
							// 需要转换
							paramValue = LocalDateHelper.parseDate(requestValue);
						}
						if (StringHelper.isEmpty(requestValue)) {
							// 如果允许为空
							if (dr.getS01().endsWith("?")) {
								params.add(null);
								params.add(1);
							} else {
								this.writeAlert("参数丢失，无法下载报表，请联系系统管理员！");
								return;
							}

						} else {
							params.add(paramValue);
							// 不为空
							if (dr.getS01().endsWith("?")) {
								params.add(2);
							}
						}
					}

				}

				try {
					if (params == null || params.size() == 0)
						vMap = this.daoReport.listMapBySql(report.getReport_sql());
					else
						vMap = this.daoReport.listMapBySql(params.toArray(new Object[0]), report.getReport_sql());
					// 生成报表
				} catch (Exception e) {
					e.printStackTrace();
					this.writeAlert("报表配置错误，请联系系统管理员！");
					return;
				}

				FrameThreadHelper.updateThread(thread, 10, "一共有【" + vMap.size() + "】条数据", FrameThreadStatus.Running);
				Map<String, Integer> titleMap = new LinkedHashMap<String, Integer>();
				// 需要序号
				if (FrameStatus.Active.toString().equals(report.getIndex_flag()))
					titleMap.put("#", vMap.size() > 10000 ? 10 : (vMap.size() > 1000 ? 8 : 5));
				for (FrameReportDetail f : fieldArray) {
					// 增加列
					titleMap.put(f.getField_text(), f.getField_length() == null ? 10 : f.getField_length());
				}

				List<List<Object>> values = new ArrayList<List<Object>>();
				// 添加值
				int index = 1;
				for (Map<String, Object> map : vMap) {
					List<Object> array = new ArrayList<Object>();
					if (FrameStatus.Active.toString().equals(report.getIndex_flag()))
						array.add(index++);
					for (FrameReportDetail f : fieldArray) {
						String field_name = f.getField_name().toLowerCase();
						if (map.containsKey(field_name)) {
							Object value = map.get(field_name);
							if (value == null)
								array.add(null);
							else {
								if ("LocalDateTime".equals(f.getField_date_type())) {
									array.add(LocalDateHelper
											.format(LocalDateHelper.fromTimestamp((java.sql.Timestamp) value)));
								} else if ("LocalDate".equals(f.getField_date_type())) {
									array.add(LocalDateHelper.format(
											LocalDateHelper.fromTimestamp((java.sql.Timestamp) value).toLocalDate()));
								} else if ("HourMinute".equals(f.getField_date_type())) {
									array.add(LocalDateHelper.format(
											LocalDateHelper.fromTimestamp((java.sql.Timestamp) value),
											LocalDateHelper.HourMinuteFormatter));

								} else if (StringHelper.isNotEmpty(f.getDict_name())) {
									array.add(FrameDictUtil.getFrameDictText(f.getDict_name(), value.toString()));
								} else
									array.add(value);

							}
						} else
							array.add(null);
					}
					values.add(array);
					if (index % 1000 == 0) {
						FrameThreadHelper.updateThread(thread, index * 100 / vMap.size() - 30, "已添加【" + index + "】条数据",
								FrameThreadStatus.Running);
					}

				}

				// 生成报表
				FrameThreadHelper.updateThread(thread, 80, "正在生成Excel文件......", FrameThreadStatus.Running);
				Excel2007Writer.saveAsExcel(tempFile, values, titleMap);
				try {
					Thread.sleep(10000);
				}catch(Exception e) {
					
				}
				FrameThreadHelper.completeThread(thread, "Excel文件完成");
			} catch (Exception e) {
				e.printStackTrace();
				FrameThreadHelper.completeThread(thread, "报表配置错误，请联系系统管理员", FrameThreadStatus.Error);
				this.writeAlert("报表配置错误，请联系系统管理员！");
				return;
			}

		}).start();

		return new Ajax(thread);

	}
	
	@RequestMapping("frame/report/detail/list")
	public Ajax listDetail(final String report_name) {
		this.authAdminRole();
		return new Ajax(this.daoReport.listDetail(report_name));
	}
	
	
	
	
}
