package com.eactive.eai.custom.alarm;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import com.eactive.eai.common.util.ApplicationContextProvider;
import com.eactive.eai.common.util.Logger;
import com.eactive.eai.custom.alarm.event.AlarmEvent;
import com.eactive.eai.custom.alarm.key.AlarmKey;
import com.eactive.eai.custom.alarm.policy.AlarmPolicy;
import com.eactive.eai.custom.alarm.policy.SendPolicy;
import com.eactive.eai.custom.alarm.ums.UmsSendManager;
import com.eactive.eai.custom.alarm.ums.UmsService;
import com.eactive.eai.custom.alarm.ums.payload.ObpMonitoringUmsTemplate;
import com.eactive.eai.custom.alarm.ums.payload.UmsRequestPayload;

//@Component
public class AlarmStateManager {

	List<AlarmEvent> registerAlarmList = new ArrayList<AlarmEvent>();

	private final ScheduledExecutorService scheduler;

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

	private static AlarmStateManager alarmStateManager;

	@Autowired
	AlarmService alarmService;

	@Autowired
	UmsSendManager umsSendManager;

	public static AlarmStateManager getAlarmStateManager() {
		if (alarmStateManager == null) {
			alarmStateManager = ApplicationContextProvider.getContext().getBean(AlarmStateManager.class);
		}
		return alarmStateManager;
	}

	public AlarmStateManager() {

		this.scheduler = Executors.newSingleThreadScheduledExecutor(r -> {
			Thread t = new Thread(r);
			t.setName("AlarmStateManager-worker");
			t.setDaemon(false);
			return t;
		});

		scheduler.scheduleWithFixedDelay(() -> {

			try {
				// === 여기에 지속 실행할 로직 ===
				fireAlarm();

			} catch (Throwable e) {
				// 반드시 예외 잡기 (안 잡으면 스케줄 자체가 죽음)
				logger.error("fireAlarm fail", e);
			}

		}, 0, 5, TimeUnit.SECONDS); // 최초 0초, 이후 5초 간격
	}

	public void onEvnet(AlarmEvent alaramEvent) {

		Optional<AlarmEvent> existEvent = registerAlarmList.stream().filter(e -> e.equals(alaramEvent)).findFirst();

		if (existEvent.isPresent()) {
			AlarmEvent event = existEvent.get();
			event.onOcurr();
		} else {
			registerAlarmList.add(alaramEvent);
		}

	}

	private void fireAlarm() {

		Map<AlarmKey, AlarmPolicy> alarmPolicyMap = alarmService.getAlarmPolicy();

		Map<AlarmKey, SendPolicy> sendPolicyMap = alarmService.getSendPolicy();

		Iterator<AlarmEvent> iterator = registerAlarmList.iterator();

		while (iterator.hasNext()) {
			AlarmEvent event = iterator.next();
			AlarmPolicy alarmPolicy = alarmPolicyMap.get(event.getKey());

			if (alarmPolicy != null && alarmPolicy.isAlarmTriggered(event)) {
				// 알람 발송 로직
				SendPolicy sendPolicy = sendPolicyMap.get(event.getKey());
				if (alarmService.isAlarmEnabled()) {
					send(sendPolicy, event);
				} else {
					logger.info("Alarm is disabled, event = {}, policy = {}", event, sendPolicy);
				}
				// 리스트에서 안전하게 제거
				iterator.remove();
			} else { // 트리거 조건이 안되더라도, 이벤트발생한지 오래 되었으면 제거하여 OOM 예방.

				long firstOcurredAt = event.getCondition().getOcurredAt();

				long diffInMs = System.currentTimeMillis() - firstOcurredAt;

				if (diffInMs >= TimeUnit.MINUTES.toMillis(60)) { // 1시간 지난거면 삭제
					iterator.remove();
				}
			}
		}

	}

	private void send(SendPolicy sendPolicy, AlarmEvent event) {

		UmsRequestPayload payload = null;

		try {

			List<String> cellPhoneList = sendPolicy.getCellPhoneList();

			for (String cellPhone : cellPhoneList) {

				payload = UmsRequestPayload.builder()
						.content(ObpMonitoringUmsTemplate.builder().message(event.getMessage()).build())
						.cellphone(cellPhone).build();
				logger.info("Alarm is disabled, UmsRequestPayload = {}", payload);
				
				umsSendManager.enqueue(payload);
			}

		} catch (Exception e) {
			logger.error(String.format("Alarm message delivery failed (UMS), payload=%s", payload), e);

		}
	}

}