package com.eactive.eai.rms.onl.manage.serviceinfo.eaimsg;

import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;

import com.eactive.eai.agent.command.CommonCommand;
import com.eactive.eai.agent.eaimessage.RemoveEAIMessageCommand;
import com.eactive.eai.agent.transformer.RemoveLayoutCommand;
import com.eactive.eai.agent.transformer.RemoveTransformCommand;
import com.eactive.eai.data.entity.onl.b2bextractor.B2BExtractId;
import com.eactive.eai.rms.common.base.BaseService;
import com.eactive.eai.rms.data.entity.onl.b2bextract.B2bExtractService;
import com.eactive.eai.rms.data.entity.onl.bizkey.BizKeyService;
import com.eactive.eai.rms.data.entity.onl.stdmessage.StandardMessageInfoService;
import com.eactive.eai.rms.onl.common.service.AgentUtilService;
import com.eactive.eai.rms.onl.manage.rule.layout.LayoutManService;
import com.eactive.eai.rms.onl.manage.rule.transform.TransformManService;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;

@Service
public class EaiMsgEasyDeleteService extends BaseService {
	
	@Autowired private EaiMsgEasyDeleteDao dao;
	
	@Autowired private EaiMsgManService eaiMsgManService;
	@Autowired private TransformManService transformManService;
	@Autowired private LayoutManService layoutManService;
	
	@Autowired
	private B2bExtractService b2bExtractService;
	
	@Autowired
	private StandardMessageInfoService standardMessageInfoService;
	
	
	@Qualifier("onlAgentUtilService")
	@Autowired private AgentUtilService agentUtilService;
	
	@Autowired
	private BizKeyService bizKeyService;
	
	private Gson gson = new Gson();
	
	private Type list_hashMap_type = new TypeToken<List<HashMap<String, Object>>>(){}.getType();

	public Map<String, Object> selectList(int startNum, int endNum, Map<String, Object> paramMap) throws Exception {
		
		// 전체 목록수 얻기
		int totalCount = dao.selectListCount(paramMap);

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

		List<Map<String, Object>> list = dao.selectList(paramMap);

		Map<String, Object> map = new HashMap<>();
		map.put("totalCount", totalCount);
		map.put("list", list);

		return map;
	}
	
	public List<Map<String, Object>> selectB2bExtList(Map<String, String> paramMap) {
		return dao.selectB2bExtList(paramMap);
	}
	
	public List<Map<String, Object>> selectBzwkFldList(Map<String, String> paramMap) {
		return dao.selectBzwkFldList(paramMap);
	}

	public List<Map<String, Object>> selectLayoutListByTransform(Map<String, Object> paramMap) {
		return dao.selectLayoutListByTransform(paramMap);
	}

	public Map<String, Object> selectLayoutEffects(Map<String, Object> paramMap) {
		
		String serviceType = (String) paramMap.get("serviceType");
    	String jsonStr = (String) paramMap.get("gridData");
    	LoutSearchGridVo vo = gson.fromJson(jsonStr, LoutSearchGridVo.class);
    	
    	// FIXME DRY
    	Map<String, Object> result = new HashMap<>();
    	if(vo.getReq() != null) {
    		result.put("req", selectLayoutEffect(serviceType, vo.getReq()));
    	}
    	if(vo.getRes() != null) {
    		result.put("res", selectLayoutEffect(serviceType, vo.getRes()));
    	}
    	if(vo.getErr() != null) {
    		result.put("err", selectLayoutEffect(serviceType, vo.getErr()));
    	}
    	
		return result;
	}
	
	private List<Map<String, Object>> selectLayoutEffect(String serviceType, GridObject gObj) {
		Map<String, Object> paramMap = new HashMap<>();
		paramMap.put("serviceType", serviceType);
		paramMap.put("loutList", gObj.getLouts());
		paramMap.put("exceptTransName", gObj.getExceptTransName());
		return dao.selectLayoutEffects(paramMap);
	}
	
	/**
	 * Transactional
	 */
	public void delete(Map<String, String> paramMap) throws Exception {
		
		String eaiSvcName 		= paramMap.get("eaiSvcName");
		String bzwkSvcKeyName 	= paramMap.get("bzwkSvcKeyName");
		
		String b2bExtList 		= paramMap.get("b2bExtList");
		String bzwkFldNameList 	= paramMap.get("bzwkFldNameList");
		
		String trans_request 	= paramMap.get("trans_chngMsgIdName");
		String trans_response 	= paramMap.get("trans_bascRspnsChngMsgIdName");
		String trans_error 		= paramMap.get("trans_errRspnsChngMsgIdName");
		
		
		String layouts_request 	= paramMap.get("layouts_trans_chngMsgIdName");
		String layouts_response = paramMap.get("layouts_trans_bascRspnsChngMsgIdName");
		String layouts_error 	= paramMap.get("lauouts_trans_errRspnsChngMsgIdName");
		
		logger.debug("EaiMsgEasyDeleteService] ▼▼▼ layout effects validation ▼▼▼ ");
		
		layoutsEffectsValidation(layouts_request, trans_request);
		layoutsEffectsValidation(layouts_response, trans_response);
		layoutsEffectsValidation(layouts_error, trans_error);
		
		logger.debug("EaiMsgEasyDeleteService] ▼▼▼ eai message easy delete start ▼▼▼ ");
		
		deleteEaiMessage(eaiSvcName); // HE01, HE02
		
		dao.deleteWithTableName("TSEAIMS02", "EAISVCNAME", eaiSvcName); // MS02
		
		deleteBzwkSvcKeyName(bzwkSvcKeyName, eaiSvcName); // HS04, HS05
		
		dao.deleteWithTableName("TSEAIFR01", "EAISVCNAME", eaiSvcName); // FR01
		deleteB2bExtList(b2bExtList, eaiSvcName); // FR06
		deleteBzwkFldNameList(bzwkFldNameList, eaiSvcName); // FR03
		
		deleteTransform(trans_request, 	"REQ", eaiSvcName); // TR01, TR02, TR03
		deleteTransform(trans_response, "RES", eaiSvcName); // TR01, TR02, TR03
		deleteTransform(trans_error, 	"ERR", eaiSvcName); // TR01, TR02, TR03
		
		List<String> allLayoutList = joinLayouts(layouts_request, layouts_response, layouts_error); 
		
		deleteLayoutList(allLayoutList);	// TR07, TR08

		logger.debug("EaiMsgEasyDeleteService] ▼▼▼ reload and send Command ▼▼▼ ");
		
		List<String> allTransformList = joinTransforms(trans_request, trans_response, trans_error);
		
		for(String loutName : allLayoutList) {
			agentUtilService.broadcast(new CommonCommand(RemoveLayoutCommand.class.getName(), loutName));
		}
		
		for(String transName : allTransformList) {
			agentUtilService.broadcast(new CommonCommand(RemoveTransformCommand.class.getName(), transName));
		}
		
		agentUtilService.broadcast(new CommonCommand(RemoveEAIMessageCommand.class.getName(), eaiSvcName));
		
	}
	
	private void layoutsEffectsValidation(String layouts, String transName) throws Exception {
		
		List<String> loutList = gson.fromJson(layouts, List.class);
		
		if(loutList == null ? true : loutList.size() == 0) {
			return;
		}
		
		if(StringUtils.isBlank(transName)) {
			throw new Exception("ERROR] 레이아웃 삭제 시 변환을 함께 삭제해야 합니다.");
		}
		
		for(String loutName : loutList) {
			
			List<String> conversions = dao.selectEffectConversionNames(new HashMap<String, Object>() {{
				put("LOUTNAME", loutName);
				put("transName", transName);
			}});
			
			if(conversions.size() > 0) {
				StringBuilder sb = new StringBuilder();
				conversions.forEach(cv -> {
					sb.append(cv);
					sb.append(",");
				});
				throw new Exception("ERROR] 타 변환에서 사용중인 레이아웃 : " + loutName + " / 영향 변환 : " + StringUtils.removeEnd(sb.toString(), ","));
			}
			
		}
		
	}

	private List<String> joinLayouts(String layouts_request, String layouts_response, String layouts_error) {
		
		List<String> result = new ArrayList<>();
		
		result.addAll(gson.fromJson(layouts_request, List.class));
		result.addAll(gson.fromJson(layouts_response, List.class));
		result.addAll(gson.fromJson(layouts_error, List.class));
		
		return result;
	}
	
	private List<String> joinTransforms(String trans_request, String trans_response, String trans_error) {
		
		List<String> result = new ArrayList<>();
		
		if(StringUtils.isNotBlank(trans_request)) {
			result.add(trans_request);
		}
		if(StringUtils.isNotBlank(trans_response)) {
			result.add(trans_response);
		}
		if(StringUtils.isNotBlank(trans_error)) {
			result.add(trans_error);
		}
		
		return result;
	}

	private void deleteEaiMessage(String eaiSvcName) throws Exception {
		
		if(StringUtils.isBlank(eaiSvcName)) {
			throw new Exception("ERROR] 인터페이스 ID Empty");
		}
		
		eaiMsgManService.delete(eaiSvcName);
		logger.debug("EaiMsgEasyDeleteService] eaiSvcName deleted : " + eaiSvcName);
	}
	
	private void deleteBzwkSvcKeyName(String bzwkSvcKeyName, String eaiSvcName) throws Exception {
		
		if(StringUtils.isBlank(bzwkSvcKeyName)) {
			return;
		}
		
		standardMessageInfoService.deleteById(bzwkSvcKeyName);
		logger.debug("EaiMsgEasyDeleteService] bzwkSvcKey deleted : " + bzwkSvcKeyName);
	}

	private void deleteTransform(String transName, String cnvsnType, String eaiSvcName) throws Exception {
		
		if(StringUtils.isBlank(transName)) {
			return;
		}
		
		transformManService.delete(transName, eaiSvcName, cnvsnType);
		logger.debug("EaiMsgEasyDeleteService] transform deleted : " + transName);
	}
	
	private void deleteB2bExtList(String b2bExtList, String eaiSvcName) throws Exception {
		
		if(StringUtils.isBlank(b2bExtList)) {
			return;
		}
		
		List<HashMap<String, Object>> paramList = gson.fromJson(b2bExtList, list_hashMap_type);
		for(HashMap<String, Object> param : paramList) {
			param.put("eaiSvcName", eaiSvcName);
			param.put("svcPrcssNo", param.get("SVCPRCSSNO"));
			
			B2BExtractId id = new B2BExtractId(eaiSvcName, Integer.parseInt((String) param.get("SVCPRCSSNO")));
			b2bExtractService.delete(id);
			logger.debug("EaiMsgEasyDeleteService] b2bExtract deleted : " + param.get("eaiSvcName") + " / " + param.get("SVCPRCSSNO"));
		}
	}
	
	private void deleteBzwkFldNameList(String bzwkFldNameList, String eaiSvcName) throws Exception {
		
		if(StringUtils.isBlank(bzwkFldNameList)) {
			return;
		}
		
		List<HashMap<String, Object>> paramList = gson.fromJson(bzwkFldNameList, list_hashMap_type);
		for(HashMap<String, Object> param : paramList) {
			param.put("eaiSvcName", eaiSvcName);
			param.put("etractDstcd", param.get("ETRACTDSTCD"));
			bizKeyService.delete(eaiSvcName, (String) param.get("ETRACTDSTCD"));
			logger.debug("EaiMsgEasyDeleteService] fieldExtract deleted : " + param.get("etractDstcd"));
		}
	}
	
	private void deleteLayoutList(List<String> loutList) throws Exception {
		
		for(String loutName : loutList) {
			layoutManService.delete(loutName);
		}
	}
	
	private class LoutSearchGridVo {
		private GridObject req;
		private GridObject res;
		private GridObject err;
		public GridObject getReq() {
			return req;
		}
		public void setReq(GridObject req) {
			this.req = req;
		}
		public GridObject getRes() {
			return res;
		}
		public void setRes(GridObject res) {
			this.res = res;
		}
		public GridObject getErr() {
			return err;
		}
		public void setErr(GridObject err) {
			this.err = err;
		}
	}
	private class GridObject {
		private List<String> louts;
		private String exceptTransName;
		public List<String> getLouts() {
			return louts;
		}
		public void setLouts(List<String> louts) {
			this.louts = louts;
		}
		public String getExceptTransName() {
			return exceptTransName;
		}
		public void setExceptTransName(String exceptTransName) {
			this.exceptTransName = exceptTransName;
		}
	}
}
