package com.eactive.eai.rms.bat.manage.rule.adapter;

import java.io.ByteArrayOutputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.atomic.AtomicInteger;

import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.core.io.ByteArrayResource;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

import com.eactive.eai.rms.bat.manage.comm.server.BatServerService;
import com.eactive.eai.rms.common.base.BaseService;
import com.eactive.eai.rms.common.datasource.DataSourceContextHolder;
import com.eactive.eai.rms.common.datasource.DataSourceTypeManager;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.ObjectMapper;

@Service
public class BatAdapterConnectionReportService extends BaseService {
	
	@Autowired
	private RestTemplate restTemplate;
	
	@Autowired @Qualifier("batServerService")
    private BatServerService batServerService;
	
	public String getRemoteFilesList(String modalAdapterCode, String modalDirectory) throws Exception {
		
		Map<String, String> hostName_requestUrl_map = getRequestUrlMap("remoteFileList.jsp");
		StringBuilder errorBuilder = new StringBuilder();
		
		for(Entry<String, String> entry : hostName_requestUrl_map.entrySet()) {
			try {
				String requestUrl = entry.getValue() + "?adapterCode=" + modalAdapterCode + "&targetDirectory=" + modalDirectory;
				String response = httpCallAndGetResponse(requestUrl);
				return response;
			} catch (Exception e) {
				logger.error("host: " + entry.getKey() + " connection error.", e);
				errorBuilder.append("HOST: ").append(entry.getKey()).append(" URL: ").append(entry.getValue()).append(" ERROR: ").append(e.getMessage());
			}
		}
		
		if(errorBuilder.length() == 0) {
			return "Cannot get EAI-Batch's requestUrl information";
		} else {
			return errorBuilder.toString();
		}
	}
	
	public List<AdapterConnectionInfo> getAdapterConnectionReportAll() throws Exception {
		
		List<AdapterConnectionInfo> result = new ArrayList<>();
		
		Map<String, String> hostName_requestUrl_map = getRequestUrlMap("connectionReport.jsp");
		
		for(Entry<String, String> entry : hostName_requestUrl_map.entrySet()) {
			String response = httpCallAndGetResponse(entry.getValue());
			List<AdapterConnectionInfo> connInfoList = convertHttpResponseToAdapterConntionInfoList(entry.getKey(), response);
			result.addAll(connInfoList);
		}
		
		return result;
	}
	
	public List<AdapterConnectionInfo> getAdapterConnectionReport(String adapterCode) throws Exception {
		
		List<AdapterConnectionInfo> result = new ArrayList<>();
		
		Map<String, String> hostName_requestUrl_map = getRequestUrlMap("connectionReport.jsp");
		
		for(Entry<String, String> entry : hostName_requestUrl_map.entrySet()) {
			String requestUrl = entry.getValue() + "?adapterCode=" + adapterCode;
			String response = httpCallAndGetResponse(requestUrl);
			AdapterConnectionInfo connectionInfo = convertHttpResponseToAdapterConntionInfo(entry.getKey(), response);
			result.add(connectionInfo);
		}
		
		return result;
	}
	
	public ByteArrayResource generateExcelFromConnectionInfoList(List<AdapterConnectionInfo> connInfoList) throws Exception {
		
		try(Workbook xwb = new XSSFWorkbook();
			ByteArrayOutputStream baos = new ByteArrayOutputStream();) {
			
			Sheet sheet = xwb.createSheet("report");
			String[] headerColumnNames = {"HOST_NAME", "ADAPTER_CODE", "DESTINATION", "TYPE", "VALID", "MESSAGE"};
			setExcelTopHeader(sheet, headerColumnNames);
			setExcelDataBody(sheet, connInfoList);
			
			xwb.write(baos);
			return new ByteArrayResource(baos.toByteArray());
		}
		
	}
	
		private Map<String, String> getRequestUrlMap(String jspName) throws Exception {
			
			DataSourceContextHolder.setDataSourceType(DataSourceTypeManager.getDataSourceType(DataSourceTypeManager.BAT));
			
			List<HashMap<String, Object>> eaiServerIpPort = batServerService.getEaiServerIpPort();
			
			Map<String, String> resultMap = new HashMap<>();
			
			for(HashMap<String, Object> row : eaiServerIpPort) {
				String hostName = String.valueOf(row.get("HOSTNAME"));
//				String requestUrl = "";
//				if(ContainerUtil.get() == ContainerUtil.TOMCAT) {
//					requestUrl = "http://" + hostName + ":" + String.valueOf(row.get("EAISVRLSNPORT")) + "/BATWeb/" + jspName;
//				} else {
//					requestUrl = "http://" + hostName + ".pobis.kr:" + String.valueOf(row.get("EAISVRLSNPORT")) + "/BATWeb/" + jspName;
//				}
//				resultMap.put(hostName, requestUrl);
				String hostIp = String.valueOf(row.get("EAISVRIP"));
				String requestUrl = "http://" + hostIp + ":" + String.valueOf(row.get("EAISVRLSNPORT")) + "/BATWeb/" + jspName;
				resultMap.put(hostName, requestUrl);
				
			}
			
			return resultMap;
		}
		
		private String httpCallAndGetResponse(String requestUrl) throws Exception {
			HttpHeaders headers = new HttpHeaders();
			HttpEntity<String> entity = new HttpEntity<>(headers);
			ResponseEntity<String> response = restTemplate.exchange(requestUrl, HttpMethod.GET, entity, String.class);
			if(200 <= response.getStatusCodeValue() || response.getStatusCodeValue() < 300) {
				return response.getBody();
			} else {
				throw new Exception(response.getBody());
			}
		}
	
		private List<AdapterConnectionInfo> convertHttpResponseToAdapterConntionInfoList(String hostName, String httpResponse) throws JsonMappingException, JsonProcessingException {
			ObjectMapper oMapper = new ObjectMapper();
			List<AdapterConnectionInfo> connInfoList = oMapper.readValue(httpResponse, new TypeReference<List<AdapterConnectionInfo>>() {});
			connInfoList.forEach(item -> item.setHostName(hostName));
			return connInfoList;
		}
		
		private AdapterConnectionInfo convertHttpResponseToAdapterConntionInfo(String hostName, String httpResponse) throws JsonMappingException, JsonProcessingException {
			ObjectMapper oMapper = new ObjectMapper();
			AdapterConnectionInfo connInfo = oMapper.readValue(httpResponse, new TypeReference<AdapterConnectionInfo>() {});
			connInfo.setHostName(hostName);
			return connInfo;
		}

		private void setExcelTopHeader(Sheet sheet, String[] headerColumnNames) {
			Row headerRow = sheet.createRow(0);
			AtomicInteger headerCellIndex = new AtomicInteger();
			for(String column : headerColumnNames) {
				headerRow.createCell(headerCellIndex.getAndIncrement()).setCellValue(column);
			}
		}
		
		private void setExcelDataBody(Sheet sheet, List<AdapterConnectionInfo> connInfoList) {
			
			AtomicInteger bodyRowIndex = new AtomicInteger(1);
			for (AdapterConnectionInfo connInfo : connInfoList) {
				AtomicInteger bodyCellIndex = new AtomicInteger();
				Row bodyRow = sheet.createRow(bodyRowIndex.getAndIncrement());
				bodyRow.createCell(bodyCellIndex.getAndIncrement()).setCellValue(connInfo.getHostName());
				bodyRow.createCell(bodyCellIndex.getAndIncrement()).setCellValue(connInfo.getAdapterCode());
				bodyRow.createCell(bodyCellIndex.getAndIncrement()).setCellValue(connInfo.getDestination());
				bodyRow.createCell(bodyCellIndex.getAndIncrement()).setCellValue(connInfo.getType());
				bodyRow.createCell(bodyCellIndex.getAndIncrement()).setCellValue(connInfo.isValid());
				bodyRow.createCell(bodyCellIndex.getAndIncrement()).setCellValue(connInfo.getMessage());
			}
		
		}

}
