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

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Vector;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.collections4.MapUtils;
import org.apache.commons.compress.archivers.tar.TarArchiveEntry;
import org.apache.commons.compress.archivers.tar.TarArchiveOutputStream;
import org.apache.commons.lang3.StringUtils;
import org.apache.log4j.Logger;
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.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.servlet.ModelAndView;

import com.eactive.eai.agent.command.CommonCommand;
import com.eactive.eai.agent.transformer.ReloadLayoutCommand;
import com.eactive.eai.agent.transformer.ReloadLayoutListCommand;
import com.eactive.eai.agent.transformer.RemoveLayoutCommand;
import com.eactive.eai.common.util.StringUtil;
import com.eactive.eai.common.util.SystemUtil;
import com.eactive.eai.rms.common.acl.bizKeyTran.BizKeyTranManService;
import com.eactive.eai.rms.common.acl.user.BizService;
import com.eactive.eai.rms.common.base.OnlBaseAnnotationController;
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.DataSourceType;
import com.eactive.eai.rms.common.datasource.DataSourceTypeManager;
import com.eactive.eai.rms.common.login.SessionManager;
import com.eactive.eai.rms.common.spring.LocaleMessage;
import com.eactive.eai.rms.common.util.CommonUtil;
import com.eactive.eai.rms.common.util.IpUtil;
import com.eactive.eai.rms.common.vo.GridResponse;
import com.eactive.eai.rms.common.vo.JsonPageVo;
import com.eactive.eai.rms.common.vo.SimpleResponse;
import com.eactive.eai.rms.onl.common.exception.BizException;
import com.eactive.eai.rms.onl.loader.service.HistoryService;
import com.eactive.eai.rms.onl.loader.service.TransactionLoaderService;
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.layoutsync.LayoutSyncService;
import com.eactive.eai.rms.onl.transaction.vo.UserBzwkDstcd;

@Controller
public class LayoutManController extends OnlBaseAnnotationController {

	private static final Logger logger = Logger.getLogger(LayoutManController.class);

	@Autowired
	@Qualifier("monitoringContext")
	private MonitoringContext monitoringContext;

	@Autowired
	@Qualifier("localeMessage")
	private LocaleMessage localeMessage;

	@Autowired
	private LayoutManService service;

	@Autowired
	@Qualifier("layoutSyncService")
	private LayoutSyncService layoutSyncService;

	@Autowired
	@Qualifier("bizService")
	private BizService bizService;

	@Autowired
	private ComboService comboService;

	@Autowired
	@Qualifier("bizKeyTranManService")
	private BizKeyTranManService bizKeyTranManService;

	@Autowired
	@Qualifier("historyService")
	private HistoryService historyService;

	@Autowired
	private TransactionLoaderService loaderService;

	@GetMapping(value =  "/onl/admin/rule/layoutMan.view")
	public void view() {}

	@GetMapping(value =  "/onl/admin/rule/layoutMan.view", params = "cmd=DETAIL")
	public String editableDetailView() {
		return "/onl/admin/rule/layoutManDetail";
	}
	
	@GetMapping(value =  "/onl/admin/rule/layoutMan.view", params = "cmd=POPUP")
	public String editableDetailPopup() {
		return "/onl/admin/rule/layoutManPopup";
	}


	@PostMapping(value = "/onl/admin/rule/layoutMan.json", params = "cmd=LIST")
	public ResponseEntity<GridResponse<LayoutUI>> selectList(Pageable pageable, LayoutUISearch layoutUISearch) {
		Page<LayoutUI> page = service.selectList(pageable, layoutUISearch);
		return ResponseEntity.ok(new GridResponse<LayoutUI>(page));
	}

	@PostMapping(value = "/onl/admin/rule/layoutMan.json", params = "cmd=LIST_INIT_COMBO")
	public ResponseEntity<Map<String, Object>> eaiSvcNameCombo(HttpServletRequest request,
			HttpServletResponse response) {

		List<ComboVo> listInoutTypeCd = comboService.getFromCode("INOUT_TYPE");
		List<ComboVo> listUseYn = comboService.getFromCode("USE_YN");
		List<ComboVo> listType = comboService.getFromLayoutType();

		Map<String, Object> resultMap = new HashMap<>();
		resultMap.put("inoutTypeRows", listInoutTypeCd);
		resultMap.put("useYnRows", listUseYn);
		resultMap.put("typeRows", listType);

		return ResponseEntity.ok(resultMap);
	}

	@PostMapping(value = "/onl/admin/rule/layoutMan.json", params = "cmd=DETAIL")
	public ResponseEntity<Map<String, Object>> selectDetail(String loutName) throws Exception {
		Map<String, Object> map = service.selectDetail(loutName);
		return ResponseEntity.ok(map);
	}

	@PostMapping(value = "/onl/admin/rule/layoutMan.json", params = "cmd=INSERT")
	public ResponseEntity<SimpleResponse> insert(LayoutUI layoutUi) throws Exception {
		service.insert(layoutUi);
		CommonCommand command = new CommonCommand(ReloadLayoutCommand.class.getName(), layoutUi.getLoutName());
		HashMap<String, Object> returnMap = agentUtilService.broadcast(command);

		SimpleResponse simpleResponse = SimpleResponse.of(CommonUtil.getMapString(returnMap, true));
		return ResponseEntity.ok(simpleResponse);
	}

	@PostMapping(value = "/onl/admin/rule/layoutMan.json", params = "cmd=UPDATE")
	public ResponseEntity<SimpleResponse> update(LayoutUI layoutUi) throws Exception {
		service.update(layoutUi);
		CommonCommand command = new CommonCommand(ReloadLayoutCommand.class.getName(), layoutUi.getLoutName());
		HashMap<String, Object> returnMap = agentUtilService.broadcast(command);

		SimpleResponse simpleResponse = SimpleResponse.of(CommonUtil.getMapString(returnMap, true));
		return ResponseEntity.ok(simpleResponse);
	}

	@PostMapping(value = "/onl/admin/rule/layoutMan.json", params = "cmd=DELETE")
	public ResponseEntity<SimpleResponse> delete(String loutName) throws Exception {
		service.delete(loutName);
		CommonCommand command = new CommonCommand(RemoveLayoutCommand.class.getName(), loutName);
		HashMap<String, Object> returnMap = agentUtilService.broadcast(command);

		SimpleResponse simpleResponse = SimpleResponse.of(CommonUtil.getMapString(returnMap, true));
		return ResponseEntity.ok(simpleResponse);

	}

	@PostMapping(value = "/onl/admin/rule/layoutMan.json", params = "cmd=DELETE_LIST")
	public ResponseEntity<Map<String, Object>> deleteMulti(
			@RequestParam(name = "delItems", defaultValue = "") String[] delItems) {

		int idx = 0;
		for (String delItem : delItems) {
			service.delete(delItem);
			idx++;
		}

		String message = "총" + idx + "건을 삭제하였습니다";

		Map<String, Object> resultMap = new HashMap<>();
		resultMap.put("message", message);
		return ResponseEntity.ok(resultMap);
	}

	@PostMapping(value = "/onl/admin/rule/layoutMan.json", params = "cmd=LIST_DETAIL_COMBO")
	public ResponseEntity<Map<String, Object>> selectDetailCombo() {
		Map<String, Object> map = service.selectDetailCombo();
		List<ComboVo> listUseYn = comboService.getFromCode("USE_YN");// 사용여부
		List<ComboVo> listEaiSevrCd = comboService.getFromCode("INOUT_TYPE");// EAI서버구분코드

		map.put("useYnRows", listUseYn);
		map.put("eaiSevrCdRows", listEaiSevrCd);
		return ResponseEntity.ok(map);
	}

	@PostMapping(value = "/onl/admin/rule/layoutMan.json", params = "cmd=INITIALIZES")
	public ResponseEntity<SimpleResponse> initializes() throws Exception {
		CommonCommand command = new CommonCommand(ReloadLayoutCommand.class.getName(), "ALL");
		HashMap<String, Object> returnMap = agentUtilService.broadcast(command);

		SimpleResponse simpleResponse = SimpleResponse.of(CommonUtil.getMapString(returnMap, true));
		return ResponseEntity.ok(simpleResponse);
	}

	@PostMapping(value = "/onl/admin/rule/layoutMan.json", params = "cmd=INITIALIZE")
	public ResponseEntity<SimpleResponse> initialize(String loutName) throws Exception {

		CommonCommand command = new CommonCommand(ReloadLayoutCommand.class.getName(), loutName);
		HashMap<String, Object> returnMap = agentUtilService.broadcast(command);

		SimpleResponse simpleResponse = SimpleResponse.of(CommonUtil.getMapString(returnMap, true));
		return ResponseEntity.ok(simpleResponse);
	}

	@PostMapping(value = "/onl/admin/rule/layoutMan.json", params = "cmd=LIST_INITIALIZE")
	public ResponseEntity<SimpleResponse> listInitialize(
			@RequestParam(name = "chkItems", defaultValue = "") String[] chkItemsArr) throws Exception {

		Vector<String> vec = new Vector<>();
		for (String chkItem : chkItemsArr) {
			vec.add(chkItem);
		}
		CommonCommand command = new CommonCommand(ReloadLayoutListCommand.class.getName(), vec);
		HashMap<String, Object> returnMap = agentUtilService.broadcast(command);

		SimpleResponse simpleResponse = SimpleResponse.of(CommonUtil.getMapString(returnMap, true));
		return ResponseEntity.ok(simpleResponse);
	}

	@PostMapping(value = "/onl/admin/rule/layoutMan.json", params = "cmd=LIST_POP")
	public ModelAndView selectListLayout(HttpServletRequest request, JsonPageVo pageVo,
			@RequestParam HashMap<String, Object> paramMap) throws Exception {

		HashMap map = service.selectListPop(pageVo.getStartNum(), pageVo.getEndNum(), paramMap);

		pageVo.setTotalCount((Integer) map.get("totalCount"));

		Map resultMap = new HashMap();
		resultMap.put("total", pageVo.getTotal()); // 전체 페이지수
		resultMap.put("page", pageVo.getPage()); // 현재 페이지수
		resultMap.put("records", pageVo.getTotalCount());// 전체 레코드건수
		resultMap.put("rows", map.get("list"));

		ModelAndView modelAndView = new ModelAndView("jsonView", resultMap);
		return modelAndView;
	}

	@PostMapping(value = "/onl/admin/rule/layoutMan.excel", params = "cmd=LIST_GRID_TO_EXCEL")
	public ModelAndView listGridToExcel(LayoutUISearch layoutUISearch) {
		HashMap<String, Object> resultMap = new HashMap<>();
		List<Map<String, Object>> datas = service.selectListToExcel(layoutUISearch);
		resultMap.put("datas", datas);

		return new ModelAndView("excelView", resultMap);
	}


	@PostMapping(value = "/onl/admin/rule/layoutMan.excel", params = "cmd=LIST_EXPORT_TO_EXCEL")
	public ResponseEntity<byte[]>  listExportToExcel(@RequestBody List<String> layoutIdList) throws IOException {
		if (layoutIdList.size() == 1) {
			// 단일 파일 처리
			String layoutId = layoutIdList.get(0);
			byte[] excelContentBytes = service.exportLayoutToExcel(layoutId); // Excel 파일 내용 생성 함수(가정)

			HttpHeaders headers = new HttpHeaders();
			headers.add(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + layoutId + ".xlsx\"");
			headers.add(HttpHeaders.CONTENT_TYPE, "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");

			return ResponseEntity.ok()
					.headers(headers)
					.body(excelContentBytes);
		} else if (layoutIdList.size() > 1) {
			// 여러 파일 압축 처리
			try (ByteArrayOutputStream baos = new ByteArrayOutputStream();
				 TarArchiveOutputStream taos = new TarArchiveOutputStream(baos)) {

				for (String layoutId : layoutIdList) {
					byte[] excelContentBytes = service.exportLayoutToExcel(layoutId); // Excel 파일 내용 생성 함수(가정)
					TarArchiveEntry entry = new TarArchiveEntry(layoutId + ".xlsx");
					entry.setSize(excelContentBytes.length);
					taos.putArchiveEntry(entry);
					taos.write(excelContentBytes);
					taos.closeArchiveEntry();
				}

				taos.finish();

				String firstLayoutId = layoutIdList.get(0);
				HttpHeaders headers = new HttpHeaders();
				headers.add(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + firstLayoutId + "_and_" + (layoutIdList.size() - 1) + "_more.tar\"");
				headers.add(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_OCTET_STREAM_VALUE);

				return ResponseEntity.ok()
						.headers(headers)
						.body(baos.toByteArray());
			} catch (Exception e) {
				e.printStackTrace();
				return ResponseEntity.internalServerError().body(null);
			}
		}
		return ResponseEntity.internalServerError().body(null);
	}

	@PostMapping(value = "/onl/admin/rule/layoutMan.file", params = "cmd=LIST_IMPORT_FROM_EXCEL")
	public ResponseEntity<?>  listImportFromExcel(@RequestParam("file") MultipartFile file) {
		try {
			service.importLayoutFromExcel(file);
			return ResponseEntity.ok().body("File successfully imported");
		} catch (IOException e) {
			e.printStackTrace();
			return ResponseEntity.internalServerError().body("Error processing file");
		}
	}

	@PostMapping(value = "/onl/admin/rule/layoutMan.json", params = "cmd=LIST_CM")
	public ModelAndView cmList(HttpServletRequest request, String eaiBzwkDstCd) throws Exception {
		HashMap<String, Object> resultMap = new HashMap<String, Object>();
		String userId = SessionManager.getUserId(request);
		Properties prop = monitoringContext.getProperties();
		if (!SystemUtil.isDevServer()) {
			throw new Exception("only support dev server ");
		}
		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");

		try {
			String groupCoCd = bizService.selectGroupCoCdByEAIBzwkDstCd(eaiBzwkDstCd);
//			AuroraUtil aurora = new AuroraUtil(auroraIni);
			String apCode = bizKeyTranManService.selectBizKeyForApCode(eaiBzwkDstCd);
//			List cmList = aurora.getCMList(userId, groupCoCd, apCode);
//			if (cmList == null || cmList.size() == 0) {
//				throw new BizException("해당 업무에 대한 CM 패키지가 없습니다.");
//			}
//			resultMap.put("cmList", cmList);
		} catch (BizException be) {
			throw new Exception(be.getMessage());
		} catch (Exception e) {
			logger.error(e.getMessage());
			throw new Exception(localeMessage.getString("errors.checklog"));
		}

		ModelAndView modelAndView = new ModelAndView("jsonView", resultMap);
		return modelAndView;
	}

	@PostMapping(value = "/onl/admin/rule/layoutMan.json", params = "cmd=CHANGE_EXPORT")
	public ModelAndView exportData(HttpServletRequest request, @RequestParam HashMap map) throws Exception {

		HashMap<String, Object> resultMap = new HashMap<>();
		String userId = SessionManager.getUserId(request);
		map.put("userId", userId);
		try {
			if (!SystemUtil.isDevServer()) {
				throw new Exception("only support dev server ");
			}
			if (map != null) {
				service.exportData(map);
			}
			resultMap.put("message", "전송이 성공적으로 완료되었습니다");
		} catch (BizException be) {
			throw new Exception(be.getMessage());
		} catch (Exception e) {
			logger.error(e.getMessage());
			throw new Exception(localeMessage.getString("errors.checklog"));
		}

		ModelAndView modelAndView = new ModelAndView("jsonView", resultMap);
		return modelAndView;
	}

	@PostMapping(value = "/onl/admin/rule/layoutMan.json", params = "cmd=LIST_CODE")
	public ResponseEntity<HashMap<String, Object>> codeList(HttpServletRequest request) {
		HashMap<String, Object> resultMap = new HashMap<>();
		String userId = SessionManager.getUserId(request);

		List<UserBzwkDstcd> codeList = service.selectUserBzwkDstch(userId);
		resultMap.put("codeList", codeList);
		
		return ResponseEntity.ok(resultMap);
	}

	@PostMapping(value = "/onl/admin/rule/layoutMan.json", params = "cmd=LIST_SRC")
	public ModelAndView srcList(HttpServletRequest request, String eaiBzwkDstCd, String repType, String schType,
			String desc) throws Exception {
		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");

		HashMap<String, Object> resultMap = new HashMap<String, Object>();
		// String userId = SessionManager.getUserId(request);
//		AuroraUtil aurora = new AuroraUtil(auroraIni);
		try {
			String groupCoCd = bizService.selectGroupCoCdByEAIBzwkDstCd(eaiBzwkDstCd);
			String repNamePath = StringUtils.equals(repType, "M") ? "/유지보수/" : "/개발/";
			String repKey = groupCoCd + repNamePath + (eaiBzwkDstCd != null ? eaiBzwkDstCd.trim() : "") + "/01.개발문서";
//			List<Map> cmList = aurora.getResourceVersion(groupCoCd, repKey, schType, desc);
//			resultMap.put("cmList", cmList);
			resultMap.put("repKey", repKey);
			resultMap.put("groupCoCd", groupCoCd);
		} catch (Exception e) {
			logger.error(e.getMessage());
			throw new Exception(localeMessage.getString("errors.checklog"));
		}

		ModelAndView modelAndView = new ModelAndView("jsonView", resultMap);
		return modelAndView;
	}

	@PostMapping(value = "/onl/admin/rule/layoutMan.json", params = "cmd=TRANSACTION_CMDOWN")
	public ModelAndView cmDown(HttpServletRequest request, String eaiBzwkDstCd, String srcIds, String versions,
			String fileNames) throws Exception {
		HashMap<String, Object> resultMap = new HashMap<String, Object>();
		// String userId = SessionManager.getUserId(request);

		ModelAndView modelAndView = new ModelAndView("jsonView", resultMap);
		return modelAndView;
	}

	/**
	 * 레이아웃을 XML 데이타로 가져오기
	 * 
	 * @param request
	 * @throws Exception
	 */

	@PostMapping(value = "/onl/admin/rule/layoutMan.json", params = "cmd=CLONETOPROD")
	public ModelAndView cloneToProd(HttpServletRequest request, @RequestParam HashMap<String, Object> paramMap)
			throws Exception {
		if (SystemUtil.isProdServer()) {
			throw new Exception("only support dev, stage server");
		}

		HashMap<String, Object> resultMap = new HashMap<String, Object>();
		String userId = SessionManager.getUserId(request);
		String serviceKey = SessionManager.getServiceTypeKey(request);
		String cmTitle = MapUtils.getString(paramMap, "CmTitle", "Deploy Layout");
		String cmDate = StringUtil.getNullStr(paramMap.get("CmDate"));
		String cmTime = StringUtil.getNullStr(paramMap.get("CmTime"));
		String listLoutName = StringUtil.getNullStr(paramMap.get("ListLoutName"));
		String[] eaiLoutNames = listLoutName.split("\\,");
		String downloadPath = monitoringContext.getStringProperty(MonitoringContext.IOMAP_DOWNLOAD_PATH);
		downloadPath = StringUtils.removeEnd(downloadPath, File.separator) + File.separator + serviceKey
				+ File.separator;
		String targetName = monitoringContext.getStringProperty(MonitoringContext.IOMAP_DEPLOY_TARGET_NAME);
		String targetUrl = monitoringContext.getStringProperty(MonitoringContext.IOMAP_DEPLOY_TARGET_URL);
		targetUrl = StringUtils.removeEnd(targetUrl, "/");

		String userIp = IpUtil.getClientIp(request);

		if (logger.isInfoEnabled()) {
			logger.info("-------------------------------------------");
			logger.info("userId=" + userId);
			logger.info("userIp=" + userIp);
			logger.info("serviceKey=" + serviceKey);
			logger.info("cmDate=" + cmDate);
			logger.info("cmTime=" + cmTime);
			logger.info("listLoutName=" + listLoutName);
			logger.info("downloadPath=" + downloadPath);
			logger.info("targetName=" + targetName); // 스테이징, 운영서버
			logger.info("targetUrl=" + targetUrl); // http://127.0.0.1:20100
			logger.info("-------------------------------------------");
		}

		DataSourceType dt = DataSourceTypeManager.getDataSourceType(serviceKey);
		String items = "";

		// 0. 서브 배포 목록 확보
		HashMap<String, ArrayList<HashMap<String, String>>> listMap = historyService
				.userHistoryListByLayout(dt, eaiLoutNames);

		if (listMap != null && listMap.size() > 0) {
			// 1. 파일 생성
			try {
				loaderService.makeDataFiles(dt, downloadPath, listMap);
			} catch (Exception e) {
				logger.error(e.getMessage(), e);
				throw new Exception("Make Datafile error:" + e.getMessage());
			}

			// 2. 파일 배포
			try {
				if (StringUtils.isBlank(targetUrl)) {
					throw new Exception("Set EMS property:" + MonitoringContext.IOMAP_DEPLOY_TARGET_URL);
				}

				String url = targetUrl + "/monitoring/loader.do";
				loaderService.deployDataToTargetSystem(url, downloadPath, listMap, serviceKey);
			} catch (Exception e) {
				logger.error(e.getMessage(), e);
				throw new Exception("Deploy to target System(" + targetName + ") error:" + e.getMessage());
			}

			items += historyService.parseSimple(serviceKey, "", listMap);
		}

		// 3. 데이터 적용 또는 스케쥴 등록
		try {
			String url = targetUrl + "/monitoring/loader.do";
			loaderService.scheduleDeployDataApply(url, userId, userIp, serviceKey, cmTitle, cmDate, cmTime, items);
		} catch (Exception e) {
			logger.error(e.getMessage(), e);
			throw new Exception("Apply DeployData or Apply Schedule error:" + e.getMessage());
		}

		resultMap.put("message", localeMessage.getMessage("ruleDeploy.msg4"));

		ModelAndView modelAndView = new ModelAndView("jsonView", resultMap);
		return modelAndView;
	}
}
