package com.eactive.eai.common.util;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

import org.apache.commons.lang3.StringUtils;
import org.apache.hc.core5.http.Header;

import com.eactive.eai.common.logger.HttpAdapterExtraHeaderVo;
import com.eactive.eai.common.logger.HttpAdapterExtraLogVo;
import com.eactive.eai.common.logger.HttpLoggingService;
import com.eactive.eai.common.logger.async.AsyncHttpLoggingPoolManager;
import com.eactive.eai.env.ElinkConfig;


public class HttpAdapterExtraLogUtil {
	public static final int MAX_HEADER_VALUE_SIZE = 400;
	public static final String BODY_FIELD_NAME = "eapim-adapter-send-body";
    static Logger logger = Logger.getLogger(Logger.LOGGER_DEFAULT);
    
    public static boolean isHttpHeaderMode() {
		return StringUtils.equals(System.getProperty("use.http.header.log", "n"), "y");
	}

    public static void insertHttpAdapterExtraLog(String guid, int serviceProcessNumber, String adapterGroupName, String adapterName, Map<Object, Object> headers, String url, String httpMethod){
        insertHttpAdapterExtraLog(guid, serviceProcessNumber, adapterGroupName, adapterName, headers, url, httpMethod, 0);
    }

    public static void insertHttpAdapterExtraLog(String guid, int serviceProcessNumber, String adapterGroupName, String adapterName, Map<Object, Object> headers, String url, String httpMethod, int httpStatus){
        List<HttpAdapterExtraHeaderVo> headerVoList = convertMapToListOfHttpAdapterExtraHeaderVo(headers);
        insertHttpAdapterExtraLog(guid, serviceProcessNumber, adapterGroupName, adapterName, headerVoList, url, httpMethod, httpStatus);
    }

    public static void insertHttpAdapterExtraLog(String guid, int serviceProcessNumber, String adapterGroupName, String adapterName, Header[] headers, String url, String httpMethod){
        insertHttpAdapterExtraLog(guid, serviceProcessNumber, adapterGroupName, adapterName, headers, url, httpMethod, 0);
    }

    public static void insertHttpAdapterExtraLog(String guid, int serviceProcessNumber, String adapterGroupName, String adapterName, Header[] headers, String url, String httpMethod, int httpStatus){
    	
    	 List<HttpAdapterExtraHeaderVo> headerVoList = new ArrayList<HttpAdapterExtraHeaderVo>();
    	 
    	if ( headers != null && headers.length != 0 ) {
    		headerVoList = convertHeaderToListOfHttpAdapterExtraHeaderVo(headers);
    	}
        
        insertHttpAdapterExtraLog(guid, serviceProcessNumber, adapterGroupName, adapterName, headerVoList, url, httpMethod, httpStatus);
    }

    public static void insertHttpAdapterExtraLog(String guid, int serviceProcessNumber, String adapterGroupName, String adapterName, List<HttpAdapterExtraHeaderVo> headerVoList, String url, String httpMethod, int httpStatus){
        try {
//            HttpAdapterExtraLogMapper mapper = ApplicationContextProvider.getContext().getBean(HttpAdapterExtraLogMapper.class);
            HttpAdapterExtraLogVo httpAdapterExtraLogVo = new HttpAdapterExtraLogVo();
            httpAdapterExtraLogVo.setGuid(guid);
            httpAdapterExtraLogVo.setServiceProcessNumber(serviceProcessNumber);
            httpAdapterExtraLogVo.setAdapterGroupName(adapterGroupName);
            httpAdapterExtraLogVo.setAdapterName(adapterName);
            httpAdapterExtraLogVo.setUrl(url);
            httpAdapterExtraLogVo.setHttpMethod(httpMethod);

            for (HttpAdapterExtraHeaderVo httpAdapterExtraHeaderVo : headerVoList) {
//            	String name = httpAdapterExtraHeaderVo.getName();
//            	if(StringUtils.isNotBlank(name) && "authorization".equals(name.toLowerCase())) {
//            		httpAdapterExtraHeaderVo.setValue("{hidden}");
//            	}
            	String value = httpAdapterExtraHeaderVo.getValue();
            	if(StringUtils.isNotBlank(value) && value.length() > MAX_HEADER_VALUE_SIZE) {
            		value = value.substring(0, 400) + "...";
            		httpAdapterExtraHeaderVo.setValue(value);
            	}else if(value == null){
                    httpAdapterExtraHeaderVo.setValue(" ");
                }
			}
            
            httpAdapterExtraLogVo.setHeaderList(headerVoList);
            httpAdapterExtraLogVo.setHttpStatus(httpStatus);
            
            logger.debug("[{}] Insert HTTP Log. - {}", guid, httpAdapterExtraLogVo);
            
            if(ElinkConfig.isUseAsyncLogging()) {
                AsyncHttpLoggingPoolManager.getInstance().publish(httpAdapterExtraLogVo);
            } else {
                HttpLoggingService service = ApplicationContextProvider.getContext().getBean(HttpLoggingService.class);
                service.insertHttpAdapterExtraLog(httpAdapterExtraLogVo);
            }

            // 2025.04.30 DB Log 작업 Async 처리 적용으로 수정
//            if (EAIDBLogControl.isEnable()) {
//                // 2025.04.11 DB 장애시 DB 장애 Flag 설정하도록 수정
//                try {
//                    HttpAdapterExtraLog httpAdapterExtraLog = mapper.toEntity(httpAdapterExtraLogVo);
//                    HttpAdapterExtraLogLogger service = ApplicationContextProvider.getContext().getBean(HttpAdapterExtraLogLogger.class);
//                    service.save(httpAdapterExtraLog);
//                } catch (Exception e) {
//                    logger.error("["+guid+"] Insert HTTP Log Error. - " + e.getMessage(), e);
//                    // DB Connection Error일 경우에만 설정하도록 수정
//                    String message = e.getMessage();
//                    // 오류 메시지 추가 - Could not open JPA EntityManager for transaction; nested exception is org.hibernate.exception.JDBCConnectionException: Unable to acquire JDBC Connection
//                    // 오류 메시지 추가 - Could not open JPA EntityManager for transaction; nested exception is org.hibernate.exception.GenericJDBCException: Unable to acquire JDBC Connection
//                    if( "ConnectionError".equals(message) || org.apache.commons.lang.StringUtils.contains(message, "JDBCConnectionException")
//                            || org.apache.commons.lang.StringUtils.contains(message, "Unable to acquire JDBC Connection") ) {
//                        EAIDBLogControl.setEnable(false);
//                    }
////                    throw e;
//                }
//            } else {
//                // TODO: 파일 로그 및 복구 처리 추가 필요
//            }
        } catch(Throwable th){
            logger.error("["+guid+"] Insert HTTP Log Error. - " + th.getMessage(), th);
        }
    }

    public static List<HttpAdapterExtraHeaderVo> convertHeaderToListOfHttpAdapterExtraHeaderVo(Header[] headers) {
        Set<String> seenNames = new HashSet<>();
        return Arrays.stream(headers)
//                .filter(header -> seenNames.add(header.getName())) // 중복된 이름을 스킵
                .map(header -> new HttpAdapterExtraHeaderVo(header.getName(), header.getValue()))
                .collect(Collectors.toList());
    }

    public static List<HttpAdapterExtraHeaderVo> convertMapToListOfHttpAdapterExtraHeaderVo(Map<Object, Object> map) {
        return map.entrySet().stream()
                .map(entry -> new HttpAdapterExtraHeaderVo(entry.getKey().toString(), entry.getValue() == null ? "" : entry.getValue().toString()))
                .collect(Collectors.toList());
    }
    
}
