package com.eactive.eai.rms.onl.manage.rule.layout;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Properties;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.StreamSupport;

import com.eactive.eai.rms.common.util.PoiUtils;
import com.eactive.eai.rms.onl.manage.rule.layout.ui.*;
import org.apache.commons.lang.WordUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.math.NumberUtils;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.ss.util.RegionUtil;
import org.apache.poi.xssf.usermodel.XSSFCellStyle;
import org.apache.poi.xssf.usermodel.XSSFColor;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.eactive.eai.data.entity.onl.message.ServiceMessageEntity;
import com.eactive.eai.data.entity.onl.transformer.layout.LayoutEntity;
import com.eactive.eai.data.entity.onl.transformer.layout.LayoutItemEntity;
import com.eactive.eai.data.entity.onl.transformer.layout.LayoutItemEntityId;
import com.eactive.eai.data.entity.onl.transformer.transform.TransformTypeEntity;
import com.eactive.eai.data.entity.onl.unifbwk.UnifBwkTp;
import com.eactive.eai.rms.common.acl.user.BizDao;
import com.eactive.eai.rms.common.base.OnlBaseService;
import com.eactive.eai.rms.common.combo.ComboService;
import com.eactive.eai.rms.common.combo.ComboVo;
import com.eactive.eai.rms.common.context.MonitoringContext;
import com.eactive.eai.rms.common.datasource.DataSourceContextHolder;
import com.eactive.eai.rms.common.datasource.DataSourceType;
import com.eactive.eai.rms.data.entity.onl.eaimsg.ServiceMessageService;
import com.eactive.eai.rms.data.entity.onl.layout.LayoutItemService;
import com.eactive.eai.rms.data.entity.onl.layout.LayoutService;
import com.eactive.eai.rms.data.entity.onl.transform.TransformTypeService;
import com.eactive.eai.rms.data.entity.onl.unifbwk.UnifBwkTpService;
import com.eactive.eai.rms.onl.common.exception.BizException;
import com.eactive.eai.rms.onl.common.util.FileWriteUtil;
import com.eactive.eai.rms.onl.loader.service.TransactionLoaderService;
import com.eactive.eai.rms.onl.manage.rule.layout.mapper.LayoutUIMapper;
import com.eactive.eai.rms.onl.manage.rule.layout.ui.LayoutEffect;
import com.eactive.eai.rms.onl.manage.rule.layout.ui.LayoutUI;
import com.eactive.eai.rms.onl.manage.rule.layout.ui.LayoutUISearch;
import com.eactive.eai.rms.onl.manage.rule.upload.IoMapLoaderKey;
import com.eactive.eai.rms.onl.transaction.vo.UserBzwkDstcd;
import com.eactive.eai.transformer.layout.Item;
import com.eactive.eai.transformer.layout.Types;
import com.eactive.eai.transformer.util.ConstantUtil;
import org.springframework.web.multipart.MultipartFile;

@Service
@Transactional
public class LayoutManService extends OnlBaseService {

	@Autowired
	private MonitoringContext monitoringContext;

	@Autowired
	@Qualifier("layoutDao")
	private LayoutDao dao;

	@Autowired
	@Qualifier("bizDao")
	private BizDao bizDao;

	@Autowired
	@Qualifier("loaderService")
	private TransactionLoaderService loaderService;

	@Autowired
	private LayoutService layoutService;

	@Autowired
	private LayoutUIMapper layoutUIMapper;

	@Autowired
	private UnifBwkTpService unifBwkTpService;

	@Autowired
	private ComboService comboService;

	@Autowired
	private TransformTypeService transformTypeService;

	@Autowired
	private ServiceMessageService serviceMessageService;

	@Autowired
	private LayoutItemService layoutItemService;

	public Page<LayoutUI> selectList(Pageable pageable, LayoutUISearch layoutUISearch) {

		// page 조회
		Page<LayoutUI> page = layoutService.findAll(pageable, layoutUISearch).map(layoutUIMapper::toVoWithoutChild);

		// 업무구분 설정
		page.forEach(ui -> {
			Optional<UnifBwkTp> unifBwkTp = unifBwkTpService.findById(ui.getEaiBzwkDstcd());
			if (unifBwkTp.isPresent()) {
				ui.setBzwkDsticName(unifBwkTp.get().getBzwkdsticname());
			}
		});

		return page;
	}

	public List<Map<String, Object>> selectListToExcel(LayoutUISearch layoutUISearch) {

		// excel 데이터 조회
		List<Map<String, Object>> list = layoutService
				.findAll(Pageable.unpaged(), layoutUISearch)
				.stream()
				.map(layoutEntity -> {
					Map<String, Object> map = new HashMap<>();

					map.put("EAIBZWKDSTCD", layoutEntity.getEaibzwkdstcd());
					map.put("LOUTNAME", layoutEntity.getLoutname());
					map.put("LOUTDESC", layoutEntity.getLoutdesc());
					map.put("EAISEVRDSTCD", layoutEntity.getEaisevrdstcd());
					map.put("LOUTPTRNNAME", layoutEntity.getLoutptrnname());
					map.put("USEYN", layoutEntity.getUseyn());
					map.put("LASTAMNDHMS", layoutEntity.getLastamndhms());
					map.put("VERINFO", layoutEntity.getVerinfo());

					return map;
				})
				.collect(Collectors.toList());

		// 업무구분 설정
		list.forEach(map -> {
			Optional<UnifBwkTp> unifBwkTp = unifBwkTpService.findById((String) map.get("EAIBZWKDSTCD"));
			if (unifBwkTp.isPresent()) {
				map.put("BZWKDSTICNAME", unifBwkTp.get().getBzwkdsticname());
			}
		});

		return list;
	}

	public Map<String, Object> selectDetail(String loutName) {
		LayoutEntity layoutEntity = layoutService.getById(loutName);

		// layout detail 조회
		LayoutUI layoutUI = layoutUIMapper.toVo(layoutEntity);

		// layout 영향도 조회
		// 영향도 변환 조회
		Set<TransformTypeEntity> transformTypeEntities = StreamSupport
				.stream(transformTypeService.findAllByIdLayoutName(loutName).spliterator(), false)
				.collect(Collectors.toSet());

		Set<String> cnvsnNames = transformTypeEntities
				.stream()
				.map(t -> t.getId().getCnvsnname())
				.collect(Collectors.toSet());

		// 영향도 eaimessage 조회
		Set<ServiceMessageEntity> serviceMessageEntities = serviceMessageService.findByCnvsnname(cnvsnNames);

		List<LayoutEffect> layoutEffects = serviceMessageEntities.stream().map(s -> {
			LayoutEffect layoutEffect = new LayoutEffect();
			layoutEffect.setEaiSvcName(s.getId().getEaisvcname());
			layoutEffect.setEaiSvcDesc(s.getEaimessage().getEaisvcdesc());
			layoutEffect.setEaiSvcSevrDstcd(s.getEaimessage().getEaisevrdstcd());

			TransformTypeEntity transformTypeEntity = transformTypeEntities
					.stream()
					.filter(t -> StringUtils
							.equalsAny(t.getId().getCnvsnname(), s.getChngmsgidname(), s.getBascrspnschngmsgidname(),
									s.getErrrspnschngmsgidname()))
					.findFirst()
					.get();

			layoutEffect.setCnvsnName(transformTypeEntity.getTransformEntity().getCnvsnname());
			layoutEffect.setCnvsnDesc(transformTypeEntity.getTransformEntity().getCnvsndesc());
			layoutEffect.setSourcRsultDstcd(transformTypeEntity.getId().getSourcrsultdstcd());
			layoutEffect.setTranSevrDstcd(transformTypeEntity.getTransformEntity().getEaisevrdstcd());

			return layoutEffect;
		}).collect(Collectors.toList());

		Map<String, Object> result = new HashMap<>();
		result.put("detail", layoutUI);
		result.put("rows", layoutUI.getLayoutItems());
		result.put("rows2", layoutEffects);

		return result;

	}

	public void update(LayoutUI layoutUI) {
		LayoutEntity layoutEntity = layoutService.getById(layoutUI.getLoutName());
		layoutUIMapper.updateEntity(layoutUI, layoutEntity);

		LayoutItemEntity root = createRootLayoutItem(layoutUI);

		List<LayoutItemEntity> layoutItemEntities = layoutEntity.getLayoutItemEntities();
		layoutItemEntities.clear();
		layoutItemEntities.add(root);
		layoutItemEntities.addAll(createLayoutItems(layoutUI));

		layoutService.save(layoutEntity);
	}

	private LayoutItemEntity createRootLayoutItem(LayoutUI layoutUI) {
		LayoutItemEntityId id = new LayoutItemEntityId();
		id.setLoutname(layoutUI.getLoutName());
		id.setLoutitemname(layoutUI.getLoutName());
		id.setLoutitemserno(0);
		LayoutItemEntity layoutItemEntity = layoutItemService.findById(id).orElse(new LayoutItemEntity(id));

		layoutItemEntity.setLoutitemidname(1000);
		layoutItemEntity.setParntloutitemidname(0);
		layoutItemEntity.setLoutitemdesc(layoutUI.getLoutDesc());
		layoutItemEntity.setLoutitemnodeptrnidname(Item.NODE_MESSAGE);
		layoutItemEntity.setLoutitemptrnidname(Types.TYPE_UNKNOWN);
		layoutItemEntity.setLoutitempathname("");
		layoutItemEntity.setLoutitemlencnt(0);
		layoutItemEntity.setLoutitemrefinfo("");
		layoutItemEntity.setLoutitemrefinfo2("");
		layoutItemEntity.setLoutitemoccurptrndstcd("");
		layoutItemEntity.setLoutitemmaxoccurnoitm(0);
		layoutItemEntity.setLoutitemminoccurnoitm(0);
		layoutItemEntity.setLoutitembascval("");
		layoutItemEntity.setLoutitemmskyn("");
		layoutItemEntity.setLoutdptcnt(1);
		layoutItemEntity.setDecptlencnt(0);
		layoutItemEntity.setLoutitemrefptrnidname("");
		return layoutItemEntity;
	}

	public void insert(LayoutUI layoutUI) {
		LayoutEntity layoutEntity = layoutUIMapper.toEntity(layoutUI);

		LayoutItemEntity root = createRootLayoutItem(layoutUI);

		List<LayoutItemEntity> layoutItemEntities = new ArrayList<>();
		layoutItemEntities.add(root);
		layoutItemEntities.addAll(createLayoutItems(layoutUI));
		layoutEntity.setLayoutItemEntities(layoutItemEntities);

		layoutService.save(layoutEntity);
	}

	public void delete(String layoutName) {
		layoutService.deleteById(layoutName);
	}

	private List<LayoutItemEntity> createLayoutItems(LayoutUI layoutUI) {

		List<LayoutItemEntity> list = new ArrayList<>();

		setParentLayoutItemUIGridData(layoutUI);

		for (LayoutItemUI layoutItemUI : layoutUI.getLayoutItems()) {

			LayoutItemEntity item = layoutItemService
					.findOrNew(layoutUI.getLoutName(), layoutItemUI.getLoutItemName(),
							layoutItemUI.getLoutItemSerno());

			createLayoutItem(layoutUI, layoutItemUI, item);

			list.add(item);
		}

		return list;
	}

	private void createLayoutItem(LayoutUI layoutUI, LayoutItemUI layoutItemUI, LayoutItemEntity item) {
		item.setLoutitemidname(layoutItemUI.getLoutItemSerno() + 1000);
		item.setParntloutitemidname(layoutItemUI.getParentLoutItemIndex() + 1000);

		item.setLoutitemdesc(layoutItemUI.getLoutItemDesc());

		int node = getItemNodeType(layoutItemUI);
		item.setLoutitemnodeptrnidname(node);

		String loutItemType = layoutItemUI.getLoutItemType();
		int loutType = ConstantUtil
				.getDataTypeId(layoutItemUI.getLoutItemDataType(), layoutUI.getLoutPtrnName());

		item.setLoutitemptrnidname(loutType);
		item.setLoutitemlencnt(layoutItemUI.getLoutItemLength());

		item.setLoutitemrefinfo2(layoutItemUI.getLoutItemOccRef());

		setItemOccurs(layoutItemUI, item, loutItemType);

		item.setLoutitembascval(layoutItemUI.getLoutItemDefault());
		item.setLoutitemmskyn(layoutItemUI.getLoutItemMaskYn());

		if ("Y".equals(layoutItemUI.getLoutItemMaskYn())) {
			item.setLoutitemmasklength(layoutItemUI.getLoutItemMaskLength());
			item.setLoutitemmaskoffset(layoutItemUI.getLoutItemMaskOffset());
		} else {
			item.setLoutitemmasklength(layoutItemUI.getLoutItemMaskLength());
		}

		int depth = layoutItemUI.getLoutItemDepth() == 0 ? 1 : layoutItemUI.getLoutItemDepth();
		item.setLoutdptcnt(depth + 1);
		item.setDecptlencnt(layoutItemUI.getLoutItemDecimal());

		if (StringUtils.equals(layoutItemUI.getLoutItemDataType(), "Int")) {
			item.setLoutitemrefptrnidname("Integer");
		}

		if (node != Item.NODE_GROUP) {
			String dataType = layoutItemUI.getLoutItemDataType();
			if ("Int".equals(dataType)) {
				dataType = "Integer";
			}
			item.setLoutitemrefptrnidname(dataType);
		}

	}

	private void setItemOccurs(LayoutItemUI layoutItemUI, LayoutItemEntity item, String loutItemType) {
		String occurNoitm = determineOccurNoItem(layoutItemUI, loutItemType);

		int max = 0;
		int min = 0;
		if (String.valueOf(Item.OCC_MULTI_OR_NONE).equals(occurNoitm)) { // *
			max = -1;
		} else if (String.valueOf(Item.OCC_ONCE_OR_NONE).equals(occurNoitm)) { // ?
			max = 1;
		} else if (String.valueOf(Item.OCC_MULTI_OR_ONCE).equals(occurNoitm)) { // +
			min = 1;
			max = -1;
		} else if ("".equals(occurNoitm)) {
			min = 1;
			max = 1;
		} else if (occurNoitm.matches("[0-9]+")) {
			min = StringUtils.isNotEmpty(item.getLoutitemrefinfo2()) ? 0 : Integer.parseInt(occurNoitm);
			max = Integer.parseInt(occurNoitm);
		}

		if (max == 0 && min == 0) {
			if ("GRID".equalsIgnoreCase(loutItemType) || "ARRAY".equalsIgnoreCase(loutItemType)) {
				min = 1;
				max = -1;
			} else {
				min = 1;
				max = 1;
			}
		}

		if ("0".equals(occurNoitm)) {
			occurNoitm = "";
		}

		item.setLoutitemoccurptrndstcd(occurNoitm);
		item.setLoutitemmaxoccurnoitm(max);
		item.setLoutitemminoccurnoitm(min);
	}

	private String determineOccurNoItem(LayoutItemUI layoutItemUI, String loutItemType) {
		if (("GRID".equalsIgnoreCase(loutItemType) || "ARRAY".equalsIgnoreCase(loutItemType))
				&& NumberUtils.toInt(layoutItemUI.getLoutItemOccCnt()) == 0) {
			return "*";
		}
		return String.valueOf(layoutItemUI.getLoutItemOccCnt());
	}

	private int getItemNodeType(LayoutItemUI el) {
		int node = 0;
		if ("GROUP".equalsIgnoreCase(el.getLoutItemType())) {
			node = Item.NODE_GROUP;
		} else if ("GRID".equalsIgnoreCase(el.getLoutItemType())) {
			node = Item.NODE_GROUP;
		} else if ("ATTR".equalsIgnoreCase(el.getLoutItemType())) {
			node = Item.NODE_ATTR;
		} else if ("ARRAY".equalsIgnoreCase(el.getLoutItemType())) {
			node = Item.NODE_FIELD;
		} else {
			node = Item.NODE_FIELD;
		}
		return node;
	}

	private void setParentLayoutItemUIGridData(LayoutUI layoutUI) {

		Map<Integer, LayoutItemUI> lastItemOfDepth = new HashMap<>();

		for (LayoutItemUI current : layoutUI.getLayoutItems()) {
			// 현재 아이템보다 depth가 작은 마지막 Grid 타입 아이템을 부모로 설정
			for (int i = current.getLoutItemDepth() - 1; i >= 0; i--) {
				if (lastItemOfDepth.containsKey(i)) {
					current.setParentLoutItemIndex(lastItemOfDepth.get(i).getLoutItemSerno());
					break;
				}
			}

			// 현재 아이템이 Grid 타입이면, 해당 depth의 마지막 아이템으로 등록
			if (StringUtils.equalsAnyIgnoreCase(current.getLoutItemType(), "GRID", "GROUP")) {
				lastItemOfDepth.put(current.getLoutItemDepth(), current);
			}
		}
	}

	public Map<String, Object> selectDetailCombo() {
		// 업무구분
		List<ComboVo> listBiz = comboService.getFromUserBusiness();

		// 전문레이아웃 유형명
		List<ComboVo> listType = comboService.getFromLayoutType();

		HashMap<String, Object> map = new HashMap<>();

		map.put("bizList", listBiz);
		map.put("typeList", listType);

		return map;
	}

	public HashMap selectListPop(int startNum, int endNum, HashMap<String, Object> paramMap) throws Exception {

		// 전체 목록수 얻기
		int totalCount = dao.selectListCountPop(paramMap);

		paramMap.put("startNum", startNum);// 시작 record
		paramMap.put("endNum", endNum);// 끝 record

		List list = dao.selectListPop(paramMap);

		HashMap map = new HashMap();

		map.put("totalCount", totalCount);

		map.put("list", list);

		return map;
	}

	public List<UserBzwkDstcd> selectUserBzwkDstch(String userId) {

		List<UnifBwkTp> unifBwkTps = unifBwkTpService.findAll();
		List<UserBzwkDstcd> bzwkDstcdzs = new ArrayList<>();

		unifBwkTps.forEach(u -> {
			UserBzwkDstcd bzwkDstcd = new UserBzwkDstcd();
			bzwkDstcd.setEaiBzwkDstcd(u.getEaibzwkdstcd());
			bzwkDstcd.setGroupCoCd(u.getGroupcocd());
			bzwkDstcdzs.add(bzwkDstcd);
		});

		return bzwkDstcdzs;
	}

	public void exportData(HashMap param) throws Exception {
		// String eaiBzwkDstCd, String userId, String cmId, String[] arrLayoutNames
		String eaiBzwkDstCd = (String) param.get("eaiBzwkDstCd");
		String userId = (String) param.get("userId");
		String cmId = (String) param.get("cmId");
		String loutNames = (String) param.get("loutNames");
		String[] arrLayoutNames = loutNames.split("\\,");

		Properties prop = monitoringContext.getProperties();

		if (prop == null || prop.size() == 0) {
			throw new Exception("프라퍼티 정보가 없습니다. - CM_CONFIG");
		}

		String auroraIni = (String) prop
				.getProperty(MonitoringContext.CM_AURORA_INI_PATH, "/fshome/greai/eaiadm/aurora/auroraApi_config.ini");
		String localPath = (String) prop.getProperty(MonitoringContext.CM_AURORA_TMP_PATH, "/fslog/eai/cmtemp/");
		String rootPath = localPath + eaiBzwkDstCd.toLowerCase() + File.separator + cmId + File.separator;
		List<String> cmList = new ArrayList<String>();
		for (String layoutName : arrLayoutNames) {
			Optional<LayoutEntity> optional = layoutService.findById(layoutName);

			if (!optional.isPresent()) {
				logger.error("returned listTR07 is null : layoutName=" + layoutName);
				continue;
			}

			LayoutEntity layoutEntity = optional.get();
			String eaiSevrDstcd = layoutEntity.getEaisevrdstcd();
			String eaiSevrName = IoMapLoaderKey.getEaiSevrName(eaiSevrDstcd);

			if ("ALL".equals(eaiSevrName)) {
				for (String sevr : IoMapLoaderKey.getAllEaiSevrName()) {
					eaiSevrName = sevr;
					String subPath = eaiSevrName + File.separator + FileWriteUtil.LAYOUT + File.separator;
					String path = rootPath + subPath;

					DataSourceType dt = DataSourceContextHolder.getDataSourceType();
					try {
						loaderService.layoutDownLoading(dt, path, layoutName);
						File f = new File(path + layoutName + FileWriteUtil.EXT_TXT);
						if (f.exists()) {
							cmList.add(path + layoutName + FileWriteUtil.EXT_TXT);
						}
					} catch (Exception e) {
						throw new BizException("파일 생성에 실패하였습니다. CM 파일 목록이 없습니다.");
					}
				}
			} else {
				String subPath = eaiSevrName + File.separator + FileWriteUtil.LAYOUT + File.separator;
				String path = rootPath + subPath;

				DataSourceType dt = DataSourceContextHolder.getDataSourceType();
				try {
					loaderService.layoutDownLoading(dt, path, layoutName);
					File f = new File(path + layoutName + FileWriteUtil.EXT_TXT);
					if (f.exists()) {
						cmList.add(path + layoutName + FileWriteUtil.EXT_TXT);
					}
				} catch (Exception e) {
					throw new BizException("파일 생성에 실패하였습니다. CM 파일 목록이 없습니다.");
				}
			}

		}
		if (cmList == null || cmList.size() == 0) {
			throw new BizException("파일 생성에 실패하였습니다. CM 파일 목록이 없습니다.");
		}

		String groupCoCd = bizDao.selectGroupCoCdByEAIBzwkDstCd(new HashMap() {
			{
				put("eaiBzwkDstCd", eaiBzwkDstCd);
			}
		});
//
//	        AuroraUtil aurora = new AuroraUtil(auroraIni,rootPath);
//
//			boolean isSuccess = aurora.addCMResource(userId, groupCoCd, eaiBzwkDstCd, cmId, cmList);
//			if (!isSuccess) {
//				throw new BizException("전송에 실패하였습니다.");
//			}

	}

	public List<HashMap> selectLayout(String loutName) {
		HashMap params = new HashMap();
		params.put("loutName", loutName);
		return dao.selectLayout(params);
	}



	// 병합된 셀의 테두리를 설정하는 메서드
	private void setBorderForMergedRegion(Sheet sheet, CellRangeAddress range, BorderStyle borderStyle) {
		RegionUtil.setBorderBottom(borderStyle, range, sheet);
		RegionUtil.setBorderTop(borderStyle, range, sheet);
		RegionUtil.setBorderLeft(borderStyle, range, sheet);
		RegionUtil.setBorderRight(borderStyle, range, sheet);
	}

	private int createLayoutForm(LayoutUI layout, Sheet sheet, Workbook workbook) {
		int height = 25;
		// 헤더 스타일 생성 및 설정
		CellStyle headerStyle = PoiUtils.createHeaderCellStyle(workbook);

		// 텍스트 스타일 생성 및 설정
		CellStyle textStyle = PoiUtils.createTextCellStyle(workbook);

		// 필드 이름
		String[] fieldNames = {
				"타입", "레이아웃 명", "레이아웃 설명", "레이아웃 유형 명", "업무구분명(코드)",
				"서버구분코드", "작성자", "사용여부(Y/N)"
		};
		String useYn = "1".equals(layout.getUseYn()) ? "Y" : "N" ;
		// LayoutUI 객체의 각 속성 값
		String[] fieldValues = {
				"LAYOUT", layout.getLoutName(), layout.getLoutDesc(), layout.getLoutPtrnName(),
				layout.getEaiBzwkDstcd(), layout.getEaiSevrDstcd(), layout.getAuthor(),
				useYn
		};

		int rowNum = 0;
		rowNum = addTitle(sheet, rowNum, PoiUtils.createTitleCellStyle(workbook), "기본 설정");
		for (int i = 0; i < fieldNames.length; i += 2) {
			Row row = sheet.createRow(rowNum++);
			row.setHeightInPoints(height); // 행 높이를 20 포인트로 설정
			int cellIndex = 0; // 초기 셀 인덱스

			for (int j = 0; j < 2 && (i + j) < fieldNames.length; j++) {
				Cell headerCell = row.createCell(cellIndex);
				headerCell.setCellValue(fieldNames[i + j]);
				headerCell.setCellStyle(headerStyle);
				CellRangeAddress mergedRegion = new CellRangeAddress(rowNum - 1, rowNum - 1, cellIndex, cellIndex + 1);
				sheet.addMergedRegion(mergedRegion);
				setBorderForMergedRegion(sheet, mergedRegion, BorderStyle.THIN);
				cellIndex += 2; // 열병합으로 인해 인덱스 조정

				Cell valueCell = row.createCell(cellIndex);
				valueCell.setCellValue(fieldValues[i + j]);
				valueCell.setCellStyle(textStyle);
				CellRangeAddress valueMergedRegion = new CellRangeAddress(rowNum - 1, rowNum - 1, cellIndex, cellIndex + 4);
				sheet.addMergedRegion(valueMergedRegion);
				setBorderForMergedRegion(sheet, valueMergedRegion, BorderStyle.THIN);
				cellIndex += 5; // 다음 셀 위치로 인덱스 조정
			}
		}

		return rowNum; // 생성된 마지막 행 번호 반환
	}


	private void createItemsTable(List<LayoutItemUI> items, Sheet sheet, Workbook workbook, int startRow) {
		int height = 25;

		CellStyle headerStyle = PoiUtils.createHeaderCellStyle(workbook);
		CellStyle dataStyle = PoiUtils.createTextCellStyle(workbook);
		if (workbook instanceof XSSFWorkbook) {
			XSSFCellStyle xssfHeaderStyle = (XSSFCellStyle) headerStyle;
			// 연두색 파스텔 톤으로 배경색 설정
			xssfHeaderStyle.setFillForegroundColor(new XSSFColor(new java.awt.Color(204, 255, 204)));
			xssfHeaderStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND);
		} else if (workbook instanceof HSSFWorkbook) {
			// HSSFWorkbook의 경우 IndexedColors를 사용 (가장 가까운 색상 선택)
			headerStyle.setFillForegroundColor(IndexedColors.LIGHT_GREEN.getIndex());
			headerStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND);
		}

		String[] headers = {
				"일련번호",
				"항목명",
				"항목설명",
				"깊이",
				"아이템유형",
				"반복횟수",
				"반복참조필드",
				"데이터타입",
				"데이터길이",
				"소수점길이",
				"기본값",
				"마스크여부(Y/N)",
				"마스킹위치",
				"마스크길이"
		};

		int rowNum = addTitle(sheet, ++startRow, PoiUtils.createTitleCellStyle(workbook), "레이아웃 항목");
		Row headerRow = sheet.createRow(rowNum++);
		headerRow.setHeightInPoints(height); // 행 높이를 20 포인트로 설정
		for (int i = 0; i < headers.length; i++) {
			Cell cell = headerRow.createCell(i);
			cell.setCellValue(headers[i]);
			cell.setCellStyle(headerStyle);
		}

		for (int i = 1; i < items.size(); i++) {
			LayoutItemUI item = items.get(i);
			Row row = sheet.createRow(rowNum++);
			row.setHeightInPoints(height); // 행 높이를 20 포인트로 설정
			int ci = 0;

			row.createCell(ci++).setCellValue(item.getLoutItemSerno());	//	항목일련번호
			row.createCell(ci++).setCellValue(item.getLoutItemName());	//	항목명
			row.createCell(ci++).setCellValue(item.getLoutItemDesc());	//	항목설명
			row.createCell(ci++).setCellValue(item.getLoutItemDepth());	//	깊이
			row.createCell(ci++).setCellValue(item.getLoutItemType());	//	아이템유형
			row.createCell(ci++).setCellValue(item.getLoutItemOccCnt());	//	반복횟수
			row.createCell(ci++).setCellValue(item.getLoutItemOccRef());	//	반복참조필드
			row.createCell(ci++).setCellValue(item.getLoutItemDataType());	//	데이터타입
			row.createCell(ci++).setCellValue(item.getLoutItemLength());	//	데이터길이
			row.createCell(ci++).setCellValue(item.getLoutItemDecimal());	//	소수점길이
			row.createCell(ci++).setCellValue(item.getLoutItemDefault());	//	항목기본값
			row.createCell(ci++).setCellValue(item.getLoutItemMaskYn());	//	항목마스크여부
			row.createCell(ci++).setCellValue(item.getLoutItemMaskOffset());	//	마스킹위치
			row.createCell(ci++).setCellValue(item.getLoutItemMaskLength());	//	마스크길이

			for (int index = 0; index < headers.length; index++) {
				Cell cell = row.getCell(index, Row.MissingCellPolicy.CREATE_NULL_AS_BLANK);
				cell.setCellStyle(dataStyle);
			}
		}

		int ci = 0;
		sheet.setColumnWidth(ci++, 72 * 30);//	항목일련번호
		sheet.setColumnWidth(ci++, 200 * 30);//	항목명
		sheet.setColumnWidth(ci++, 200 * 30);//	항목설명
		sheet.setColumnWidth(ci++, 42 * 30);//	깊이
		sheet.setColumnWidth(ci++, 90 * 30);//	아이템유형
		sheet.setColumnWidth(ci++, 90 * 30);//	반복횟수
		sheet.setColumnWidth(ci++, 200 * 30);//	반복참조필드
		sheet.setColumnWidth(ci++, 100 * 30);//	데이터타입
		sheet.setColumnWidth(ci++, 90 * 30);//	데이터길이
		sheet.setColumnWidth(ci++, 90 * 30);//	소수점길이
		sheet.setColumnWidth(ci++, 150 * 30);//	기본값
		sheet.setColumnWidth(ci++, 110 * 30);//	마스크여부
		sheet.setColumnWidth(ci++, 90 * 30);//	마스킹위치
		sheet.setColumnWidth(ci++, 90 * 30);//	마스크길이
	}

	private int addTitle(Sheet sheet, int rowNum, CellStyle titleStyle, String title) {
		Row row = sheet.createRow(rowNum++);
		row.setHeightInPoints(30); // 행 높이를 20 포인트로 설정
		createCell(row, 0, titleStyle, title);
		CellRangeAddress mergedRegion = new CellRangeAddress(rowNum - 1, rowNum - 1, 0, 1);
		sheet.addMergedRegion(mergedRegion);
		setBorderForMergedRegion(sheet, mergedRegion, BorderStyle.THIN);
		return rowNum;
	}

	private void createCell(Row row, int cellIndex, CellStyle cellStyle, String value){
		Cell cell = row.createCell(cellIndex);
		cell.setCellValue(value);
		cell.setCellStyle(cellStyle);
	}

	public byte[] exportLayoutToExcel(String loutName) throws IOException {
		LayoutEntity layoutEntity = layoutService.getById(loutName);
		LayoutUI layoutUI = layoutUIMapper.toVo(layoutEntity);

		try (Workbook workbook = new XSSFWorkbook()) {
			addLayoutExcelSheet(layoutUI, workbook, layoutUI.getLoutName());

			try (ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream()) {
				workbook.write(byteArrayOutputStream);
				return byteArrayOutputStream.toByteArray();
			}
		}
	}

	public void addLayoutExcelSheet(String loutName, Workbook workbook, String sheetName) throws IOException {
		LayoutEntity layoutEntity = layoutService.getById(loutName);
		LayoutUI layoutUI = layoutUIMapper.toVo(layoutEntity);
		addLayoutExcelSheet(layoutUI, workbook, sheetName);
	}

	public void addLayoutExcelSheet(LayoutUI layoutUI, Workbook workbook, String sheetName) throws IOException {
		Sheet sheet = workbook.createSheet(sheetName);
		// 먼저 LayoutUI 정보를 시트 상단에 배치
		int currentRow = createLayoutForm(layoutUI, sheet, workbook);
		// LayoutItemUI 목록을 바로 아래에 표 형태로 배치
		createItemsTable(layoutUI.getLayoutItems(), sheet, workbook, currentRow);
	}

	public LayoutUI importLayoutExcelSheet(Sheet sheet){
		String layoutName = PoiUtils.getCellValue(sheet, 1, 9);
		String layoutDesc = PoiUtils.getCellValue(sheet, 2, 2);

		String layoutType = PoiUtils.getCellValue(sheet, 2, 9);
		String bizCode = PoiUtils.getCellValue(sheet, 3, 2);

		String systemType = PoiUtils.getCellValue(sheet, 3, 9);
		String author = PoiUtils.getCellValue(sheet, 4, 2);

		String useYn = "Y".equals(PoiUtils.getCellValue(sheet, 4, 9)) ? "1" : "0";

		LayoutUI layoutUI = new LayoutUI();
		layoutUI.setLoutName(layoutName);
		layoutUI.setLoutDesc(layoutDesc);
		layoutUI.setLoutPtrnName(layoutType);
		layoutUI.setEaiBzwkDstcd(bizCode);
		layoutUI.setEaiSevrDstcd(systemType);
		layoutUI.setUseYn(useYn);
		layoutUI.setAuthor(author);

		List<LayoutItemUI> layoutItemUiList = new ArrayList<>();
		layoutUI.setLayoutItems(layoutItemUiList);

		// 시트의 마지막 행까지 반복
		for (int rowIndex = 8; rowIndex <= sheet.getLastRowNum(); rowIndex++) {
			Row row = sheet.getRow(rowIndex);
			if(row == null) continue;

			LayoutItemUI layoutItemUI = new LayoutItemUI();
			layoutItemUiList.add(layoutItemUI);
			int idx = PoiUtils.convertCellToInt(row.getCell(0)); //index
			layoutItemUI.setId(idx);
			layoutItemUI.setLoutItemSerno(idx);

			layoutItemUI.setLoutItemName(row.getCell(1).getStringCellValue()); //항목명
			layoutItemUI.setLoutItemDesc(row.getCell(2).getStringCellValue()); //항목설명
			layoutItemUI.setLoutItemDepth(PoiUtils.convertCellToInt(row.getCell(3))); //깊이

			String itemType = WordUtils.capitalizeFully(row.getCell(4).getStringCellValue()); //아이템유형
			layoutItemUI.setLoutItemType(itemType);
			layoutItemUI.setLoutItemOccCnt(String.valueOf(PoiUtils.convertCellToInt(row.getCell(5)))); //반복횟수
			layoutItemUI.setLoutItemOccRef(row.getCell(6).getStringCellValue()); //반복참조필드
			layoutItemUI.setLoutItemDataType(row.getCell(7).getStringCellValue()); //데이터타입
			layoutItemUI.setLoutItemLength(PoiUtils.convertCellToInt(row.getCell(8))); //데이터길이
			layoutItemUI.setLoutItemDecimal(PoiUtils.convertCellToInt(row.getCell(9))); //소수점길이
			layoutItemUI.setLoutItemDefault(row.getCell(10).getStringCellValue()); //기본값
			layoutItemUI.setLoutItemMaskYn(row.getCell(11).getStringCellValue()); //마스크여부(Y/N)
			layoutItemUI.setLoutItemMaskOffset(PoiUtils.convertCellToInt(row.getCell(12)));//마스킹위치
			layoutItemUI.setLoutItemMaskOffset(PoiUtils.convertCellToInt(row.getCell(13)));//마스킹위치
		}

		importLayoutUi(layoutUI);

		return layoutUI;
	}

	public void importLayoutUi(LayoutUI layoutUI) {
		String layoutName = layoutUI.getLoutName();

		if(!layoutService.existsById(layoutName)){
			insert(layoutUI);
		}else{
			update(layoutUI);
		}
	}

	public void importLayoutFromExcel(MultipartFile file) throws IOException {
		if (file.isEmpty()) {
			throw new IOException("File is empty");
		}
		Workbook workbook;

		try (InputStream inputStream = file.getInputStream()) {
			workbook = new XSSFWorkbook(inputStream);
		}

		Sheet sheet = workbook.getSheetAt(0);
		importLayoutExcelSheet(sheet);
	}

	public LayoutUI getLayoutUiToExport(String layoutName){
		LayoutEntity layoutEntity = layoutService.getById(layoutName);
		LayoutUI layoutUI = layoutUIMapper.toVo(layoutEntity);
		layoutUI.getLayoutItems().remove(0);
		layoutUI.setLastamndhms(null);
		return layoutUI;
	}
}