package com.caliverse.admin.domain.service;

import com.caliverse.admin.domain.dao.admin.NoticeMapper;
import com.caliverse.admin.domain.entity.InGame;
import com.caliverse.admin.domain.entity.Message;
import com.caliverse.admin.domain.entity.log.LogAction;
import com.caliverse.admin.domain.entity.log.LogStatus;
import com.caliverse.admin.domain.request.NoticeRequest;
import com.caliverse.admin.domain.response.NoticeResponse;
import com.caliverse.admin.global.common.annotation.BusinessProcess;
import com.caliverse.admin.global.common.code.CommonCode;
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 com.caliverse.admin.scheduler.ScheduleService;
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.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Slf4j
@Service
@RequiredArgsConstructor
public class NoticeService {

    private final NoticeMapper noticeMapper;
    private final ScheduleService scheduleService;
    private final MysqlHistoryLogService mysqlHistoryLogService;
    private final BusinessProcessIdManager processIdManager;

    public NoticeResponse getNoticeList(){

        List<InGame> noticeList = noticeMapper.getNoticeList();

        return NoticeResponse.builder()
                .resultData(NoticeResponse.ResultData.builder()
                        .list(noticeList).build())
                .status(CommonCode.SUCCESS.getHttpStatus())
                .result(CommonCode.SUCCESS.getResult())
                .build();
    }
    public NoticeResponse getNoticeDetail(Long id){

        NoticeResponse.ResultData resultData = null;
        log.info("getNoticeDetail id::"+id);

        InGame inGame = noticeMapper.getNoticeDetail(id);

        if(inGame != null){
            List<Message> noticeMessage = noticeMapper.getMessage(inGame.getId());

            resultData = NoticeResponse.ResultData.builder()
                    .gameMessages(noticeMessage)
                    .inGame(inGame)
                    .build();
        }else{
            // 조회된 데이터가 없습니다.
            return NoticeResponse.builder()
                    .resultData(NoticeResponse.ResultData.builder().message(SuccessCode.NULL_DATA.getMessage()).build())
                    .status(CommonCode.SUCCESS.getHttpStatus())
                    .result(CommonCode.SUCCESS.getResult())
                    .build();
        }

        return NoticeResponse.builder()
                .resultData(resultData)
                .status(CommonCode.SUCCESS.getHttpStatus())
                .result(CommonCode.SUCCESS.getResult())
                .build();
    }

    //인게임 메시지 등록
    @BusinessProcess(action = LogAction.NOTICE)
    @Transactional(transactionManager = "transactionManager")
    public NoticeResponse postInGameMessage(NoticeRequest noticeRequest){
        // 등록자는 메일로 넣어주자
        noticeRequest.setCreateBy(CommonUtils.getAdmin().getId());
        // notice 테이블 insert
        int i = noticeMapper.postNotice(noticeRequest);
        if(i > 0){
            Map<String,Object> map = new HashMap<>();
            noticeRequest.getGameMessages().stream()
                    .filter(item -> !item.getContent().isEmpty())
                    .map(item -> {
                        map.put("id", noticeRequest.getId());
                        map.put("language", item.getLanguage());
                        map.put("content", item.getContent());
                        //메시지 테이블 insert
                        noticeMapper.insertMessage(map);
                        return item;
            }).collect(Collectors.toList());
        }
        log.info("postInGameMessage notice: {}", noticeRequest);

        InGame info = noticeMapper.getNoticeDetail(noticeRequest.getId());
        info.setMessageList(noticeMapper.getMessage(noticeRequest.getId()));

        String prodId = processIdManager.getCurrentProcessId();
        TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() {
            @Override
            public void afterCommit() {
                try {
                    mysqlHistoryLogService.insertHistoryLog(
                            prodId,
                            LogAction.NOTICE,
                            LogStatus.SUCCESS,
                            MysqlConstants.TABLE_NAME_NOTICE,
                            "",
                            info
                    );
                } catch (Exception e) {
                    log.warn("Failed to log notice creation: {}", e.getMessage());
                }
            }
        });

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

    @BusinessProcess(action = LogAction.NOTICE)
    @Transactional(transactionManager = "transactionManager")
    public NoticeResponse updateInGameMessage(Long id, NoticeRequest noticeRequest){
        noticeRequest.setId(id);
        noticeRequest.setUpdateBy(CommonUtils.getAdmin().getId());

        InGame before_info = noticeMapper.getNoticeDetail(id);
        before_info.setMessageList(noticeMapper.getMessage(id));

        int i = noticeMapper.updateNotice(noticeRequest);
        // 스케줄에서 기존 등록 제거
        scheduleService.closeTask(noticeRequest.getId().toString());

        if(i > 0){
            InGame before_notice = noticeMapper.getNoticeDetail(noticeRequest.getId());
            log.info("updateInGameMessage Before notice: {}", before_notice);

            Map<String, Object> map = new HashMap<>();
            //선 삭제 후 insert
            noticeMapper.deleteMessage(noticeRequest.getId());

            for (Message item : noticeRequest.getGameMessages()) {
                String content = item.getContent();

                // content가 null이거나 빈 문자열인 경우 루프 건너뛰기
                if (content == null || content.isEmpty()) {
                    continue;
                }

                map.put("id", noticeRequest.getId());
                map.put("language", item.getLanguage());
                map.put("content", content);
                // 메시지 테이블 insert
                noticeMapper.insertMessage(map);
            }
        }
        log.info("updateInGameMessage After notice: {}", noticeRequest);

        InGame info = noticeMapper.getNoticeDetail(noticeRequest.getId());
        info.setMessageList(noticeMapper.getMessage(noticeRequest.getId()));

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

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

    @BusinessProcess(action = LogAction.NOTICE)
    @Transactional(transactionManager = "transactionManager")
    public NoticeResponse deleteInGameMessage(NoticeRequest noticeRequest){

        Map<String, Object> map = new HashMap<>();
        noticeRequest.getList().forEach(
                item->{

                    noticeMapper.deleteNotice(item.getId());

                    // 스케줄에서 제거
                    scheduleService.closeTask("notice-" + item.getId());

                    log.info("deleteInGameMessage notice: {}", item);

                }
        );
        log.info("deleteInGameMessage notice id: {}", noticeRequest.getList().get(0).getId());
        return NoticeResponse.builder()
                .resultData(NoticeResponse.ResultData.builder().message(SuccessCode.DELETE.getMessage()).build())
                .result(CommonCode.SUCCESS.getResult())
                .status(CommonCode.SUCCESS.getHttpStatus())
                .build();
    }

    public List<InGame> getScheduleNoticeList(){
        return noticeMapper.getSchesuleNoticeList();
    }

    public List<Message> getNoticeMessageList(Long id){
        return noticeMapper.getMessage(id);
    }

    @Transactional(transactionManager = "transactionManager")
    public void updateNoticeStatus(Long id, InGame.SENDSTATUS status){
        HashMap map = new HashMap();
        map.put("id", id);
        map.put("status", status.toString());
        noticeMapper.updateStatusNotice(map);
    }

    public void updateNoticeCount(Long id){
        noticeMapper.updateCountNotice(id);
    }

}
