/**
 * CommonExcelView.java
 *
 * @author AllForLand Dong-Kew, Kim
 * @created 2014. 7. 3.
 */
package incheon.res.com.excel.web;

import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.WorkbookUtil;
import org.egovframe.rte.psl.dataaccess.util.EgovMap;
import org.springframework.web.servlet.view.document.AbstractXlsxView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.*;

public class CommonExcelView extends AbstractXlsxView {

	@Override
	protected void buildExcelDocument(Map<String, Object> model,
									  Workbook wb,
									  HttpServletRequest request,
									  HttpServletResponse response) throws Exception {

		// 파일명: 타이틀 기반 + 타임스탬프
		String excelTitle = (String) model.getOrDefault("excelTitle", "export");
		String timestamp = String.valueOf(System.currentTimeMillis());
		/*String filename = excelTitle + "_" + timestamp + ".xlsx";*/
		String filename = excelTitle + ".xlsx";

		// 컨텐츠 타입/헤더
		response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
		String encoded = URLEncoder.encode(filename, StandardCharsets.UTF_8.name()).replaceAll("\\+", "%20");
		response.setHeader("Content-Disposition",
				"attachment; filename=\"" + encoded + "\"; filename*=UTF-8''" + encoded);

		// 보조 타이틀
		String excelTitle2 = "아래 데이터는 " + excelTitle + " 데이터로서 목록에서 조회된 데이터 개수와 차이날 수 있습니다.";
		String excelTitle3 = (String) model.get("excelTitle3");
		String excelTitle4 = (String) model.get("excelTitle4");

		int startListIdx = 2; // 기본은 타이틀 한 줄(0) + 데이터는 2행부터
		if (excelTitle2 != null) startListIdx++;
		if (excelTitle3 != null) startListIdx++;
		if (excelTitle4 != null) startListIdx++;

		// 스타일 약간만
		CellStyle headerStyle = wb.createCellStyle();
		Font headerFont = wb.createFont();
		headerFont.setBold(true);
		headerStyle.setFont(headerFont);
		headerStyle.setWrapText(false);

		CellStyle titleStyle = wb.createCellStyle();
		Font titleFont = wb.createFont();
		titleFont.setBold(true);
		titleFont.setFontHeightInPoints((short) 12);
		titleStyle.setFont(titleFont);

		CellStyle descStyle = wb.createCellStyle();
		Font descFont = wb.createFont();
		descFont.setColor(IndexedColors.RED.getIndex());
		descFont.setBold(true);
		descStyle.setFont(descFont);

		String statsFlag = (String) model.get("statsFlag");
		if ("Y".equals(statsFlag)) {
			// 통계: statsResultList (List<List<String>>) 그대로 렌더링
			@SuppressWarnings("unchecked")
			ArrayList<ArrayList<String>> statsResultList =
					(ArrayList<ArrayList<String>>) model.get("statsResultList");

			Sheet sheet = wb.createSheet(safeSheetName(excelTitle, null));
			sheet.setDefaultColumnWidth(12);

			int rowIdx = 0;
			setCell(sheet, rowIdx++, 0, excelTitle, titleStyle);

			// 데이터는 2행부터
			rowIdx = 2;
			for (ArrayList<String> row : statsResultList) {
				Row r = sheet.createRow(rowIdx++);
				for (int c = 0; c < row.size(); c++) {
					setCell(r, c, safe(row.get(c)), null);
				}
			}

		} else {
			// 일반: resultList + cellValue
			@SuppressWarnings("unchecked")
			List<EgovMap> excelVo = (List<EgovMap>) model.get("resultList");

			@SuppressWarnings("unchecked")
			LinkedHashMap<String, String> cellValue =
					(LinkedHashMap<String, String>) model.get("cellValue");

			final int MAX_PER_SHEET = 5000;
			int total = excelVo == null ? 0 : excelVo.size();
			int sheetCount = (total == 0) ? 1 : ((total - 1) / MAX_PER_SHEET + 1);

			for (int s = 0; s < sheetCount; s++) {
				Sheet sheet = wb.createSheet(safeSheetName(excelTitle, s + 1));
				sheet.setDefaultColumnWidth(12);

				int rowIdx = 0;
				setCell(sheet, rowIdx++, 0, excelTitle, titleStyle);
				if (excelTitle2 != null) setCell(sheet, rowIdx++, 0, excelTitle2, descStyle);
				if (excelTitle3 != null) setCell(sheet, rowIdx++, 0, excelTitle3, null);
				if (excelTitle4 != null) setCell(sheet, rowIdx++, 0, excelTitle4, null);

				// 헤더
				Row header = sheet.createRow(startListIdx - 1);
				int col = 0;
				for (String headerText : cellValue.keySet()) {
					setCell(header, col++, headerText, headerStyle);
				}

				// 바디
				int from = s * MAX_PER_SHEET;
				int to = Math.min(total, from + MAX_PER_SHEET);
				int dataRow = startListIdx;

				for (int i = from; i < to; i++) {
					EgovMap map = excelVo.get(i);
					Row r = sheet.createRow(dataRow++);
					int c = 0;
					for (Map.Entry<String, String> entry : cellValue.entrySet()) {
						String keyOfMap = entry.getValue();
						String value = safe(String.valueOf(map.get(keyOfMap)));
						setCell(r, c++, value, null);
					}
				}
			}
		}
	}

	// 시트명 생성 헬퍼 (번호 붙는 경우 길이 31 보장)
	private static String safeSheetName(String title, Integer idx) {
		String base = WorkbookUtil.createSafeSheetName(
				Optional.ofNullable(title).orElse("Sheet")
		); // 금지문자/작은따옴표 처리 + 필요시 따옴표 제거

		String suffix = (idx == null) ? "" : String.valueOf(idx);
		int max = 31 - suffix.length();
		if (max < 1) { // 극단 케이스 방지
			base = "S";
		} else if (base.length() > max) {
			base = base.substring(0, max);
		}
		return base + suffix;
	}

	private static void setCell(Sheet sheet, int row, int col, String value, CellStyle style) {
		Row r = sheet.getRow(row);
		if (r == null) r = sheet.createRow(row);
		setCell(r, col, value, style);
	}

	private static void setCell(Row row, int col, String value, CellStyle style) {
		Cell cell = row.createCell(col, CellType.STRING);
		cell.setCellValue(value == null ? "" : value);
		if (style != null) cell.setCellStyle(style);
	}

	private static String safe(String s) {
		if (s == null || "null".equalsIgnoreCase(s)) return "";
		return s;
	}
}
