package com.style24.core.biz.service;

import com.gagaframework.web.parameter.GagaMap;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.openxml4j.opc.OPCPackage;
import org.apache.poi.poifs.filesystem.POIFSFileSystem;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.ss.util.NumberToTextConverter;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.io.FileInputStream;
import java.text.FieldPosition;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collection;

/**
 * 엑셀 Service
 *
 * @author yujung
 * @since 2021. 10. 13
 */
@Service
@Slf4j
public class TscExcelService {

	/**
	 * 엑셀
	 * @author yujung
	 * @since 2021. 10. 13
	 */
	public Collection<GagaMap> getExcelList(String excelFile, int headerPosition, String[] cellName, int sheetIndex) throws Exception {

		Workbook wb = null;
		String extension = getFileExtension(excelFile);
		if (extension.equals("xls")) {
			POIFSFileSystem fs = new POIFSFileSystem(new FileInputStream(excelFile));
			wb = new HSSFWorkbook(fs);
		} else if (extension.equals("xlsx")) {
			wb = new XSSFWorkbook(OPCPackage.open(new FileInputStream(excelFile)));
		}

		Sheet sheet = getSheetSplitMergedCell((Workbook)wb, sheetIndex);
		int rows = sheet.getLastRowNum() + 1;
		log.debug("rows: {}", rows);
		if (rows == 0) {
			throw new IllegalStateException("엑셀 파일에 데이터가 없습니다.");
		} else {
			Row row = sheet.getRow(headerPosition++);
			int cells = row.getPhysicalNumberOfCells();
			log.debug("cells: {}, cellName.length: {}", cells, cellName.length);
			if (cells != cellName.length) {
				throw new IllegalStateException("컬럼의 개수와 제목의 개수가 일치하지 않습니다.");
			} else {
				Collection<GagaMap> dataList = new ArrayList();

				for(int r = headerPosition; r < rows; ++r) {
					int comVal = 0;
					GagaMap dataMap = new GagaMap();
					row = sheet.getRow(r);
					if (row != null) {
						for(int idx = 0; idx < cells; ++idx) {
							if (row.getCell(idx) != null && !StringUtils.isEmpty(row.getCell(idx).toString())) {
								dataMap.put(cellName[idx], getCellDataByType(row.getCell(idx)));
							} else {
								++comVal;
							}

							if (comVal == cells) {
								return dataList;
							}
						}

						log.debug("dataMap: {}", dataMap.toString());
						dataList.add(dataMap);
					}
				}

				return dataList;
			}
		}
	}

	private static String getFileExtension(String fileName) {
		int lastDot = fileName.lastIndexOf(46);
		String extension = lastDot != -1 ? fileName.substring(lastDot + 1) : "";
		return extension.toLowerCase();
	}

	private static Sheet getSheetSplitMergedCell(Workbook wb, int sheetIndex) {
		Sheet sheet = wb.getSheetAt(sheetIndex);
		Cell cValue = null;

		for(int x = 0; x < sheet.getNumMergedRegions(); ++x) {
			CellRangeAddress cra = sheet.getMergedRegion(x);
			if (cra.getLastColumn() - cra.getFirstColumn() == 0 && cra.getLastRow() - cra.getFirstRow() > 0) {
				cValue = sheet.getRow(cra.getFirstRow()).getCell(cra.getFirstColumn());
				String value = null;
				cValue.getCellTypeEnum();
				if (!CellType.STRING.equals(CellType.STRING)) {
					break;
				}

				value = sheet.getRow(cra.getFirstRow()).getCell(cra.getFirstColumn()).getStringCellValue();
				int columnIndex = cra.getFirstColumn();

				for(int i = cra.getFirstRow() + 1; i <= cra.getLastRow(); ++i) {
					sheet.getRow(i).getCell(columnIndex).getCellTypeEnum();
					if (CellType.BLANK.equals(CellType.BLANK)) {
						sheet.getRow(i).getCell(columnIndex).setCellValue(value);
					}
				}
			}
		}

		return sheet;
	}

	private static Object getCellDataByType(Cell cell) throws Exception {
		Object value = null;
		CellType cellType = cell.getCellTypeEnum();
		if (cellType.equals(CellType.STRING)) {
			value = cell.getStringCellValue().trim();
		} else if (cellType.equals(CellType.FORMULA)) {
			value = cell.getCellFormula();
		} else if (cellType.equals(CellType.NUMERIC)) {
			if (DateUtil.isCellDateFormatted(cell)) {
				StringBuffer toAppendTo = new StringBuffer();
				(new SimpleDateFormat("yyyyMMdd")).format(cell.getDateCellValue(), toAppendTo, new FieldPosition(0));
				value = toAppendTo.toString();
			} else {
				value = NumberToTextConverter.toText(cell.getNumericCellValue());
			}
		} else if (cellType.equals(CellType.BOOLEAN)) {
			value = cell.getBooleanCellValue();
		} else if (cellType.equals(CellType.ERROR)) {
			value = cell.getErrorCellValue();
		} else if (cellType.equals(CellType.BLANK)) {
			value = "";
		}

		return value;
	}
	
}
