package com.caliverse.admin.domain.service;

import com.caliverse.admin.Indicators.entity.*;
import com.caliverse.admin.domain.cache.CommonCacheHandler;
import com.caliverse.admin.domain.entity.excel.ExcelBusinessLog;
import com.caliverse.admin.domain.entity.log.GenericLog;
import com.caliverse.admin.domain.request.LogGameRequest;
import com.caliverse.admin.domain.request.LogGenericRequest;
import com.caliverse.admin.domain.response.IndicatorsResponse;
import com.caliverse.admin.domain.response.LogResponse;
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.exception.RestApiException;
import com.caliverse.admin.global.common.utils.CommonUtils;
import com.caliverse.admin.global.common.utils.DateUtils;
import com.caliverse.admin.global.component.tracker.ExcelProgressTracker;
import com.caliverse.admin.logs.Indicatordomain.GenericMongoLog;
import com.caliverse.admin.logs.logservice.businesslogservice.BusinessLogGenericService;
import com.caliverse.admin.logs.logservice.indicators.*;
import com.caliverse.admin.mongodb.dto.MongoPageResult;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.data.mongodb.UncategorizedMongoDbException;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.stream.Collectors;

@Service
@RequiredArgsConstructor
@Slf4j
public class LogService {

    private final BusinessLogGenericService businessLogGenericService;
    private final ExcelService excelService;
    private final CommonCacheHandler commonCacheHandler;
    private final ExcelProgressTracker progressTracker;
    private final IndicatorsCurrencyService  indicatorsCurrencyService;
    private final IndicatorsItemService indicatorsItemService;
    private final IndicatorsUserLoginService indicatorsUserLoginService;
    private final IndicatorsUserCreateService indicatorsUserCreateService;
    private final IndicatorsSnapshotService indicatorsSnapshotService;

    @RequestLog
    public LogResponse genericLogList(LogGenericRequest logGenericRequest){
        int page = logGenericRequest.getPageNo();
        int size = logGenericRequest.getPageSize();

        LocalDateTime startDt = logGenericRequest.getStartDt().plusHours(9);
        LocalDateTime endDt = logGenericRequest.getEndDt().plusHours(9).plusDays(1);
        logGenericRequest.setStartDt(startDt);
        logGenericRequest.setEndDt(endDt);

        // 병렬 처리를 위한 CompletableFuture 생성
        CompletableFuture<List<GenericLog>> logListFuture = CompletableFuture.supplyAsync(() -> {
            try {
                return businessLogGenericService.loadBusinessLogData(logGenericRequest, GenericLog.class);
            } catch (UncategorizedMongoDbException e) {
                if (e.getMessage().contains("Sort exceeded memory limit")) {
                    log.error("MongoDB Query memory limit error: {}", e.getMessage());
                    throw new RuntimeException("MEMORY_LIMIT_ERROR", e);
                } else if (e.getMessage().contains("time limit")) {
                    log.error("MongoDB Query operation exceeded time limit: {}", e.getMessage());
                    throw new RuntimeException("TIME_LIMIT_ERROR", e);
                } else {
                    log.error("MongoDB Query error", e);
                    throw new RuntimeException("MONGODB_QUERY_ERROR", e);
                }
            } catch (Exception e) {
                log.error("businessLog error", e);
                throw new RuntimeException("BUSINESS_LOG_ERROR", e);
            }
        });

        CompletableFuture<Integer> totalCountFuture = CompletableFuture.supplyAsync(() -> commonCacheHandler.getLogCount(logGenericRequest));

        try {
            // 두 작업이 모두 완료될 때까지 대기
            List<GenericLog> logList = logListFuture.get();
            int totalAll = totalCountFuture.get();

            int totalItems = logList.size();

            return LogResponse.builder()
                    .resultData(LogResponse.ResultData.builder()
                            .genericList(logList)
                            .total(totalItems)
                            .totalAll(totalAll)
                            .pageNo(logGenericRequest.getPageNo() != null ? page : 1)
                            .build())
                    .status(CommonCode.SUCCESS.getHttpStatus())
                    .result(CommonCode.SUCCESS.getResult())
                    .build();

        } catch (ExecutionException e) {
            Throwable cause = e.getCause();
            if (cause instanceof RuntimeException) {
                RuntimeException runtimeException = (RuntimeException) cause;
                String message = runtimeException.getMessage();

                if ("MEMORY_LIMIT_ERROR".equals(message)) {
                    return LogResponse.builder()
                            .status(CommonCode.ERROR.getHttpStatus())
                            .result(ErrorCode.ERROR_LOG_MEMORY_LIMIT.toString())
                            .build();
                } else if ("TIME_LIMIT_ERROR".equals(message)) {
                    return LogResponse.builder()
                            .status(CommonCode.ERROR.getHttpStatus())
                            .result(ErrorCode.ERROR_LOG_MEMORY_LIMIT.toString())
                            .build();
                } else if ("MONGODB_QUERY_ERROR".equals(message)) {
                    return LogResponse.builder()
                            .status(CommonCode.ERROR.getHttpStatus())
                            .result(ErrorCode.ERROR_MONGODB_QUERY.toString())
                            .build();
                }
            }
            log.error("Parallel execution error", e);
            return LogResponse.builder()
                    .status(CommonCode.ERROR.getHttpStatus())
                    .result(CommonCode.ERROR.getResult())
                    .build();
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            log.error("Thread interrupted", e);
            return LogResponse.builder()
                    .status(CommonCode.ERROR.getHttpStatus())
                    .result(CommonCode.ERROR.getResult())
                    .build();
        }
    }

//    public LogResponse genericLogList(LogGenericRequest logGenericRequest){
//        int page = logGenericRequest.getPageNo();
//        int size = logGenericRequest.getPageSize();
//
////        LocalDateTime startDt = logGenericRequest.getStartDt().plusHours(9);
////        LocalDateTime endDt = logGenericRequest.getEndDt().plusHours(9).plusDays(1);
////        logGenericRequest.setStartDt(startDt);
////        logGenericRequest.setEndDt(endDt);
//
////        List<Map<String, Object>> logList = businessLogGenericService.loadBusinessLogData(logGenericRequest);
//        LocalDateTime startDt = logGenericRequest.getStartDt().plusHours(9);
//        LocalDateTime endDt = logGenericRequest.getEndDt().plusHours(9).plusDays(1);
//        logGenericRequest.setStartDt(startDt);
//        logGenericRequest.setEndDt(endDt);
//
//        List<GenericLog> logList = new ArrayList<>();
//        try{
//            logList = businessLogGenericService.loadBusinessLogData(logGenericRequest, GenericLog.class);
//        }catch(UncategorizedMongoDbException e){
//            if (e.getMessage().contains("Sort exceeded memory limit")) {
//                log.error("MongoDB Query memory limit error: {}", e.getMessage());
//                return LogResponse.builder()
//                        .status(CommonCode.ERROR.getHttpStatus())
//                        .result(ErrorCode.ERROR_LOG_MEMORY_LIMIT.toString())
//                        .build();
//            } else if (e.getMessage().contains("time limit")) {
//                log.error("MongoDB Query operation exceeded time limit: {}", e.getMessage());
//                return LogResponse.builder()
//                        .status(CommonCode.ERROR.getHttpStatus())
//                        .result(ErrorCode.ERROR_LOG_MEMORY_LIMIT.toString())
//                        .build();
//            }else {
//                log.error("MongoDB Query error", e);
//                return LogResponse.builder()
//                        .status(CommonCode.ERROR.getHttpStatus())
//                        .result(ErrorCode.ERROR_MONGODB_QUERY.toString())
//                        .build();
//            }
//        }catch (Exception e){
//            log.error("businessLog error", e);
//        }
//
////        logList = logList.stream().map(logData -> {
////            try {
////                var header = logData.getMessage().get("Header");
////                var body = logData.getMessage().get("Body");
////                logData.setHeader((Map<String, Object>) header);
////                logData.setBody((Map<String, Object>) body);
////                logData.setMessage("");
////                return logData;
////            } catch (Exception e) {
////                log.error("Error parsing JSON from message field", e);
////                logData.setMessage(null);
////                return logData;
////            }
////        }).collect(Collectors.toList());
//
//        int totalItems = logList.size();
//        int totalAll = commonCacheHandler.getLogCount(logGenericRequest);
//        return LogResponse.builder()
//             .resultData(LogResponse.ResultData.builder()
//                     .genericList(logList)
//                     .total(totalItems)
//                     .totalAll(totalAll)
//                     .pageNo(logGenericRequest.getPageNo() != null ?
//                             page : 1)
//                     .build())
//             .status(CommonCode.SUCCESS.getHttpStatus())
//             .result(CommonCode.SUCCESS.getResult())
//             .build();
//
//    }

    public void genericExcelExport(HttpServletResponse response, LogGenericRequest logGenericRequest){
        String taskId = logGenericRequest.getTaskId();
        LocalDateTime startDt = logGenericRequest.getStartDt().plusHours(9);
        LocalDateTime endDt = logGenericRequest.getEndDt().plusHours(9).plusDays(1);
        logGenericRequest.setStartDt(startDt);
        logGenericRequest.setEndDt(endDt);
        logGenericRequest.setPageNo(null);
        logGenericRequest.setPageSize(null);
        progressTracker.updateProgress(taskId, 5, 100, "엑셀 생성 준비 중...");


        List<GenericLog> logList = new ArrayList<>();
        try{
            logList = businessLogGenericService.loadBusinessLogData(logGenericRequest, GenericLog.class);
            progressTracker.updateProgress(taskId, 20, 100, "데이터 생성완료");
        }catch(UncategorizedMongoDbException e){
            if (e.getMessage().contains("Sort exceeded memory limit")) {
                log.error("MongoDB Query memory limit error: {}", e.getMessage());
                throw new RestApiException(CommonCode.ERROR.getHttpStatus(), ErrorCode.ERROR_LOG_MEMORY_LIMIT.toString());
            } else if (e.getMessage().contains("time limit")) {
                log.error("MongoDB Query operation exceeded time limit: {}", e.getMessage());
                throw new RestApiException(CommonCode.ERROR.getHttpStatus(), ErrorCode.ERROR_LOG_MEMORY_LIMIT.toString());
            }else {
                log.error("MongoDB Query error", e);
                throw new RestApiException(CommonCode.ERROR.getHttpStatus(), ErrorCode.ERROR_MONGODB_QUERY.toString());
            }
        }catch (Exception e){
            log.error("ExcelExport Data Search Error", e);
        }

        progressTracker.updateProgress(taskId, 25, 100, "데이터 파싱 준비중...");
        List<ExcelBusinessLog> excelList = logList.stream()
                .map(logData -> {
                    try {
                        return ExcelBusinessLog.builder()
                                .logTime(logData.getLogTime())
                                .accountId(logData.getAccountId())
                                .userGuid(logData.getUserGuid())
                                .userNickname(logData.getUserNickname())
                                .tranId(logData.getTranId())
                                .action(logData.getAction())
                                .domain(logData.getDomain())
                                .header(logData.getHeader())
                                .body(logData.getBody())
                                .build();
                    } catch (Exception e) {
                        log.error("Error parsing JSON from message field", e);
                        return null;
                    }
                })
                .filter(Objects::nonNull) // null 값 제거
                .toList();
        progressTracker.updateProgress(taskId, 30, 100, "데이터 파싱 완료...");

        try{
            excelService.generateExcelToResponse(
                    response,
                    excelList,
                    "비즈니스 로그 데이터",
                    "sheet1",
                    taskId
            );

        }catch (Exception e){
            log.error("Excel Export Create Error", e);
            throw new RestApiException(CommonCode.ERROR.getHttpStatus(), ErrorCode.ERROR_EXCEL_DOWN.toString());
        }

    }

    public Map<String, Object> getProgress(String taskId){
        try {
            ExcelProgressTracker.ProgressInfo progress = progressTracker.getProgress(taskId);

            if (progress == null) {
                Map<String, Object> response = new HashMap<>();
                response.put("exists", false);
                return (response);
            }

            Map<String, Object> response = new HashMap<>();
            response.put("exists", true);
            response.put("percentage", progress.getPercentage());
            response.put("currentStep", progress.getCurrentStep());
            response.put("totalSteps", progress.getTotalSteps());
            response.put("message", progress.getMessage());

            return response;
        }catch (Exception e){
            log.error(e.getMessage());
            throw new RestApiException(CommonCode.ERROR.getHttpStatus(), ErrorCode.ERROR_EXCEL_DOWN.toString());
        }
    }

    @RequestLog
    public LogResponse getCurrencyLogList(Map<String, String> requestParams){
        LocalDateTime startDt = DateUtils.stringISOToLocalDateTime(requestParams.get("start_dt"));
        LocalDateTime endDt = DateUtils.stringISOToLocalDateTime(requestParams.get("end_dt"));
        List<CurrencyLogInfo> currencyLogList = indicatorsCurrencyService.getIndicatorsLogData(
                startDt.toString().substring(0, 10),
                endDt.toString().substring(0, 10),
                CurrencyLogInfo.class);

        List<LogResponse.currencyLog> currencyList = new ArrayList<>();
        for (CurrencyLogInfo info : currencyLogList){
            LogResponse.currencyLog build = LogResponse.currencyLog.builder()
                    .logDay(info.getLogDay())
                    .accountId(info.getAccountId())
                    .userGuid(info.getUserGuid())
                    .userNickname(info.getUserNickname())
                    .goldAcquired(info.getGoldAcquired())
                    .goldConsumed(info.getGoldConsumed())
                    .goldNet(info.getGoldNet())
                    .sapphireAcquired(info.getSapphireAcquired())
                    .sapphireConsumed(info.getSapphireConsumed())
                    .sapphireNet(info.getSapphireNet())
                    .beamAcquired(info.getBeamAcquired())
                    .beamConsumed(info.getBeamConsumed())
                    .beamNet(info.getBeamNet())
                    .caliumAcquired(info.getCaliumAcquired())
                    .caliumConsumed(info.getCaliumConsumed())
                    .caliumNet(info.getCaliumNet())
                    .rubyAcquired(info.getRubyAcquired())
                    .rubyConsumed(info.getRubyConsumed())
                    .rubyNet(info.getRubyNet())
                    .totalCurrencies(info.getTotalCurrencies())
                    .build();
            currencyList.add(build);
        }

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

    public void currencyExcelExport(HttpServletResponse response, LogGameRequest logGameRequest){
        String taskId = logGameRequest.getTaskId();
        LocalDateTime startDt = logGameRequest.getStartDt().plusHours(9);
        LocalDateTime endDt = logGameRequest.getEndDt().plusHours(9).plusDays(1);
        logGameRequest.setStartDt(startDt);
        logGameRequest.setEndDt(endDt);
        logGameRequest.setPageNo(null);
        logGameRequest.setPageSize(null);
        progressTracker.updateProgress(taskId, 5, 100, "엑셀 생성 준비 중...");

        List<CurrencyLogInfo> result = null;
        try{
            result = indicatorsCurrencyService.getIndicatorsLogData(
                    startDt.toString().substring(0, 10),
                    endDt.toString().substring(0, 10),
                    CurrencyLogInfo.class
            );
            progressTracker.updateProgress(taskId, 20, 100, "데이터 생성완료");
        }catch(UncategorizedMongoDbException e){
            if (e.getMessage().contains("Sort exceeded memory limit")) {
                log.error("MongoDB Query memory limit error: {}", e.getMessage());
                throw new RestApiException(CommonCode.ERROR.getHttpStatus(), ErrorCode.ERROR_LOG_MEMORY_LIMIT.toString());
            } else if (e.getMessage().contains("time limit")) {
                log.error("MongoDB Query operation exceeded time limit: {}", e.getMessage());
                throw new RestApiException(CommonCode.ERROR.getHttpStatus(), ErrorCode.ERROR_LOG_MEMORY_LIMIT.toString());
            }else {
                log.error("MongoDB Query error", e);
                throw new RestApiException(CommonCode.ERROR.getHttpStatus(), ErrorCode.ERROR_MONGODB_QUERY.toString());
            }
        }catch (Exception e){
            log.error("currencyExcelExport ExcelExport Data Search Error", e);
        }

        List<LogResponse.currencyLog> currencyList = new ArrayList<>();
        for (CurrencyLogInfo info : result){
            LogResponse.currencyLog build = LogResponse.currencyLog.builder()
                    .logDay(info.getLogDay())
                    .accountId(info.getAccountId())
                    .userGuid(info.getUserGuid())
                    .userNickname(info.getUserNickname())
                    .goldAcquired(info.getGoldAcquired())
                    .goldConsumed(info.getGoldConsumed())
                    .goldNet(info.getGoldNet())
                    .sapphireAcquired(info.getSapphireAcquired())
                    .sapphireConsumed(info.getSapphireConsumed())
                    .sapphireNet(info.getSapphireNet())
                    .beamAcquired(info.getBeamAcquired())
                    .beamConsumed(info.getBeamConsumed())
                    .beamNet(info.getBeamNet())
                    .caliumAcquired(info.getCaliumAcquired())
                    .caliumConsumed(info.getCaliumConsumed())
                    .caliumNet(info.getCaliumNet())
                    .rubyAcquired(info.getRubyAcquired())
                    .rubyConsumed(info.getRubyConsumed())
                    .rubyNet(info.getRubyNet())
                    .totalCurrencies(info.getTotalCurrencies())
                    .build();
            currencyList.add(build);
        }
        progressTracker.updateProgress(taskId, 30, 100, "데이터 파싱 완료...");

        try{
            excelService.generateExcelToResponse(
                    response,
                    currencyList,
                    "재화 지표 데이터",
                    "sheet1",
                    taskId
            );

        }catch (Exception e){
            log.error("currencyExcelExport Excel Export Create Error", e);
            throw new RestApiException(CommonCode.ERROR.getHttpStatus(), ErrorCode.ERROR_EXCEL_DOWN.toString());
        }

    }

    @RequestLog
    public LogResponse getCurrencyDetailLogList(Map<String, String> requestParams){
        String searchType = requestParams.get("search_type");
        String searchData = requestParams.get("search_data");
        String tranId = requestParams.get("tran_id");
        String logAction = requestParams.get("log_action");
        String currencyType = requestParams.get("currency_type");
        String amountDeltaType = requestParams.get("amount_delta_type");
        LocalDateTime startDt = DateUtils.stringISOToLocalDateTime(requestParams.get("start_dt"));
        LocalDateTime endDt = DateUtils.stringISOToLocalDateTime(requestParams.get("end_dt"));
        String orderBy = requestParams.get("orderby");
        int pageNo = Integer.parseInt(requestParams.get("page_no"));
        int pageSize = Integer.parseInt(requestParams.get("page_size"));
        MongoPageResult<CurrencyDetailLogInfo> result = indicatorsCurrencyService.getCurrencyDetailLogData(
                searchType,
                searchData,
                tranId,
                logAction,
                currencyType,
                amountDeltaType,
                startDt.toString().substring(0, 10),
                endDt.toString().substring(0, 10),
                orderBy,
                pageNo,
                pageSize,
                CurrencyDetailLogInfo.class
        );

        List<CurrencyDetailLogInfo> currencyLogList = result.getItems();
        int totalCount = result.getTotalCount();

        return LogResponse.builder()
                .resultData(LogResponse.ResultData.builder()
                        .currencyDetailList(currencyLogList)
                        .total(currencyLogList.size())
                        .totalAll(totalCount)
                        .pageNo(pageNo)
                        .build())
                .status(CommonCode.SUCCESS.getHttpStatus())
                .result(CommonCode.SUCCESS.getResult())
                .build();
    }

    public void currencyDetailExcelExport(HttpServletResponse response, LogGameRequest logGameRequest){
        String taskId = logGameRequest.getTaskId();
        LocalDateTime startDt = logGameRequest.getStartDt().plusHours(9);
        LocalDateTime endDt = logGameRequest.getEndDt().plusHours(9).plusDays(1);
        logGameRequest.setStartDt(startDt);
        logGameRequest.setEndDt(endDt);
        logGameRequest.setPageNo(null);
        logGameRequest.setPageSize(null);
        progressTracker.updateProgress(taskId, 5, 100, "엑셀 생성 준비 중...");

        MongoPageResult<CurrencyDetailLogInfo> result = null;
        try{
            result = indicatorsCurrencyService.getCurrencyDetailLogData(
                    logGameRequest.getSearchType().toString(),
                    logGameRequest.getSearchData(),
                    logGameRequest.getTranId(),
                    logGameRequest.getLogAction().name(),
                    logGameRequest.getCurrencyType().name(),
                    logGameRequest.getAmountDeltaType().name(),
                    startDt.toString().substring(0, 10),
                    endDt.toString().substring(0, 10),
                    logGameRequest.getOrderBy(),
                    logGameRequest.getPageNo(),
                    logGameRequest.getPageSize(),
                    CurrencyDetailLogInfo.class
            );
            progressTracker.updateProgress(taskId, 20, 100, "데이터 생성완료");
        }catch(UncategorizedMongoDbException e){
            if (e.getMessage().contains("Sort exceeded memory limit")) {
                log.error("MongoDB Query memory limit error: {}", e.getMessage());
                throw new RestApiException(CommonCode.ERROR.getHttpStatus(), ErrorCode.ERROR_LOG_MEMORY_LIMIT.toString());
            } else if (e.getMessage().contains("time limit")) {
                log.error("MongoDB Query operation exceeded time limit: {}", e.getMessage());
                throw new RestApiException(CommonCode.ERROR.getHttpStatus(), ErrorCode.ERROR_LOG_MEMORY_LIMIT.toString());
            }else {
                log.error("MongoDB Query error", e);
                throw new RestApiException(CommonCode.ERROR.getHttpStatus(), ErrorCode.ERROR_MONGODB_QUERY.toString());
            }
        }catch (Exception e){
            log.error("currencyDetailExcelExport ExcelExport Data Search Error", e);
        }

        List<CurrencyDetailLogInfo> currencyLogList = result.getItems();
        progressTracker.updateProgress(taskId, 30, 100, "데이터 파싱 완료...");

        try{
            excelService.generateExcelToResponse(
                    response,
                    currencyLogList,
                    "게임 재화 로그 데이터",
                    "sheet1",
                    taskId
            );

        }catch (Exception e){
            log.error("currencyDetailExcelExport Excel Export Create Error", e);
            throw new RestApiException(CommonCode.ERROR.getHttpStatus(), ErrorCode.ERROR_EXCEL_DOWN.toString());
        }

    }

    @RequestLog
    public LogResponse getItemDetailLogList(Map<String, String> requestParams){
        String searchType = requestParams.get("search_type");
        String searchData = requestParams.get("search_data");
        String tranId = requestParams.get("tran_id");
        String logAction = requestParams.get("log_action");
        String itemLargeType = requestParams.get("item_large_type");
        String itemSmallType = requestParams.get("item_small_type");
        String countDeltaType = requestParams.get("count_delta_type");
        LocalDateTime startDt = DateUtils.stringISOToLocalDateTime(requestParams.get("start_dt"));
        LocalDateTime endDt = DateUtils.stringISOToLocalDateTime(requestParams.get("end_dt"));
        String orderBy = requestParams.get("orderby");
        int pageNo = Integer.parseInt(requestParams.get("page_no"));
        int pageSize = Integer.parseInt(requestParams.get("page_size"));
        MongoPageResult<ItemDetailLogInfo> result = indicatorsItemService.getItemDetailLogData(
                searchType,
                searchData,
                tranId,
                logAction,
                itemLargeType,
                itemSmallType,
                countDeltaType,
                startDt.toString().substring(0, 10),
                endDt.toString().substring(0, 10),
                orderBy,
                pageNo,
                pageSize,
                ItemDetailLogInfo.class
        );

        List<ItemDetailLogInfo> itemLogList = result.getItems();
        int totalCount = result.getTotalCount();

        return LogResponse.builder()
                .resultData(LogResponse.ResultData.builder()
                        .itemDetailList(itemLogList)
                        .total(itemLogList.size())
                        .totalAll(totalCount)
                        .pageNo(pageNo)
                        .build())
                .status(CommonCode.SUCCESS.getHttpStatus())
                .result(CommonCode.SUCCESS.getResult())
                .build();
    }

    public void itemDetailExcelExport(HttpServletResponse response, LogGameRequest logGameRequest){
        String taskId = logGameRequest.getTaskId();
        LocalDateTime startDt = logGameRequest.getStartDt().plusHours(9);
        LocalDateTime endDt = logGameRequest.getEndDt().plusHours(9).plusDays(1);
        logGameRequest.setStartDt(startDt);
        logGameRequest.setEndDt(endDt);
        logGameRequest.setPageNo(null);
        logGameRequest.setPageSize(null);
        progressTracker.updateProgress(taskId, 5, 100, "엑셀 생성 준비 중...");

        MongoPageResult<ItemDetailLogInfo> result = null;
        try{
            result = indicatorsItemService.getItemDetailLogData(
                    logGameRequest.getSearchType().toString(),
                    logGameRequest.getSearchData(),
                    logGameRequest.getTranId(),
                    logGameRequest.getLogAction().name(),
                    logGameRequest.getItemTypeLarge(),
                    logGameRequest.getItemTypeSmall(),
                    logGameRequest.getCountDeltaType().name(),
                    startDt.toString().substring(0, 10),
                    endDt.toString().substring(0, 10),
                    logGameRequest.getOrderBy(),
                    logGameRequest.getPageNo(),
                    logGameRequest.getPageSize(),
                    ItemDetailLogInfo.class
            );
            progressTracker.updateProgress(taskId, 20, 100, "데이터 생성완료");
        }catch(UncategorizedMongoDbException e){
            if (e.getMessage().contains("Sort exceeded memory limit")) {
                log.error("MongoDB Query memory limit error: {}", e.getMessage());
                throw new RestApiException(CommonCode.ERROR.getHttpStatus(), ErrorCode.ERROR_LOG_MEMORY_LIMIT.toString());
            } else if (e.getMessage().contains("time limit")) {
                log.error("MongoDB Query operation exceeded time limit: {}", e.getMessage());
                throw new RestApiException(CommonCode.ERROR.getHttpStatus(), ErrorCode.ERROR_LOG_MEMORY_LIMIT.toString());
            }else {
                log.error("MongoDB Query error", e);
                throw new RestApiException(CommonCode.ERROR.getHttpStatus(), ErrorCode.ERROR_MONGODB_QUERY.toString());
            }
        }catch (Exception e){
            log.error("itemDetailExcelExport ExcelExport Data Search Error", e);
        }

        List<ItemDetailLogInfo> currencyLogList = result.getItems();
        progressTracker.updateProgress(taskId, 30, 100, "데이터 파싱 완료...");

        try{
            excelService.generateExcelToResponse(
                    response,
                    currencyLogList,
                    "게임 아이템 로그 데이터",
                    "sheet1",
                    taskId
            );

        }catch (Exception e){
            log.error("itemDetailExcelExport Excel Export Create Error", e);
            throw new RestApiException(CommonCode.ERROR.getHttpStatus(), ErrorCode.ERROR_EXCEL_DOWN.toString());
        }

    }

    @RequestLog
    public LogResponse getCurrencyItemLogList(Map<String, String> requestParams){
        String searchType = requestParams.get("search_type");
        String searchData = requestParams.get("search_data");
        String tranId = requestParams.get("tran_id");
        String logAction = requestParams.get("log_action");
        String currencyType = requestParams.get("currency_type");
        String amountDeltaType = requestParams.get("amount_delta_type");
        LocalDateTime startDt = DateUtils.stringISOToLocalDateTime(requestParams.get("start_dt"));
        LocalDateTime endDt = DateUtils.stringISOToLocalDateTime(requestParams.get("end_dt"));
        String orderBy = requestParams.get("orderby");
        int pageNo = Integer.parseInt(requestParams.get("page_no"));
        int pageSize = Integer.parseInt(requestParams.get("page_size"));
        MongoPageResult<CurrencyItemLogInfo> result = indicatorsCurrencyService.getCurrencyItemLogData(
                searchType,
                searchData,
                tranId,
                logAction,
                currencyType,
                amountDeltaType,
                startDt.toString().substring(0, 10),
                endDt.toString().substring(0, 10),
                orderBy,
                pageNo,
                pageSize,
                CurrencyItemLogInfo.class
        );

        List<CurrencyItemLogInfo> currencyItemLogList = result.getItems();
        int totalCount = result.getTotalCount();

        return LogResponse.builder()
                .resultData(LogResponse.ResultData.builder()
                        .currencyItemList(currencyItemLogList)
                        .total(currencyItemLogList.size())
                        .totalAll(totalCount)
                        .pageNo(pageNo)
                        .build())
                .status(CommonCode.SUCCESS.getHttpStatus())
                .result(CommonCode.SUCCESS.getResult())
                .build();
    }

    public void currencyItemExcelExport(HttpServletResponse response, LogGameRequest logGameRequest){
        String taskId = logGameRequest.getTaskId();
        LocalDateTime startDt = logGameRequest.getStartDt().plusHours(9);
        LocalDateTime endDt = logGameRequest.getEndDt().plusHours(9).plusDays(1);
        logGameRequest.setStartDt(startDt);
        logGameRequest.setEndDt(endDt);
        logGameRequest.setPageNo(null);
        logGameRequest.setPageSize(null);
        progressTracker.updateProgress(taskId, 5, 100, "엑셀 생성 준비 중...");

        MongoPageResult<CurrencyItemLogInfo> result = null;
        try{
            result = indicatorsCurrencyService.getCurrencyItemLogData(
                    logGameRequest.getSearchType().toString(),
                    logGameRequest.getSearchData(),
                    logGameRequest.getTranId(),
                    logGameRequest.getLogAction().name(),
                    logGameRequest.getCurrencyType().name(),
                    logGameRequest.getAmountDeltaType().name(),
                    startDt.toString().substring(0, 10),
                    endDt.toString().substring(0, 10),
                    logGameRequest.getOrderBy(),
                    logGameRequest.getPageNo(),
                    logGameRequest.getPageSize(),
                    CurrencyItemLogInfo.class
            );
            progressTracker.updateProgress(taskId, 20, 100, "데이터 생성완료");
        }catch(UncategorizedMongoDbException e){
            if (e.getMessage().contains("Sort exceeded memory limit")) {
                log.error("MongoDB Query memory limit error: {}", e.getMessage());
                throw new RestApiException(CommonCode.ERROR.getHttpStatus(), ErrorCode.ERROR_LOG_MEMORY_LIMIT.toString());
            } else if (e.getMessage().contains("time limit")) {
                log.error("MongoDB Query operation exceeded time limit: {}", e.getMessage());
                throw new RestApiException(CommonCode.ERROR.getHttpStatus(), ErrorCode.ERROR_LOG_MEMORY_LIMIT.toString());
            }else {
                log.error("MongoDB Query error", e);
                throw new RestApiException(CommonCode.ERROR.getHttpStatus(), ErrorCode.ERROR_MONGODB_QUERY.toString());
            }
        }catch (Exception e){
            log.error("currencyItemExcelExport ExcelExport Data Search Error", e);
        }

        List<CurrencyItemLogInfo> currencyLogList = result.getItems();
        progressTracker.updateProgress(taskId, 30, 100, "데이터 파싱 완료...");

        try{
            excelService.generateExcelToResponse(
                    response,
                    currencyLogList,
                    "게임 재화(아이템) 로그 데이터",
                    "sheet1",
                    taskId
            );

        }catch (Exception e){
            log.error("currencyItemExcelExport Excel Export Create Error", e);
            throw new RestApiException(CommonCode.ERROR.getHttpStatus(), ErrorCode.ERROR_EXCEL_DOWN.toString());
        }

    }

    @RequestLog
    public LogResponse getUserCreateLogList(Map<String, String> requestParams){
        String searchType = requestParams.get("search_type");
        String searchData = requestParams.get("search_data");
        LocalDateTime startDt = DateUtils.stringISOToLocalDateTime(requestParams.get("start_dt"));
        LocalDateTime endDt = DateUtils.stringISOToLocalDateTime(requestParams.get("end_dt"));
        String orderBy = requestParams.get("orderby");
        int pageNo = Integer.parseInt(requestParams.get("page_no"));
        int pageSize = Integer.parseInt(requestParams.get("page_size"));
        MongoPageResult<UserCreateLogInfo> result = indicatorsUserCreateService.getUserCreateLogData(
                searchType,
                searchData,
                startDt.toString().substring(0, 10),
                endDt.toString().substring(0, 10),
                orderBy,
                pageNo,
                pageSize,
                UserCreateLogInfo.class
        );

        List<UserCreateLogInfo> userCreateLogList = result.getItems();
        int totalCount = result.getTotalCount();

        return LogResponse.builder()
                .resultData(LogResponse.ResultData.builder()
                        .userCreateList(userCreateLogList)
                        .total(userCreateLogList.size())
                        .totalAll(totalCount)
                        .pageNo(pageNo)
                        .build())
                .status(CommonCode.SUCCESS.getHttpStatus())
                .result(CommonCode.SUCCESS.getResult())
                .build();
    }

    public void userCreateExcelExport(HttpServletResponse response, LogGameRequest logGameRequest){
        String taskId = logGameRequest.getTaskId();
        LocalDateTime startDt = logGameRequest.getStartDt().plusHours(9);
        LocalDateTime endDt = logGameRequest.getEndDt().plusHours(9).plusDays(1);
        logGameRequest.setStartDt(startDt);
        logGameRequest.setEndDt(endDt);
        logGameRequest.setPageNo(null);
        logGameRequest.setPageSize(null);
        progressTracker.updateProgress(taskId, 5, 100, "엑셀 생성 준비 중...");

        MongoPageResult<UserCreateLogInfo> result = null;
        try{
            result = indicatorsUserCreateService.getUserCreateLogData(
                    logGameRequest.getSearchType().toString(),
                    logGameRequest.getSearchData(),
                    startDt.toString().substring(0, 10),
                    endDt.toString().substring(0, 10),
                    logGameRequest.getOrderBy(),
                    logGameRequest.getPageNo(),
                    logGameRequest.getPageSize(),
                    UserCreateLogInfo.class
            );
            progressTracker.updateProgress(taskId, 20, 100, "데이터 생성완료");
        }catch(UncategorizedMongoDbException e){
            if (e.getMessage().contains("Sort exceeded memory limit")) {
                log.error("MongoDB Query memory limit error: {}", e.getMessage());
                throw new RestApiException(CommonCode.ERROR.getHttpStatus(), ErrorCode.ERROR_LOG_MEMORY_LIMIT.toString());
            } else if (e.getMessage().contains("time limit")) {
                log.error("MongoDB Query operation exceeded time limit: {}", e.getMessage());
                throw new RestApiException(CommonCode.ERROR.getHttpStatus(), ErrorCode.ERROR_LOG_MEMORY_LIMIT.toString());
            }else {
                log.error("MongoDB Query error", e);
                throw new RestApiException(CommonCode.ERROR.getHttpStatus(), ErrorCode.ERROR_MONGODB_QUERY.toString());
            }
        }catch (Exception e){
            log.error("userCreateExcelExport ExcelExport Data Search Error", e);
        }

        List<UserCreateLogInfo> logList = result.getItems();
        progressTracker.updateProgress(taskId, 30, 100, "데이터 파싱 완료...");

        try{
            excelService.generateExcelToResponse(
                    response,
                    logList,
                    "유저 생성 로그 데이터",
                    "sheet1",
                    taskId
            );

        }catch (Exception e){
            log.error("userCreateExcelExport Excel Export Create Error", e);
            throw new RestApiException(CommonCode.ERROR.getHttpStatus(), ErrorCode.ERROR_EXCEL_DOWN.toString());
        }

    }

    @RequestLog
    public LogResponse getUserLoginDetailLogList(Map<String, String> requestParams){
        String searchType = requestParams.get("search_type");
        String searchData = requestParams.get("search_data");
        String tranId = requestParams.get("tran_id");
        LocalDateTime startDt = DateUtils.stringISOToLocalDateTime(requestParams.get("start_dt"));
        LocalDateTime endDt = DateUtils.stringISOToLocalDateTime(requestParams.get("end_dt"));
        String orderBy = requestParams.get("orderby");
        int pageNo = Integer.parseInt(requestParams.get("page_no"));
        int pageSize = Integer.parseInt(requestParams.get("page_size"));
        MongoPageResult<UserLoginDetailLogInfo> result = indicatorsUserLoginService.getLoginDetailLogData(
                searchType,
                searchData,
                tranId,
                startDt.toString().substring(0, 10),
                endDt.toString().substring(0, 10),
                orderBy,
                pageNo,
                pageSize,
                UserLoginDetailLogInfo.class
        );

        List<UserLoginDetailLogInfo> userLoginLogList = result.getItems();
        int totalCount = result.getTotalCount();

        return LogResponse.builder()
                .resultData(LogResponse.ResultData.builder()
                        .userLoginList(userLoginLogList)
                        .total(userLoginLogList.size())
                        .totalAll(totalCount)
                        .pageNo(pageNo)
                        .build())
                .status(CommonCode.SUCCESS.getHttpStatus())
                .result(CommonCode.SUCCESS.getResult())
                .build();
    }

    public void userLoginExcelExport(HttpServletResponse response, LogGameRequest logGameRequest){
        String taskId = logGameRequest.getTaskId();
        LocalDateTime startDt = logGameRequest.getStartDt().plusHours(9);
        LocalDateTime endDt = logGameRequest.getEndDt().plusHours(9).plusDays(1);
        logGameRequest.setStartDt(startDt);
        logGameRequest.setEndDt(endDt);
        logGameRequest.setPageNo(null);
        logGameRequest.setPageSize(null);
        progressTracker.updateProgress(taskId, 5, 100, "엑셀 생성 준비 중...");

        MongoPageResult<UserLoginDetailLogInfo> result = null;
        try{
            result = indicatorsUserLoginService.getLoginDetailLogData(
                    logGameRequest.getSearchType().toString(),
                    logGameRequest.getSearchData(),
                    logGameRequest.getTranId(),
                    startDt.toString().substring(0, 10),
                    endDt.toString().substring(0, 10),
                    logGameRequest.getOrderBy(),
                    logGameRequest.getPageNo(),
                    logGameRequest.getPageSize(),
                    UserLoginDetailLogInfo.class
            );
            progressTracker.updateProgress(taskId, 20, 100, "데이터 생성완료");
        }catch(UncategorizedMongoDbException e){
            if (e.getMessage().contains("Sort exceeded memory limit")) {
                log.error("MongoDB Query memory limit error: {}", e.getMessage());
                throw new RestApiException(CommonCode.ERROR.getHttpStatus(), ErrorCode.ERROR_LOG_MEMORY_LIMIT.toString());
            } else if (e.getMessage().contains("time limit")) {
                log.error("MongoDB Query operation exceeded time limit: {}", e.getMessage());
                throw new RestApiException(CommonCode.ERROR.getHttpStatus(), ErrorCode.ERROR_LOG_MEMORY_LIMIT.toString());
            }else {
                log.error("MongoDB Query error", e);
                throw new RestApiException(CommonCode.ERROR.getHttpStatus(), ErrorCode.ERROR_MONGODB_QUERY.toString());
            }
        }catch (Exception e){
            log.error("userLoginExcelExport ExcelExport Data Search Error", e);
        }

        List<UserLoginDetailLogInfo> logList = result.getItems();
        progressTracker.updateProgress(taskId, 30, 100, "데이터 파싱 완료...");

        try{
            excelService.generateExcelToResponse(
                    response,
                    logList,
                    "유저 로그인 로그 데이터",
                    "sheet1",
                    taskId
            );

        }catch (Exception e){
            log.error("userLoginExcelExport Excel Export Create Error", e);
            throw new RestApiException(CommonCode.ERROR.getHttpStatus(), ErrorCode.ERROR_EXCEL_DOWN.toString());
        }

    }

    @RequestLog
    public LogResponse getSnapshotLogList(Map<String, String> requestParams){
        String searchType = requestParams.get("search_type");
        String searchData = requestParams.get("search_data");
        LocalDateTime startDt = DateUtils.stringISOToLocalDateTime(requestParams.get("start_dt"));
        LocalDateTime endDt = DateUtils.stringISOToLocalDateTime(requestParams.get("end_dt"));
        String orderBy = requestParams.get("orderby");
        int pageNo = Integer.parseInt(requestParams.get("page_no"));
        int pageSize = Integer.parseInt(requestParams.get("page_size"));
        MongoPageResult<SnapshotLogInfo> result = indicatorsSnapshotService.getSnapshotLogData(
                searchType,
                searchData,
                startDt.toString().substring(0, 10),
                endDt.toString().substring(0, 10),
                orderBy,
                pageNo,
                pageSize,
                SnapshotLogInfo.class
        );

        int totalCount = result.getTotalCount();

        return LogResponse.builder()
                .resultData(LogResponse.ResultData.builder()
                        .snapshotList(result.getItems())
                        .total(result.getItems().size())
                        .totalAll(totalCount)
                        .pageNo(pageNo)
                        .build())
                .status(CommonCode.SUCCESS.getHttpStatus())
                .result(CommonCode.SUCCESS.getResult())
                .build();
    }

    public void SnapshotExcelExport(HttpServletResponse response, LogGameRequest logGameRequest){
        String taskId = logGameRequest.getTaskId();
        LocalDateTime startDt = logGameRequest.getStartDt().plusHours(9);
        LocalDateTime endDt = logGameRequest.getEndDt().plusHours(9).plusDays(1);
        logGameRequest.setStartDt(startDt);
        logGameRequest.setEndDt(endDt);
        logGameRequest.setPageNo(null);
        logGameRequest.setPageSize(null);
        progressTracker.updateProgress(taskId, 5, 100, "엑셀 생성 준비 중...");

        MongoPageResult<SnapshotLogInfo> result = null;
        try{
            result = indicatorsSnapshotService.getSnapshotLogData(
                    logGameRequest.getSearchType().toString(),
                    logGameRequest.getSearchData(),
                    startDt.toString().substring(0, 10),
                    endDt.toString().substring(0, 10),
                    logGameRequest.getOrderBy(),
                    logGameRequest.getPageNo(),
                    logGameRequest.getPageSize(),
                    SnapshotLogInfo.class
            );
            progressTracker.updateProgress(taskId, 20, 100, "데이터 생성완료");
        }catch(UncategorizedMongoDbException e){
            if (e.getMessage().contains("Sort exceeded memory limit")) {
                log.error("MongoDB Query memory limit error: {}", e.getMessage());
                throw new RestApiException(CommonCode.ERROR.getHttpStatus(), ErrorCode.ERROR_LOG_MEMORY_LIMIT.toString());
            } else if (e.getMessage().contains("time limit")) {
                log.error("MongoDB Query operation exceeded time limit: {}", e.getMessage());
                throw new RestApiException(CommonCode.ERROR.getHttpStatus(), ErrorCode.ERROR_LOG_MEMORY_LIMIT.toString());
            }else {
                log.error("MongoDB Query error", e);
                throw new RestApiException(CommonCode.ERROR.getHttpStatus(), ErrorCode.ERROR_MONGODB_QUERY.toString());
            }
        }catch (Exception e){
            log.error("SnapshotExcelExport ExcelExport Data Search Error", e);
        }

        List<SnapshotLogInfo> logList = result.getItems();
        progressTracker.updateProgress(taskId, 30, 100, "데이터 파싱 완료...");

        try{
            excelService.generateExcelToResponse(
                    response,
                    logList,
                    "유저 스냅샷 로그 데이터",
                    "sheet1",
                    taskId
            );

        }catch (Exception e){
            log.error("SnapshotExcelExport Excel Export Create Error", e);
            throw new RestApiException(CommonCode.ERROR.getHttpStatus(), ErrorCode.ERROR_EXCEL_DOWN.toString());
        }

    }
}
