package com.caliverse.admin.domain.service;

import com.caliverse.admin.domain.dao.admin.RewardEventMapper;
import com.caliverse.admin.domain.datacomponent.MetaDataHandler;
import com.caliverse.admin.domain.entity.*;
import com.caliverse.admin.domain.entity.log.LogAction;
import com.caliverse.admin.domain.entity.log.LogStatus;
import com.caliverse.admin.domain.request.RewardEventRequest;
import com.caliverse.admin.domain.response.RewardEventResponse;
import com.caliverse.admin.dynamodb.service.DynamodbMailService;
import com.caliverse.admin.dynamodb.service.DynamodbService;
import com.caliverse.admin.global.common.annotation.BusinessProcess;
import com.caliverse.admin.global.common.annotation.RequestLog;
import com.caliverse.admin.global.common.code.CommonCode;
import com.caliverse.admin.global.common.code.ErrorCode;
import com.caliverse.admin.global.common.code.SuccessCode;
import com.caliverse.admin.global.common.constants.MysqlConstants;
import com.caliverse.admin.global.common.utils.CommonUtils;
import com.caliverse.admin.global.component.manager.BusinessProcessIdManager;
import com.caliverse.admin.mongodb.service.MysqlHistoryLogService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.TransactionSynchronization;
import org.springframework.transaction.support.TransactionSynchronizationManager;

import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Service
@Slf4j
@RequiredArgsConstructor
public class RewardEventService {
    private final DynamodbService dynamodbService;
    private final DynamodbMailService dynamodbMailService;

    private final RewardEventMapper rewardEventMapper;
    private final MetaDataHandler metaDataHandler;
    private final MysqlHistoryLogService mysqlHistoryLogService;
    private final BusinessProcessIdManager processIdManager;

    @RequestLog
    public RewardEventResponse getList(Map requestParam){
        //페이징 처리
        requestParam = CommonUtils.pageSetting(requestParam);

        List<RewardEvent> list = rewardEventMapper.getEventList(requestParam);

        int allCnt = rewardEventMapper.getAllCnt(requestParam);

        return RewardEventResponse.builder()
                .status(CommonCode.SUCCESS.getHttpStatus())
                .result(CommonCode.SUCCESS.getResult())
                .resultData(RewardEventResponse.ResultData.builder()
                        .rewardEventList(list)
                        .total(rewardEventMapper.getTotal())
                        .totalAll(allCnt)
                        .pageNo(requestParam.get("page_no")!=null?
                                Integer.valueOf(requestParam.get("page_no").toString()):1)
                        .build()
                )
                .build();
    }

    @RequestLog
    public RewardEventResponse getDetail(Long id){
        RewardEvent rewardEvent = rewardEventMapper.getEventDetail(id);

        rewardEvent.setMailList(rewardEventMapper.getMessage(id));
        List<Item> itemList = rewardEventMapper.getItem(id);
        for(Item item : itemList){
            String itemName = metaDataHandler.getMetaItemNameData(Integer.parseInt(item.getItem()));
            item.setItemName(metaDataHandler.getTextStringData(itemName));
        }
        rewardEvent.setItemList(itemList);

        log.info("getDetail call User Email: {}, event_id: {}", CommonUtils.getAdmin().getEmail(), id);

        return RewardEventResponse.builder()
                .status(CommonCode.SUCCESS.getHttpStatus())
                .result(CommonCode.SUCCESS.getResult())
                .resultData(RewardEventResponse.ResultData.builder()
                        .rewardEvent(rewardEvent)
                        .build())
                .build();
    }

    @BusinessProcess(action = LogAction.EVENT)
    @Transactional(transactionManager = "transactionManager")
    @RequestLog
    public RewardEventResponse postEvent(RewardEventRequest rewardEventRequest){
        rewardEventRequest.setCreateBy(CommonUtils.getAdmin().getId());

        int result = rewardEventMapper.postEvent(rewardEventRequest);
        log.info("postEvent AdminToolDB Event Save id: {}", rewardEventRequest.getId());

        long event_id = rewardEventRequest.getId();

        HashMap<String,String> map = new HashMap<>();
        map.put("mailId",String.valueOf(event_id));

        //아이템 저장
        if(rewardEventRequest.getItemList()!= null && !rewardEventRequest.getItemList().isEmpty()){
            rewardEventRequest.getItemList().forEach(
                    item -> {
                        map.put("goodsId",item.getItem());
                        map.put("itemCnt",String.valueOf(item.getItemCnt()));
                        rewardEventMapper.insertItem(map);
                    }
            );
        }
        log.info("postEvent AdminToolDB Item Save Complete");

        //메시지 저장
        if(rewardEventRequest.getMailList()!= null && !rewardEventRequest.getMailList().isEmpty()){
            rewardEventRequest.getMailList().forEach(
                    item -> {
                        map.put("title",item.getTitle());
                        map.put("content",item.getContent());
                        map.put("language",item.getLanguage());
                        rewardEventMapper.insertMessage(map);
                    }
            );
        }
        log.info("postEvent AdminToolDB Message Save Complete");

        String prodId = processIdManager.getCurrentProcessId();

        RewardEvent rewardEvent = rewardEventMapper.getEventDetail(event_id);
        rewardEvent.setMailList(rewardEventMapper.getMessage(event_id));
        rewardEvent.setItemList(rewardEventMapper.getItem(event_id));

        TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() {
            @Override
            public void afterCommit() {
                try {
                    mysqlHistoryLogService.insertHistoryLog(
                            prodId,
                            LogAction.EVENT,
                            LogStatus.SUCCESS,
                            MysqlConstants.TABLE_NAME_EVENT,
                            "",
                            rewardEvent
                    );
                } catch (Exception e) {
                    log.warn("Failed to log event creation: {}", e.getMessage());
                }
            }
        });

        return RewardEventResponse.builder()
                .status(CommonCode.SUCCESS.getHttpStatus())
                .result(CommonCode.SUCCESS.getResult())
                .resultData(RewardEventResponse.ResultData.builder()
                        .message(SuccessCode.SAVE.getMessage())
                        .build())
                .build();
    }

    @BusinessProcess(action = LogAction.EVENT)
    @Transactional(transactionManager = "transactionManager")
    @RequestLog
    public RewardEventResponse updateEvent(Long id, RewardEventRequest rewardEventRequest) {
        rewardEventRequest.setId(id);
        rewardEventRequest.setUpdateBy(CommonUtils.getAdmin().getId());
        rewardEventRequest.setUpdateDt(LocalDateTime.now());

        Long event_id = rewardEventRequest.getId();
        RewardEvent before_info = rewardEventMapper.getEventDetail(event_id);
        before_info.setMailList(rewardEventMapper.getMessage(event_id));
        before_info.setItemList(rewardEventMapper.getItem(event_id));

        int result = rewardEventMapper.updateEvent(rewardEventRequest);

        Map<String, String> map = new HashMap<>();
        map.put("mailId", String.valueOf(event_id));

        // item 테이블 데이터 삭제 처리 by event_id
        rewardEventMapper.deleteItem(map);

        // 아이템 업데이트
        if (rewardEventRequest.getItemList() != null && !rewardEventRequest.getItemList().isEmpty()) {
            rewardEventRequest.getItemList().forEach(item -> {
                map.put("goodsId", item.getItem());
                map.put("itemCnt", String.valueOf(item.getItemCnt()));

                rewardEventMapper.insertItem(map);
            });
        }

        // message 테이블 데이터 삭제 처리 by mail_id
        rewardEventMapper.deleteMessage(map);

        // 메시지 업데이트
        if (rewardEventRequest.getMailList() != null && !rewardEventRequest.getMailList().isEmpty()) {
            rewardEventRequest.getMailList().forEach(item -> {
                map.put("title", item.getTitle());
                map.put("content", item.getContent());
                map.put("language", item.getLanguage());

                rewardEventMapper.insertMessage(map);
            });
        }
        log.info("updateEvent AdminToolDB Event Update Complete id: {}", rewardEventRequest.getId());

        RewardEvent after_Reward_event = rewardEventMapper.getEventDetail(event_id);
        after_Reward_event.setMailList(rewardEventMapper.getMessage(event_id));
        after_Reward_event.setItemList(rewardEventMapper.getItem(event_id));

        String prodId = processIdManager.getCurrentProcessId();
        TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() {
            @Override
            public void afterCommit() {
                try {
                    mysqlHistoryLogService.updateHistoryLog(
                            prodId,
                            LogAction.EVENT,
                            LogStatus.SUCCESS,
                            MysqlConstants.TABLE_NAME_EVENT,
                            "",
                            before_info,
                            after_Reward_event
                    );
                } catch (Exception e) {
                    log.warn("Failed to log event creation: {}", e.getMessage());
                }
            }
        });

        return RewardEventResponse.builder()
                .status(CommonCode.SUCCESS.getHttpStatus())
                .result(CommonCode.SUCCESS.getResult())
                .resultData(RewardEventResponse.ResultData.builder()
                        .message(SuccessCode.UPDATE.getMessage())
                        .build())
                .build();
    }

    @BusinessProcess(action = LogAction.EVENT)
    @Transactional(transactionManager = "transactionManager")
    @RequestLog
    public RewardEventResponse deleteEvent(RewardEventRequest rewardEventRequest){
        Map<String,Object> map = new HashMap<>();

        rewardEventRequest.getList().forEach(
                item->{
                    Long event_id = item.getId();
                    RewardEvent rewardEvent = rewardEventMapper.getEventDetail(event_id);
                    rewardEvent.setMailList(rewardEventMapper.getMessage(event_id));
                    rewardEvent.setItemList(rewardEventMapper.getItem(event_id));

                    map.put("id",event_id);
                    map.put("desc", item.getDeleteDesc());
                    int result = rewardEventMapper.deleteEvent(map);
                    log.info("updateEvent AdminTool Delete Complete id: {}", event_id);
                }
        );

        return RewardEventResponse.builder()
                .status(CommonCode.SUCCESS.getHttpStatus())
                .result(CommonCode.SUCCESS.getResult())
                .resultData(RewardEventResponse.ResultData.builder()
                        .message(SuccessCode.DELETE.getMessage())
                        .build())
                .build();
    }

    public List<RewardEvent> getScheduleMailList(){
        return rewardEventMapper.getScheduleEventList();
    }
    public List<Message> getMessageList(Long id){
        return rewardEventMapper.getMessage(id);
    }

    public List<Item> getItemList(Long id){
        return rewardEventMapper.getItem(id);
    }

    @Transactional(transactionManager = "transactionManager")
    public void updateEventStatus(Long id, RewardEvent.EVENTSTATUS status){
        Map<String,Object> map = new HashMap<>();
        map.put("id", id);
        map.put("status", status.toString());
        rewardEventMapper.updateStatusEvent(map);
        log.info("updateEventStatus event status changed: {}", status);
    }

    //메타 아이템
    public RewardEventResponse getMetaItem(String metaId){
        long id = Long.parseLong(metaId);
        String item = metaDataHandler.getMetaItemNameData((int) id);
        boolean isItem = (item != null && !item.isEmpty());
        if(isItem) {
            Item item_info = new Item();
            item_info.setItem(metaId);
            item_info.setItemName(metaDataHandler.getTextStringData(item));
            return RewardEventResponse.builder()
                    .status(CommonCode.SUCCESS.getHttpStatus())
                    .result(CommonCode.SUCCESS.getResult())
                    .resultData(RewardEventResponse.ResultData.builder()
                            .message(SuccessCode.ITEM_EXIST.getMessage())
                            .itemInfo(item_info)
                            .build())
                    .build();
        }else
            return RewardEventResponse.builder()
                    .status(CommonCode.ERROR.getHttpStatus())
                    .result(CommonCode.ERROR.getResult())
                    .resultData(RewardEventResponse.ResultData.builder()
                            .message(ErrorCode.NOT_ITEM.getMessage())
                            .build())
                    .build();
    }

    @Transactional(transactionManager = "transactionManager")
    public void insertSystemMail(RewardEvent rewardEvent){
        try {
            long event_id = rewardEvent.getId();
            rewardEvent.setMailList(rewardEventMapper.getMessage(event_id));
            rewardEvent.setItemList(rewardEventMapper.getItem(event_id));

            dynamodbMailService.insertSystemMail(rewardEvent);

            rewardEventMapper.updateAddFlag(event_id);
            updateEventStatus(event_id, RewardEvent.EVENTSTATUS.RUNNING);

            log.info("insertSystemMail Save Complete: {}", rewardEvent.getId());
        }catch (Exception e){
            log.error("insertSystemMail Exception: {}", e.getMessage());
            updateEventStatus(rewardEvent.getId(), RewardEvent.EVENTSTATUS.FAIL);
        }
    }
}
