package com.eactive.eai.custom.statistics;

import java.time.LocalDateTime;

import org.springframework.stereotype.Component;

import com.eactive.eai.common.message.EAIMessage;
import com.eactive.eai.common.monitor.StatisticsMonitor;
import com.eactive.eai.common.util.Logger;
import com.eactive.eai.custom.statistics.collector.ApiStatsCollector;
import com.eactive.eai.custom.statistics.dto.TransactionEvent;

import lombok.RequiredArgsConstructor;

/**
 * StatisticsMonitor 구현체 - EAIServiceMonitor에서 호출되어 API 통계 수집 - EAIMessage에서 필요한
 * 정보를 추출하여 ApiStatsCollector에 전달
 */
@Component
@RequiredArgsConstructor
public class ApiStatsMonitorImpl implements StatisticsMonitor {

	private static final Logger logger = Logger.getLogger(Logger.LOGGER_DEFAULT);

	private final ApiStatsCollector apiStatsCollector;

	@Override
	public void recordStatistics(EAIMessage requestEaiMessage) {
		try {
			// 로그 시퀀스 100, 400, 900만 처리
			int logSequence = requestEaiMessage.getLogPssSno();

			// 디버깅: 모든 logSequence 로깅
			logger.info("API Stats - logSeq: {}, API: {}, errorCode: {}",
				logSequence, requestEaiMessage.getEAISvcCd(), requestEaiMessage.getStatErrorCode());

			if (logSequence != 100 && logSequence != 400 && logSequence != 900) {
				return;
			}

			String apiName = extractApiName(requestEaiMessage);
			String gwInstanceId = extractGwInstanceId(requestEaiMessage);
			String bizDivCode = extractBizDivCode(requestEaiMessage);
			String clientId = extractClientId(requestEaiMessage);
			String inboundAdapter = extractInboundAdapter(requestEaiMessage);
			String outboundAdapter = extractOutboundAdapter(requestEaiMessage);
			long responseTimeMs = extractResponseTime(requestEaiMessage);
			boolean success = extractSuccess(requestEaiMessage);
			TransactionEvent.ErrorType errorType = extractErrorType(requestEaiMessage, success);

			// TransactionEvent 생성
			TransactionEvent event = TransactionEvent.builder().apiName(apiName).gwInstanceId(gwInstanceId)
					.bizDivCode(TransactionEvent.normalizeValue(bizDivCode))
					.clientId(TransactionEvent.normalizeValue(clientId))
					.inboundAdapter(TransactionEvent.normalizeValue(inboundAdapter))
					.outboundAdapter(TransactionEvent.normalizeValue(outboundAdapter)).responseTimeMs(responseTimeMs)
					.logSequence(logSequence).success(success).errorType(errorType).build();

			// 통계 수집
			apiStatsCollector.recordEvent(event);

			if (logger.isDebug()) {
				logger.debug("API statistics recorded: " + apiName);
			}

		} catch (Exception e) {
			logger.error("Failed to record API statistics", e);
		}
	}

	/**
	 * API 명 추출
	 */
	private String extractApiName(EAIMessage msg) {
		String apiName = msg.getEAISvcCd();
		return apiName != null ? apiName : "UNKNOWN";
	}

	/**
	 * Gateway 인스턴스 ID 추출
	 */
	private String extractGwInstanceId(EAIMessage msg) {
		String instanceId = msg.getEAISvrInstNm();
		return instanceId != null ? instanceId : "UNKNOWN";
	}

	/**
	 * 업무구분코드 추출
	 */
	private String extractBizDivCode(EAIMessage msg) {
		return msg.getBwkCls();
	}

	/**
	 * 클라이언트 ID 추출
	 */
	private String extractClientId(EAIMessage msg) {
		return msg.getClientId();
	}

	/**
	 * Inbound Adapter 추출
	 */
	private String extractInboundAdapter(EAIMessage msg) {
		return msg.getSngSysItfTp();
	}

	/**
	 * Outbound Adapter 추출
	 */
	private String extractOutboundAdapter(EAIMessage msg) {
		if (msg.getCurrentSvcMsg() != null) {
			// TODO 실제 값이 맞는 지 확인 필요
			return msg.getCurrentSvcMsg().getPsvSysItfTp();
		}
		return null;
	}

	/**
	 * 응답시간 추출 (ms)
	 */
	private long extractResponseTime(EAIMessage msg) {
		long msgPssTm = msg.getMsgPssTm(); // 메시지 처리시각
		long msgRcvTm = msg.getMsgRcvTm(); // 메시지 수신시각
		
		if (msgPssTm == 0) {
			msgPssTm = System.currentTimeMillis();
		}

		if (msgPssTm > 0 && msgRcvTm > 0) {
			return msgPssTm - msgRcvTm;
		}

		return 0L;
	}

	/**
	 * 성공 여부 추출
	 */
	private boolean extractSuccess(EAIMessage msg) {
		// logPssSno가 900이면 에러로 처리
		if (msg.getLogPssSno() == 900) {
			return false;
		}
		return msg.getStatErrorCode() == 0;
	}

	/**
	 * 에러 유형 추출
	 */
	private TransactionEvent.ErrorType extractErrorType(EAIMessage msg, boolean success) {
		int errorCode = msg.getStatErrorCode();

		switch (errorCode) {
		case 0:
			return success ? null : TransactionEvent.ErrorType.SYSTEM_ERROR;
		case 1:
			return TransactionEvent.ErrorType.BUSINESS_ERROR;
		case 2:
			return TransactionEvent.ErrorType.TIMEOUT;
		case 3:
			return TransactionEvent.ErrorType.SYSTEM_ERROR;
		default:
			return success ? null : TransactionEvent.ErrorType.SYSTEM_ERROR;
		}
	}
}
