package com.caliverse.admin.scheduler.service;

import com.caliverse.admin.domain.RabbitMq.MessageHandlerService;
import com.caliverse.admin.domain.RabbitMq.message.LanguageType;
import com.caliverse.admin.domain.RabbitMq.message.MailItem;
import com.caliverse.admin.domain.entity.*;
import com.caliverse.admin.domain.service.EventService;
import com.caliverse.admin.domain.service.HistoryService;
import com.caliverse.admin.dynamodb.entity.SystemMessage;
import com.caliverse.admin.redis.service.RedisUserInfoService;
import com.caliverse.admin.global.common.utils.CommonUtils;
import com.caliverse.admin.global.common.utils.JsonUtils;
import com.caliverse.admin.scheduler.config.ScheduleExecutionConfig;
import com.caliverse.admin.scheduler.ScheduleType;
import com.caliverse.admin.scheduler.Scheduler;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import lombok.*;
import lombok.extern.slf4j.Slf4j;

import java.time.Duration;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;

@Slf4j
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class EventScheduler implements Scheduler {
    private Event event;
    private EventService eventService;
    private RedisUserInfoService redisUserInfoService;
    private MessageHandlerService messageHandlerService;
    private HistoryService historyService;

    @Override
    public void execute() {
        try {
            processEvent();
        } catch (Exception e) {
            log.error("Event execution failed for event ID: {}", event.getId(), e);
            eventService.updateEventStatus(event.getId(), Event.EVENTSTATUS.FAIL);
            historyService.setScheduleLog(HISTORYTYPE.SCHEDULE_EVENT_FAIL, e.getMessage());
        }
    }

    @Override
    public boolean isRepeatable() {
        return false;
    }

    @Override
    public ScheduleType getScheduleType() {
        return ScheduleType.DELAYED;
    }

    @Override
    public ScheduleExecutionConfig getSchedulerConfig() {
        return ScheduleExecutionConfig.builder()
                .taskId("event-" + event.getId())
                .startTime(event.getStartDt())
                .endTime(event.getEndDt())
                .build();
    }

    private void processEvent() {
        LocalDateTime nowDate = LocalDateTime.now();
        LocalDateTime startTime = event.getStartDt();
        LocalDateTime endTime = event.getEndDt();

        // 이벤트가 이미 종료되었는지 체크
        if (nowDate.isAfter(endTime) && event.getStatus().equals(Event.EVENTSTATUS.WAIT)) {
            eventService.updateEventStatus(event.getId(), Event.EVENTSTATUS.FAIL);
            log.error("eventJob eventSchedule timeOut : {}", event);
            return;
        }

        // 시작 30분 전에 게임 DB에 insert
        if (event.getStatus().equals(Event.EVENTSTATUS.WAIT)
                && Duration.between(nowDate, startTime).abs().toMinutes() <= 30
                && !event.isAddFlag()) {

            systemMailInsert();
            eventService.updateEventStatus(event.getId(), Event.EVENTSTATUS.RUNNING);
            log.info("eventJob eventSchedule dynamoDB Insert & Start: {}", event);
        }

        // 종료 시간이 되면 이벤트 종료
        if (!nowDate.isBefore(endTime) && event.getStatus().equals(Event.EVENTSTATUS.RUNNING)) {
            eventService.updateEventStatus(event.getId(), Event.EVENTSTATUS.FINISH);
            log.info("eventJob eventSchedule block end : {}", event);
        }
    }

    private void systemMailInsert() {
        try {
            log.info("systemMailInsert Info: {}", event);

            // 메시지 처리
            List<SystemMessage> mailTitleMessages = new ArrayList<>();
            List<SystemMessage> mailTextMessages = new ArrayList<>();
            List<SystemMessage> mailSenderMessages = new ArrayList<>();
            List<MailItem> mailItems = new ArrayList<>();

            processMessages(mailTitleMessages, mailTextMessages, mailSenderMessages);
            processItems(mailItems);

            // JSON 변환
            ObjectMapper objectMapper = new ObjectMapper();
            ArrayNode mailTitleArray = convertToJsonArray(objectMapper, mailTitleMessages);
            ArrayNode mailTextArray = convertToJsonArray(objectMapper, mailTextMessages);
            ArrayNode mailSenderArray = convertToJsonArray(objectMapper, mailSenderMessages);
            ArrayNode mailItemArray = convertToJsonArray(objectMapper, mailItems);

            // 시스템 메일 등록
            eventService.insertSystemMail(
                    event,
                    mailTitleArray,
                    mailTextArray,
                    mailSenderArray,
                    mailItemArray
            );

        } catch (Exception e) {
            log.error("systemMailInsert Exception: {}", e.getMessage());
            eventService.updateEventStatus(event.getId(), Event.EVENTSTATUS.FAIL);
            historyService.setScheduleLog(HISTORYTYPE.SCHEDULE_EVENT_FAIL, e.getMessage());
            throw new RuntimeException("Failed to insert system mail", e);
        }
    }

    private void processMessages(
            List<SystemMessage> titleMessages,
            List<SystemMessage> textMessages,
            List<SystemMessage> senderMessages
    ) {
        List<Message> msgList = eventService.getMessageList(event.getId());

        for (Message msg : msgList) {
            LanguageConfig langConfig = getLanguageConfig(msg.getLanguage());

            // Title message
            titleMessages.add(SystemMessage.builder()
                    .languageType(langConfig.getLangType())
                    .text(msg.getTitle())
                    .build());

            // Content message
            textMessages.add(SystemMessage.builder()
                    .languageType(langConfig.getLangType())
                    .text(msg.getContent())
                    .build());

            // Sender message
            senderMessages.add(SystemMessage.builder()
                    .languageType(langConfig.getLangType())
                    .text(langConfig.getSender())
                    .build());
        }
    }

    private void processItems(List<MailItem> mailItems) {
        List<Item> itemList = eventService.getItemList(event.getId());

        for (Item item : itemList) {
            mailItems.add(MailItem.newBuilder()
                    .setItemId(CommonUtils.stringToInt(item.getItem()))
                    .setCount(item.getItemCnt())
                    .build());
        }
    }

    @Getter
    @AllArgsConstructor
    private static class LanguageConfig {
        int langType;
        String sender;

        static LanguageConfig from(String language) {
            return switch (language) {
                case "EN" -> new LanguageConfig(
                        LanguageType.LanguageType_en.getNumber(),
                        "CALIVERSE"
                );
                case "JA" -> new LanguageConfig(
                        LanguageType.LanguageType_ja.getNumber(),
                        "カリバース"
                );
                default -> new LanguageConfig(
                        LanguageType.LanguageType_ko.getNumber(),
                        "칼리버스"
                );
            };
        }
    }

    private LanguageConfig getLanguageConfig(String language) {
        return LanguageConfig.from(language);
    }

    private <T> ArrayNode convertToJsonArray(ObjectMapper objectMapper, List<T> items) {
        ArrayNode arrayNode = objectMapper.createArrayNode();

        items.forEach(item -> {
            if (item instanceof SystemMessage) {
                arrayNode.add(JsonUtils.createSystemMessage((SystemMessage) item));
            } else if (item instanceof MailItem) {
                arrayNode.add(JsonUtils.createMAilItem((MailItem) item));
            }
        });

        return arrayNode;
    }
}
