package com.caliverse.admin.domain.service;

import com.caliverse.admin.domain.datacomponent.MetaDataHandler;
import com.caliverse.admin.domain.entity.*;
import com.caliverse.admin.domain.entity.excel.ExcelBusinessLog;
import com.caliverse.admin.domain.entity.log.GenericLog;
import com.caliverse.admin.domain.entity.metadata.MetaBattleConfigData;
import com.caliverse.admin.domain.entity.metadata.MetaBrandData;
import com.caliverse.admin.domain.entity.metadata.MetaItemData;
import com.caliverse.admin.domain.request.LogGenericRequest;
import com.caliverse.admin.domain.response.BattleEventResponse;
import com.caliverse.admin.domain.response.DictionaryResponse;
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.component.tracker.ExcelProgressTracker;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.mongodb.UncategorizedMongoDbException;
import org.springframework.stereotype.Service;
import org.springframework.web.bind.annotation.RequestParam;

import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

@Service
@RequiredArgsConstructor
@Slf4j
public class MetaDataService {

    @Autowired
    private MetaDataHandler metaDataHandler;
    private final ExcelService excelService;
    private final ExcelProgressTracker progressTracker;

    public DictionaryResponse getBrandList(){

        List<MetaBrandData> list = metaDataHandler.getMetaBrandListData();

        List<MetaBrandData> items = list.stream()
                .peek(data -> {
                    String name = metaDataHandler.getTextStringData(data.getBrandName());
                    data.setBrandDesc(name);
                }).toList();

        return DictionaryResponse.builder()
                .status(CommonCode.SUCCESS.getHttpStatus())
                .result(CommonCode.SUCCESS.getResult())
                .resultData(DictionaryResponse.ResultData.builder()
                        .brandList(items)
                        .build()
                )
                .build();
    }

    //아이템 백과사전
    @RequestLog
    public DictionaryResponse getItemDictList(@RequestParam Map<String, String> requestParam){
        String searchType = requestParam.get("search_type");
        String searchData = requestParam.get("search_data").trim();
        String largeType = requestParam.get("large_type");
        String smallType = requestParam.get("small_type");
        String brand = requestParam.get("brand");
        String gender = requestParam.get("gender");
        String orderBy = requestParam.get("orderby");
        String pageNo = requestParam.get("page_no");
        String pageSize = requestParam.get("page_size");

        List<MetaItemData> items = metaDataHandler.getMetaItemListData();

        List<ItemDict> itemDictListKo = createItemDictList(items, LANGUAGETYPE.KO, searchType, searchData, largeType, smallType, brand, gender);
        List<ItemDict> itemDictListEn = createItemDictList(items, LANGUAGETYPE.EN, searchType, searchData, largeType, smallType, brand, gender);
        List<ItemDict> itemDictListJa = createItemDictList(items, LANGUAGETYPE.JA, searchType, searchData, largeType, smallType, brand, gender);

        int totalAll = itemDictListKo.size();

        if(orderBy != null && !orderBy.isEmpty()) {
            Comparator<ItemDict> comparator = null;

            if(orderBy.equalsIgnoreCase("ASC")) {
                comparator = Comparator.comparing(ItemDict::getItemId);
            } else if(orderBy.equalsIgnoreCase("DESC")) {
                comparator = Comparator.comparing(ItemDict::getItemId).reversed();
            }

            if(comparator != null) {
                itemDictListKo = itemDictListKo.stream().sorted(comparator).toList();
                itemDictListEn = itemDictListEn.stream().sorted(comparator).toList();
                itemDictListJa = itemDictListJa.stream().sorted(comparator).toList();
            }
        }

        // 페이징 처리
        int currentPageNo = 1;
        int currentPageSize = 10; // 기본값

        if(pageNo != null && !pageNo.isEmpty()) {
            try {
                currentPageNo = Integer.parseInt(pageNo);
            } catch(NumberFormatException e) {
                currentPageNo = 1;
            }
        }

        if(pageSize != null && !pageSize.isEmpty()) {
            try {
                currentPageSize = Integer.parseInt(pageSize);
            } catch(NumberFormatException e) {
                currentPageSize = 10;
            }
        }

        // offset 계산
        int offset = (currentPageNo - 1) * currentPageSize;

        // 페이징 적용
        List<ItemDict> pagedItemDictListKo = itemDictListKo.stream()
                .skip(offset)
                .limit(currentPageSize)
                .toList();

        List<ItemDict> pagedItemDictListEn = itemDictListEn.stream()
                .skip(offset)
                .limit(currentPageSize)
                .toList();

        List<ItemDict> pagedItemDictListJa = itemDictListJa.stream()
                .skip(offset)
                .limit(currentPageSize)
                .toList();

        DictionaryResponse.ItemList itemTotalList = DictionaryResponse.ItemList.builder()
                .ko(pagedItemDictListKo)
                .en(pagedItemDictListEn)
                .ja(pagedItemDictListJa)
                .build();


        return DictionaryResponse.builder()
                .status(CommonCode.SUCCESS.getHttpStatus())
                .result(CommonCode.SUCCESS.getResult())
                .resultData(DictionaryResponse.ResultData.builder()
                        .itemList(itemTotalList)
                        .totalAll(totalAll)
                        .total(pagedItemDictListKo.size())
                        .pageNo(currentPageNo)
                        .build()
                )
                .build();
    }

    public void itemExcelExport(HttpServletResponse response, @RequestParam Map<String, String> requestParam){
        String searchType = requestParam.get("search_type");
        String searchData = requestParam.get("search_data").trim();
        String largeType = requestParam.get("large_type");
        String smallType = requestParam.get("small_type");
        String brand = requestParam.get("brand");
        String gender = requestParam.get("gender");
        String taskId = requestParam.get("task_id");
        String lang = requestParam.get("lang");

        if(taskId == null || taskId.isEmpty() || taskId.equals("undefined")){
            log.error("itemExcelExport Excel Export taskId is null or empty");
            throw new RestApiException(CommonCode.ERROR.getHttpStatus(), ErrorCode.ERROR_EXCEL_DOWN.toString());
        }

        LANGUAGETYPE languageType = LANGUAGETYPE.valueOf(lang.toUpperCase());

        progressTracker.updateProgress(taskId, 5, 100, "엑셀 생성 준비 중...");

        List<MetaItemData> items = metaDataHandler.getMetaItemListData();

        List<ItemDict> itemDictList = createItemDictList(items, languageType, searchType, searchData, largeType, smallType, brand, gender);
        progressTracker.updateProgress(taskId, 30, 100, "데이터 생성완료");

        try{
            excelService.generateExcelToResponse(
                    response,
                    itemDictList,
                    "Item Dictionary Data",
                    "sheet1",
                    taskId
            );

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

    }

    private List<ItemDict> createItemDictList(List<MetaItemData> items, LANGUAGETYPE languageType,
                                              String searchType, String searchData, String largeType,
                                              String smallType, String brand, String gender) {
        return items.stream()
                .filter(data -> {
                    boolean result = true;

                    if(!largeType.equals("ALL")){
                        result = data.getLargeType().equals(largeType);
                    }

                    if(!smallType.equals("ALL")){
                        result = result && data.getSmallType().equals(smallType);
                    }

                    if(!brand.equals("ALL")){
                        result = result && data.getBrand().equals(Integer.valueOf(brand));
                    }

                    if(!gender.equals("ALL")){
                        result = result && data.getGender().equals(gender);
                    }

                    return result;
                })
                .map(item -> {
                    String buffName = metaDataHandler.getMetaBuffName(item.getBuffId());
                    String brandName = metaDataHandler.getMetaBrandName(item.getBrand());
                    String randomGroupAttribName = metaDataHandler.getMetaAttribData(item.getAttributeRandomGroupId());
                    String itemSetName = metaDataHandler.getMetaItemSetName(item.getItemSetId());
                    Integer gachaGroupId = metaDataHandler.getMetaGachaGroupId(item.getGachaGroupId());
                    String webLink = metaDataHandler.getMetaWebLinkData(item.getProductLink(), languageType);
                    String currencySellName = metaDataHandler.getMetaCurrencyName(item.getSellId());
                    String currencyBuyName = metaDataHandler.getMetaCurrencyName(item.getBuyId());

                    ItemDict.Country country = ItemDict.Country.builder()
                            .maxCount(item.getMaxCount())
                            .stackMaxCount(item.getStackMaxCount())
                            .build();

                    ItemDict.Attrib attrib = ItemDict.Attrib.builder()
                            .rarity(item.getRarity())
                            .defaultAttrib(item.getDefaultAttribute())
                            .attribRandomGroup(randomGroupAttribName)
                            .itemSet(metaDataHandler.getTextStringData(itemSetName, languageType))
                            .buff(metaDataHandler.getTextStringData(buffName, languageType))
                            .build();

                    ItemDict.Expire expire = ItemDict.Expire.builder()
                            .expireType(item.getExpireType())
                            .expireStartDt(item.getExpireFixedTermStart())
                            .expireEndDt(item.getExpireFixedTermEnd())
                            .expireTimeSec(item.getExpireTimeSec())
                            .build();

                    ItemDict.Trade trade = ItemDict.Trade.builder()
                            .userTradable(item.getIsUserTradable())
                            .cartBuy(item.getIsCartNBuy())
                            .throwable(item.getIsThrowable())
                            .systemTradable(item.getIsSystemTradable())
                            .build();

                    ItemDict.Etc etc = ItemDict.Etc.builder()
                            .productLink(webLink)
                            .propSmallType(item.getPropSmallType())
                            .gachaGroupId(gachaGroupId)
                            .ugqAction(item.getUgqAction())
                            .linkedLand(item.getLinkedLand())
                            .build();

                    return ItemDict.builder()
                            .itemId(item.getItemId())
                            .itemName(metaDataHandler.getTextStringData(item.getName(), languageType))
                            .gender(item.getGender())
                            .typeLarge(item.getLargeType())
                            .typeSmall(item.getSmallType())
                            .brand(metaDataHandler.getTextStringData(brandName, languageType))
                            .sellType(metaDataHandler.getTextStringData(currencySellName, LANGUAGETYPE.KO))
                            .sellPrice(item.getSellPrice())
                            .buyType(metaDataHandler.getTextStringData(currencyBuyName, LANGUAGETYPE.KO))
                            .buyPrice(item.getBuyPrice())
                            .buyDiscountRate(item.getBuyDiscountRate())
                            .country(country)
                            .attrib(attrib)
                            .expire(expire)
                            .trade(trade)
                            .etc(etc)
                            .build();
                }).filter(data -> {
                    boolean result = true;

                    if(!searchData.isEmpty()){
                        if(searchType.equals("NAME")){
                            result = data.getItemName().contains(searchData);
                        }

                        if(searchType.equals("ID")){
                            result = data.getItemId().toString().equals(searchData);
                        }
                    }

                    return result;
                })
                .collect(Collectors.toList());
    }


}
