package com.eactive.eai.custom.alarm.ums;

import java.io.IOException;
import java.nio.charset.StandardCharsets;

import javax.annotation.PreDestroy;

import org.apache.hc.client5.http.classic.methods.HttpPost;
import org.apache.hc.client5.http.config.RequestConfig;
import org.apache.hc.client5.http.entity.EntityBuilder;
import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
import org.apache.hc.client5.http.impl.classic.HttpClients;
import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManagerBuilder;
import org.apache.hc.client5.http.io.HttpClientConnectionManager;
import org.apache.hc.core5.http.ContentType;
import org.apache.hc.core5.http.io.entity.EntityUtils;
import org.apache.hc.core5.util.TimeValue;
import org.apache.hc.core5.util.Timeout;
import org.springframework.stereotype.Component;

import com.eactive.eai.common.property.PropManager;
import com.eactive.eai.common.util.Jsons;
import com.eactive.eai.common.util.Logger;
import com.eactive.eai.custom.alarm.ums.payload.UmsRequestPayload;
import com.eactive.eai.custom.alarm.ums.payload.ValidationUtil;

@Component
public class UmsService {

    protected static Logger logger = Logger.getLogger(Logger.LOGGER_DEFAULT);

    // 설정 상수
    private final static String UMS_GROUP_PROP_NAME = "UMS";
    private final static String UMS_PROP_HOST = "host";
    private final static String UMS_PROP_URL = "url";
    private final static String UMS_PROP_API_KEY = "apiKey";
    private final static String UMS_PROP_CONNECTION_TIMEOUT = "timeout.connection.ms";
    private final static String UMS_PROP_TIMEOUT = "timeout.ms";
    
    // 기본값
    private final static String DEFAULT_UMS_URL = "http://172.31.35.144:9021";
    private final static String DEFAULT_SEND_URI = "/ums/openapi/send";
    private final static String DEFAULT_API_KEY = "7cca6d58-e4f7-474d-9edd-525806bc99ff";
    private final static String AUTHORIZATION_FMT = "Bearer %s";

    // 재사용되는 HttpClient (Thread-Safe)
    private final CloseableHttpClient httpClient;

    public UmsService() {
        // 커넥션 풀 설정: 매번 소켓을 열고 닫지 않고 재사용함
        HttpClientConnectionManager cm = PoolingHttpClientConnectionManagerBuilder.create()
                .setMaxConnTotal(100)      // 전체 최대 커넥션 수
                .setMaxConnPerRoute(20)    // 호스트당 최대 커넥션 수
                .setConnectionTimeToLive(TimeValue.ofMinutes(3))  // TTL
                .setValidateAfterInactivity(TimeValue.ofSeconds(5)) // 🔥 중요
                .build();

        this.httpClient = HttpClients.custom()
                .setConnectionManager(cm)
                .evictExpiredConnections()                     // 만료 제거
                .evictIdleConnections(TimeValue.ofSeconds(20)) // 20초 idle 제거
                .build();
    }

    public UmsCallResult send(UmsRequestPayload payload) throws Exception {
        if (payload.getContent() == null) {
            throw new IllegalArgumentException("content is null");
        }

        try {
            ValidationUtil.validateOrThrow(payload);
        } catch (Exception ex) {
            logger.debug(String.format("UMS Request payload validation failed - %s", payload));
            throw ex;
        }

        return call(payload);
    }

    private UmsCallResult call(UmsRequestPayload requestPayload) throws Exception {
        // 1. 프로퍼티 로드
        PropManager prop = PropManager.getInstance();
        String host = prop.getProperty(UMS_GROUP_PROP_NAME, UMS_PROP_HOST, DEFAULT_UMS_URL);
        String uri = prop.getProperty(UMS_GROUP_PROP_NAME, UMS_PROP_URL, DEFAULT_SEND_URI);
        String apiKey = prop.getProperty(UMS_GROUP_PROP_NAME, UMS_PROP_API_KEY, DEFAULT_API_KEY);
        long connectionTimeoutMs = Long.parseLong(prop.getProperty(UMS_GROUP_PROP_NAME, UMS_PROP_CONNECTION_TIMEOUT, "3000"));
        long timeoutMs = Long.parseLong(prop.getProperty(UMS_GROUP_PROP_NAME, UMS_PROP_TIMEOUT, "3000"));
        // 2. 요청 생성
        HttpPost httpPost = new HttpPost(host + uri);
        httpPost.setHeader("Authorization", String.format(AUTHORIZATION_FMT, apiKey));
        
        String json = Jsons.GSON.toJson(requestPayload);
        httpPost.setEntity(EntityBuilder.create()
                .setText(json)
                .setContentType(ContentType.APPLICATION_JSON)
                .setContentEncoding("UTF-8")
                .build());

        // 3. 타임아웃 설정 (설정파일 값 적용)
        RequestConfig config = RequestConfig.custom()
                .setConnectTimeout(Timeout.ofMilliseconds(connectionTimeoutMs))
                .setResponseTimeout(Timeout.ofMilliseconds(timeoutMs))
                .build();
        httpPost.setConfig(config);

        if (logger.isDebugEnabled()) {
            logger.debug("UMS Request to: {}", host + uri);
            logger.debug("UMS Request Body: {}", json);
        }

        // 4. 실행 (HttpClient 재사용)
        try {
            return httpClient.execute(httpPost, response -> {
                String body = EntityUtils.toString(response.getEntity(), StandardCharsets.UTF_8);
                
                if (logger.isDebugEnabled()) {
                    logger.debug("UMS Response Status: {}", response.getCode());
                    logger.debug("UMS Response Body: {}", body);
                }

                UmsCallResult result = Jsons.GSON.fromJson(body, UmsCallResult.class);
                result.setUmsMessageId(requestPayload.getMessageIdentityNo());
                
                // HTTP 200인 경우만 성공으로 간주 (필요에 따라 조정)
                result.setSuccess(response.getCode() == 200);
                
                if (response.getCode() != 200) {
                    logger.warn("UMS Call failed with status: {}", response.getCode());
                }
                
                return result;
            });
        } catch (Exception e) {
            logger.error("UMS call exception: " + e.getMessage(), e);
            return UmsCallResult.builder()
                    .umsMessageId(requestPayload.getMessageIdentityNo())
                    .isSuccess(false)
                    .throwable(e)
                    .build();
        }
    }

    @PreDestroy
    public void destroy() {
        try {
            if (httpClient != null) {
                httpClient.close();
                logger.info("UMS HttpClient closed.");
            }
        } catch (IOException e) {
            logger.error("Error closing UMS HttpClient", e);
        }
    }
}