package com.eactive.eai.rms.onl.apim.service;

import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;

import com.eactive.eai.rms.ext.djb.common.DjbPropertyHolder;
import com.eactive.eai.util.IpUtil;

import lombok.extern.slf4j.Slf4j;

/**
 * IP 화이트리스트 인증 서비스
 *
 * <p>기능:</p>
 * <ul>
 *   <li>IP 화이트리스트 관리 및 검증</li>
 *   <li>캐싱을 통한 성능 최적화 (60초 TTL)</li>
 *   <li>와일드카드(*), CIDR, 정확한 매칭 지원</li>
 * </ul>
 *
 * <p>캐싱 전략:</p>
 * <ul>
 *   <li>캐시 TTL: 60초</li>
 *   <li>스레드 안전성: volatile + synchronized 이중 체크 락킹</li>
 * </ul>
 *
 * @see com.eactive.eai.util.IpUtil#isMatchIp(String, String)
 */
@Service
@Slf4j
public class IpAuthenticationService {

    /**
     * 캐시 TTL (밀리초)
     */
    private static final long CACHE_TTL_MS = 60_000L; // 60초

    /**
     * 캐시된 IP 화이트리스트
     */
    private volatile String cachedWhitelist = null;

    /**
     * 캐시 만료 시간 (밀리초)
     */
    private volatile long cacheExpirationTime = 0L;

    /**
     * 클라이언트 IP가 화이트리스트에 포함되는지 확인
     *
     * @param clientIp 클라이언트 IP 주소
     * @return 화이트리스트에 포함되면 true, 아니면 false
     */
    public boolean isIpAllowed(String clientIp) {
        if (StringUtils.isBlank(clientIp)) {
            log.warn("Client IP is blank, denying access");
            return false;
        }

        String whitelist = getWhitelistWithCache();

        if (StringUtils.isBlank(whitelist)) {
            log.warn("IP whitelist is empty, denying all access");
            return false;
        }

        try {
            boolean allowed = IpUtil.isMatchIp(whitelist, clientIp);
            if (log.isDebugEnabled()) {
                log.debug("IP authentication - IP: {}, Allowed: {}, Whitelist: {}", clientIp, allowed, whitelist);
            }
            return allowed;
        } catch (Exception e) {
            log.error("Error checking IP whitelist - IP: {}, Whitelist: {}", clientIp, whitelist, e);
            return false;
        }
    }

    /**
     * 캐시된 화이트리스트 반환, 만료 시 재로딩
     *
     * @return IP 화이트리스트 (쉼표로 구분된 IP 패턴)
     */
    private String getWhitelistWithCache() {
        long currentTime = System.currentTimeMillis();

        // 캐시가 유효한 경우 캐시 반환
        if (cachedWhitelist != null && currentTime < cacheExpirationTime) {
            return cachedWhitelist;
        }

        // 캐시 갱신 (이중 체크 락킹)
        synchronized (this) {
            // 다른 스레드가 이미 갱신했는지 재확인
            if (cachedWhitelist != null && currentTime < cacheExpirationTime) {
                return cachedWhitelist;
            }

            // DB에서 화이트리스트 로드
            String whitelist = loadWhitelistFromDb();

            // 공백 제거 및 캐시 저장
            cachedWhitelist = trimWhitelist(whitelist);
            cacheExpirationTime = currentTime + CACHE_TTL_MS;

            log.info("IP whitelist cache refreshed - Whitelist: {}", cachedWhitelist);
            return cachedWhitelist;
        }
    }

    /**
     * DB에서 IP 화이트리스트 로드
     *
     * @return IP 화이트리스트 문자열
     */
    private String loadWhitelistFromDb() {
        try {
            String whitelist = DjbPropertyHolder.get().getApiAllowIpList();
            if (StringUtils.isBlank(whitelist)) {
                log.warn("IP whitelist property is empty");
                return "";
            }
            return whitelist;
        } catch (Exception e) {
            log.error("Failed to load IP whitelist from database", e);
            return "";
        }
    }

    /**
     * 화이트리스트의 각 IP 패턴에서 공백 제거
     *
     * @param whitelist 원본 화이트리스트 (쉼표로 구분)
     * @return 공백이 제거된 화이트리스트
     */
    private String trimWhitelist(String whitelist) {
        if (StringUtils.isBlank(whitelist)) {
            return "";
        }

        String[] patterns = whitelist.split(",");
        StringBuilder trimmed = new StringBuilder();

        for (int i = 0; i < patterns.length; i++) {
            if (i > 0) {
                trimmed.append(",");
            }
            trimmed.append(patterns[i].trim());
        }

        return trimmed.toString();
    }

    /**
     * 캐시 강제 갱신 (테스트용)
     */
    public void clearCache() {
        synchronized (this) {
            cachedWhitelist = null;
            cacheExpirationTime = 0L;
            log.info("IP whitelist cache cleared");
        }
    }
}
