package com.caliverse.admin.domain.datacomponent;


import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;

import com.caliverse.admin.domain.entity.metadata.*;
import com.caliverse.admin.global.common.constants.MetadataConstants;
import com.caliverse.admin.global.common.exception.MetaDataException;
import jakarta.annotation.PostConstruct;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import com.caliverse.admin.domain.entity.EMetaData;

@Component
@Slf4j
public class MetaDataFileLoader {
    private final JsonFileReader jsonFileReader;
    private final Map<Integer, MetaItemData> items;
    private final Map<String, MetaTextStringData> textStrings;
    private final Map<Integer, MetaClothTypeData> clothTypes;
    private final Map<Integer, MetaToolData> toolItems;
    private final Map<Integer, String> banWords;
    private final Map<MetaQuestKey, MetaQuestData> quests;
    private final Map<Integer, MetaBuildingData> buildings;
    private final Map<Integer, MetaLandData> lands;
    private final Map<Integer, MetaBattleConfigData> battleConfigs;
    private final Map<Integer, MetaBattleRewardData> battleRewards;
    private final Map<String, MetaSystemMailData> systemMails;

    public MetaDataFileLoader(JsonFileReader jsonFileReader) {
        this.jsonFileReader = jsonFileReader;
        this.items = new ConcurrentHashMap<>();
        this.textStrings = new ConcurrentHashMap<>();
        this.clothTypes = new ConcurrentHashMap<>();
        this.toolItems = new ConcurrentHashMap<>();
        this.banWords = new ConcurrentHashMap<>();
        this.quests = new ConcurrentHashMap<>();
        this.buildings = new ConcurrentHashMap<>();
        this.lands = new ConcurrentHashMap<>();
        this.battleConfigs = new ConcurrentHashMap<>();
        this.battleRewards = new ConcurrentHashMap<>();
        this.systemMails = new ConcurrentHashMap<>();
    }

    @PostConstruct
    public void initialize(){
        loadMetaData();
    }

    @Scheduled(fixedDelayString = "${caliverse.metadata.reload.interval}")
    public void reloadMetaData() {
        try {
            log.info("Starting metadata reload");
            loadMetaData();
            log.info("Metadata reload completed");
        } catch (Exception e) {
            log.error("Failed to reload metadata", e);
        }
    }

    private void loadMetaData(){
        try{
            loadTextStrings();
            loadQuests();
            loadLand();
            loadBanWord();
            loadBuilding();
            loadItems();
            loadToolItems();
            loadClothType();
            loadBattleConfig();
            loadBattleReward();
            loadSystemMail();
        }catch(MetaDataException e){
            log.error("Failed to initialize metadata", e);
            throw e;
        }
    }

    public Optional<MetaTextStringData> getName(String text){
        if(text == null) return Optional.empty();

        return Optional.ofNullable(textStrings.get(text));
    }

    //아이템 가져오기
    public Optional<MetaItemData> getMetaItem(int itemId) {
        if(itemId == 0) return Optional.empty();

        return Optional.ofNullable(items.get(itemId));
    }

    //의상 타입 가져오기
    public Optional<MetaClothTypeData> getMetaClothType(int id) {
        if(id == 0) return Optional.empty();

        return Optional.ofNullable(clothTypes.get(id));
    }

    //도구 정보 가져오기
    public Optional<MetaToolData> getMetaToolItem(int id) {
        if(id == 0) return Optional.empty();

        return Optional.ofNullable(toolItems.get(id));
    }

    //퀘스트 정보 가져오기
    public List<MetaQuestData> getMetaQuests(int id) {
        if(id == 0) return Collections.emptyList();

        return quests.entrySet().stream()
                .filter(entry -> entry.getKey().getQeustId().equals(id))
                .map(Map.Entry::getValue)
                .collect(Collectors.toList());
    }

    //빌딩 정보 가져오기
    public Optional<MetaBuildingData> getMetaBuildingItem(int id) {
        if(id == 0){
            return Optional.empty();
        }

        return Optional.ofNullable(buildings.get(id));
    }

    public List<MetaBuildingData> getMetaBuildings() {
        return new ArrayList<>(buildings.values());
    }

    //랜드 정보 가져오기
    public Optional<MetaLandData> getMetaLandItem(int id) {
        if(id == 0){
            return Optional.empty();
        }

        return Optional.ofNullable(lands.get(id));
    }

    public List<MetaLandData> getMetaLands() {
        return new ArrayList<>(lands.values());
    }

    public List<MetaBattleConfigData> getMetaBattleConfigs() {
        return new ArrayList<>(battleConfigs.values());
    }
    public List<MetaBattleRewardData> getMetaBattleRewards() {
        return battleRewards.values().stream()
                .collect(Collectors.groupingBy(MetaBattleRewardData::getGroupID))  // groupId로 그룹화
                .values().stream()                                                 // 그룹화된 리스트들의 스트림
                .map(group -> group.get(0))                                       // 각 그룹의 첫 번째 항목만 선택
                .sorted(Comparator.comparing(MetaBattleRewardData::getGroupID))   // groupId 기준으로 정렬
                .collect(Collectors.toList());
    }
    public List<MetaSystemMailData> getMetaSystemMail() {
        return new ArrayList<>(systemMails.values());
    }









    // 문자 데이터 로드
    private void loadTextStrings() {
        List<Map<String, Object>> metaList = jsonFileReader.readJsonFile(
                EMetaData.TEXT_STRING_DATA.getFileName(),
                MetadataConstants.JSON_LIST_TEXT_STRING
        );
        if(metaList == null || metaList.isEmpty()) {
            log.warn("textStrings data is empty or file not found: {}", EMetaData.TOOL_DATA.getFileName());
            return;
        }

        metaList.forEach(meta -> {
            MetaTextStringData textString = new MetaTextStringData();
            textString.setKey((String) meta.get("Key"));
            textString.setKor((String) meta.get("SourceString"));
            textString.setEn((String) meta.get("en"));
            textString.setJa((String) meta.get("ja"));
            textStrings.put(textString.getKey(), textString);
        });

        log.info("loadTextStrings {} Load Complete",EMetaData.TEXT_STRING_DATA.getFileName());
    }

    // 아이템 정보 데이터 로드
    public void loadItems(){
        List<Map<String, Object>> metaList = jsonFileReader.readJsonFile(EMetaData.ITEM_DATA.getFileName(), MetadataConstants.JSON_LIST_ITEM);
        if(metaList == null || metaList.isEmpty()) {
            log.warn("item data is empty or file not found: {}", EMetaData.TOOL_DATA.getFileName());
            return;
        }

        metaList.forEach(meta -> {
            MetaItemData item = new MetaItemData();
            item.setItemId((Integer)meta.get("item_id"));
            item.setName((String)meta.get("name"));
            item.setLargeType((String)meta.get("type_large"));
            item.setGender((String)meta.get("gender"));
            items.put(item.getItemId(), item);
        });

        log.info("loadItems {} Load Complete", EMetaData.ITEM_DATA.getFileName());

    }

    // 의상 타입 데이터 로드
    public void loadClothType(){
        List<Map<String, Object>> metaList = jsonFileReader.readJsonFile(EMetaData.CLOTH_TYPE_DATA.getFileName(), MetadataConstants.JSON_LIST_CLOTH_TYPE);
        if(metaList == null || metaList.isEmpty()) {
            log.warn("clothType data is empty or file not found: {}", EMetaData.TOOL_DATA.getFileName());
            return;
        }

        metaList.forEach(meta -> {
            MetaClothTypeData item = new MetaClothTypeData();
            item.setMetaId((Integer)meta.get("Meta_id"));
            item.setSmallType((String)meta.get("SmallType"));
            item.setEquipSlotType((String)meta.get("EquipSlotType"));
            clothTypes.put(item.getMetaId(), item);
        });

        log.info("loadClothType {} Load Complete", EMetaData.CLOTH_TYPE_DATA.getFileName());
    }

    // 도구 정보 데이터 로드
    public void loadToolItems(){
        List<Map<String, Object>> metaList = jsonFileReader.readJsonFile(EMetaData.TOOL_DATA.getFileName(), MetadataConstants.JSON_LIST_TOOL);
        if(metaList == null || metaList.isEmpty()) {
            log.warn("tool data is empty or file not found: {}", EMetaData.TOOL_DATA.getFileName());
            return;
        }

        metaList.forEach(meta -> {
            MetaToolData item = new MetaToolData();
            item.setToolId((Integer)meta.get("tool_id"));
            item.setToolName((String)meta.get("tool_name"));
            toolItems.put(item.getToolId(), item);
        });

        log.info("loadToolItems {} Load Complete", EMetaData.TOOL_DATA.getFileName());
    }

    // 금지어 데이터 로드
    public void loadBanWord(){
        List<Map<String, Object>> metaList = jsonFileReader.readJsonFile(EMetaData.BAN_WORD_DATA.getFileName(), MetadataConstants.JSON_LIST_BAN_WORD);
        if(metaList == null || metaList.isEmpty()) {
            log.warn("ban data is empty or file not found: {}", EMetaData.BAN_WORD_DATA.getFileName());
            return;
        }

        metaList.forEach(meta -> {
            banWords.put((Integer)meta.get("Id"), (String)meta.get("Ban_Word"));
        });

        log.info("loadBanWord {} Load Complete", EMetaData.BAN_WORD_DATA.getFileName());
    }

    // 퀘스트 데이터 로드
    public void loadQuests(){
        List<Map<String, Object>> metaList = jsonFileReader.readJsonFile(EMetaData.QUEST_DATA.getFileName(), MetadataConstants.JSON_LIST_QUEST);
        if(metaList == null || metaList.isEmpty()) {
            log.warn("quest data is empty or file not found: {}", EMetaData.QUEST_DATA.getFileName());
            return;
        }

        metaList.forEach(meta -> {
            MetaQuestData item = new MetaQuestData();
            Integer questId = (Integer)meta.get("QuestID");
            Integer taskNum = (Integer)meta.get("TaskNum");
            item.setQuestId(questId);
            item.setTaskNum(taskNum);
            item.setTaskName((String)meta.get("TaskName"));
            item.setCounter((Integer) meta.get("SetCounter"));
            quests.put(new MetaQuestKey(questId, taskNum), item);
        });

        log.info("loadQuests {} Load Complete", EMetaData.QUEST_DATA.getFileName());
    }

    // 빌딩 데이터 로드
    public void loadBuilding(){
        List<Map<String, Object>> metaList = jsonFileReader.readJsonFile(EMetaData.BUILDING_DATA.getFileName(), MetadataConstants.JSON_LIST_BUILDING);
        if(metaList == null || metaList.isEmpty()) {
            log.warn("building data is empty or file not found: {}", EMetaData.BUILDING_DATA.getFileName());
            return;
        }

        metaList.forEach(meta -> {
            String building_name = (String)meta.get("BuildingName");
            if(building_name.isEmpty()) return;
            MetaBuildingData item = new MetaBuildingData();
            item.setBuildingId((Integer)meta.get("BuildingId"));
            item.setBuildingOpen((Boolean)meta.get("BuildingOpen"));
            item.setOwner((String)meta.get("Owner"));
            item.setEditor((String)meta.get("Editor"));
            item.setBuildingName(building_name);
            item.setBuildingDesc((String)meta.get("BuildingDesc"));
            item.setBuildingSize((String)meta.get("BuildingSize"));
            item.setInstanceSocket((Integer)meta.get("InstanceSocket"));
            buildings.put((Integer)meta.get("BuildingId"), item);
        });

        log.info("loadBuilding {} Load Complete", EMetaData.BUILDING_DATA.getFileName());
    }

    // 랜드 데이터 로드
    public void loadLand(){
        List<Map<String, Object>> metaList = jsonFileReader.readJsonFile(EMetaData.LAND_DATA.getFileName(), MetadataConstants.JSON_LIST_LAND);
        if(metaList == null || metaList.isEmpty()) {
            log.warn("land data is empty or file not found: {}", EMetaData.LAND_DATA.getFileName());
            return;
        }

        metaList.forEach(meta -> {
            String land_name = (String)meta.get("LandName");
            if(land_name.isEmpty()) return;
            MetaLandData item = new MetaLandData();
            item.setLandId((Integer)meta.get("LandId"));
            item.setOwner((String)meta.get("Owner"));
            item.setEditor((String)meta.get("Editor"));
            Boolean nonAuction = (Boolean)meta.get("NonAuction");
            if(nonAuction != null)
                item.setNonAuction(nonAuction);
            item.setRentalStateSwitch((Boolean)meta.get("RentalStateSwitch"));
            item.setRentalAvailable((Boolean)meta.get("RentalAvailable"));
            item.setLandName(land_name);
            item.setLandDesc((String)meta.get("LandDesc"));
            item.setLandSize((String)meta.get("LandSize"));
            item.setLandType((String)meta.get("LandType"));
            item.setLinkedItem((Integer)meta.get("LinkedItem"));
            item.setCityType((String)meta.get("CityType"));
            item.setBuildingArea((String)meta.get("BuildingArea"));
            item.setBuildingId((Integer)meta.get("BuildingId"));
            item.setBuildingSocket((Integer)meta.get("BuildingSocket"));
            lands.put((Integer)meta.get("LandId"), item);
        });

        log.info("loadLand {} Load Complete", EMetaData.LAND_DATA.getFileName());
    }

    // 전투 설정 데이터 로드
    public void loadBattleConfig(){
        List<Map<String, Object>> metaList = jsonFileReader.readJsonFile(EMetaData.BATTLE_CONFIG_DATA.getFileName(), MetadataConstants.JSON_LIST_BATTLE_CONFIG);
        if(metaList == null || metaList.isEmpty()) {
            log.warn("Battle config data is empty or file not found: {}", EMetaData.BATTLE_CONFIG_DATA.getFileName());
            return;
        }

        metaList.forEach(meta -> {
            MetaBattleConfigData item = new MetaBattleConfigData();
            item.setId((Integer)meta.get("Id"));
            item.setDesc((String)meta.get("Description"));
            item.setPlayerRespawnTime((Integer)meta.get("PlayerRespawnTime"));
            item.setDefaultRoundCount((Integer)meta.get("DefaultRoundCount"));
            item.setRoundTime((Integer)meta.get("RoundTime"));
            item.setNextRoundWaitTime((Integer)meta.get("NextRoundWaitTime"));
            item.setResultUIWaitTime((Integer)meta.get("ResultUIWaitTime"));
            item.setGetRewardTime((Integer)meta.get("GetRewardTime"));
            battleConfigs.put((Integer)meta.get("Id"), item);
        });

        log.info("loadBattleConfig {} Load Complete", EMetaData.BATTLE_CONFIG_DATA.getFileName());
    }

    // 전투 보상 데이터 로드
    public void loadBattleReward(){
        List<Map<String, Object>> metaList = jsonFileReader.readJsonFile(EMetaData.BATTLE_REWARD_DATA.getFileName(), MetadataConstants.JSON_LIST_BATTLE_REWARD);
        if(metaList == null || metaList.isEmpty()) {
            log.warn("Battle reward data is empty or file not found: {}", EMetaData.BATTLE_REWARD_DATA.getFileName());
            return;
        }

        metaList.forEach(meta -> {
            MetaBattleRewardData item = new MetaBattleRewardData();
            item.setId((Integer)meta.get("Id"));
            item.setDesc((String)meta.get("Description"));
            item.setGroupID((Integer)meta.get("GroupID"));
            item.setChargeLevel((Integer)meta.get("ChargeLevel"));
            item.setChargeTime((Integer)meta.get("ChargeTime"));
            item.setRewardItemID((Integer)meta.get("RewardItemID"));
            item.setRewardCount((Integer)meta.get("RewardCount"));
            battleRewards.put((Integer)meta.get("Id"), item);
        });

        log.info("loadBattleReward {} Load Complete", EMetaData.BATTLE_REWARD_DATA.getFileName());
    }

    // 시스템메일 데이터 로드
    public void loadSystemMail(){
        List<Map<String, Object>> metaList = jsonFileReader.readJsonFile(EMetaData.SYSTEM_MAIL_DATA.getFileName(), MetadataConstants.JSON_LIST_SYSTEM_META);
        if(metaList == null || metaList.isEmpty()) {
            log.warn("System Mail data is empty or file not found: {}", EMetaData.SYSTEM_MAIL_DATA.getFileName());
            return;
        }

        metaList.forEach(meta -> {
            MetaSystemMailData item = new MetaSystemMailData();
            item.setKey((String)meta.get("Key"));
            item.setMailTitle((String)meta.get("Mail_Title"));
            item.setMailDesc((String)meta.get("Mail_Desc"));
            item.setSender((String)meta.get("Sender"));
            systemMails.put((String)meta.get("Key"), item);
        });

        log.info("loadSystemMail {} Load Complete", EMetaData.SYSTEM_MAIL_DATA.getFileName());
    }
}
