package com.caliverse.admin.redis.service;


import com.caliverse.admin.domain.entity.FriendRequest;
import com.caliverse.admin.domain.entity.redis.RedisLoginInfo;
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.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

@Slf4j
@Service
public class RedisUserInfoService {

    private final RedisTemplate<String, Object> redisTemplate;

    private final ObjectMapper objectMapper = new ObjectMapper();

    public RedisUserInfoService(RedisTemplate<String, Object> redisTemplate) {
        this.redisTemplate = redisTemplate;
    }

    public RedisLoginInfo getUserLoginSessionInfo(String userGuid) {
        String prefix = "login:";
        String key = prefix + userGuid;

        String infoString =  (String) redisTemplate.opsForValue().get(key);

        if(infoString == null) return null;

        RedisLoginInfo info = null;
        try{
            info = objectMapper.readValue(infoString, RedisLoginInfo.class);
        }
        catch (JsonProcessingException e) {
            log.error(e.getMessage());
            throw new RestApiException(CommonCode.ERROR.getHttpStatus(), ErrorCode.USER_GAME_LOGIN_JSON_MAPPER_PARSE_ERROR.getMessage());
        }
        log.info("getUserLoginSessionInfo userInfo : {}", info);
        return info;
    }

    // 전체 채널,인던 정보
    public List<String> getAllServerList(){
        String worldKey_a = "serverinfo:Keys:ChannelKey:001";
        String worldKey_b = "serverinfo:Keys:ChannelKey:002";
        String worldKey_c = "serverinfo:Keys:ChannelKey:003";
        String indunKey = "serverinfo:Keys:IndunKey";

        List<String> keys_a = getKeys(worldKey_a);
        List<String> keys_b = getKeys(worldKey_b);
        List<String> keys_c = getKeys(worldKey_c);
        List<String> keys_d = getKeys(indunKey);

        List<String> channels_a = getValueList(keys_a);
        List<String> channels_b = getValueList(keys_b);
        List<String> channels_c = getValueList(keys_c);
        List<String> channels_d = getValueList(keys_d);

        List<String> allChannels = new ArrayList<>();
        allChannels.addAll(channels_a);
        allChannels.addAll(channels_b);
        allChannels.addAll(channels_c);
        allChannels.addAll(channels_d);

        log.info("noticeJob getAllServerList serverList : {}", allChannels);

        return allChannels;
    }

    // 첫번째 채널 정보
    public String getFirstChannel(){
        String worldKey_a = "serverinfo:Keys:ChannelKey:001";
        String worldKey_b = "serverinfo:Keys:ChannelKey:002";
        String worldKey_c = "serverinfo:Keys:ChannelKey:003";

        List<String> keys_a = getKeys(worldKey_a);
        List<String> keys_b = getKeys(worldKey_b);
        List<String> keys_c = getKeys(worldKey_c);

        List<String> channels_a = getValueList(keys_a);
        List<String> channels_b = getValueList(keys_b);
        List<String> channels_c = getValueList(keys_c);

        List<String> allChannels = new ArrayList<>();
        allChannels.addAll(channels_a);
        allChannels.addAll(channels_b);
        allChannels.addAll(channels_c);

        String server_name = allChannels.stream().findFirst().get();
        log.info("noticeJob DynamicScheduler.getFirstChannel serverList : {}", allChannels);
        return server_name;
    }

    //친구 요청 정보
    public List<FriendRequest> getFriendRequestInfo(String type, String guid){
        String key = type.equals("receive") ? "receivedfriendrequest:" + guid : "sendedfriendrequest:" + guid;
        Map<Object, Object> entries = redisTemplate.opsForHash().entries(key);
        List<FriendRequest> friendList = entries.values().stream()
                .map(value -> {
                    try {
                        return objectMapper.readValue(value.toString(), FriendRequest.class);
                    } catch (JsonProcessingException e) {
                        throw new RuntimeException("Failed to parse JSON to FriendRequest", e);
                    }
                })
                .collect(Collectors.toList());

        log.info("getFriendRequestInfo type: {}, list: {}", type, friendList);
        return friendList;
    }

    private List<String> getKeys(String worldKey){
        Set<Object> setMember = redisTemplate.opsForSet().members(worldKey);

        if(setMember == null || setMember.isEmpty()) return new ArrayList<>();

        return setMember.stream().map(Object::toString).toList();
    }

    private List<String> getValueList(List<String> keys){
        List<String> namesList = new ArrayList<>();

        for (String key : keys) {
            String infoString = (String) redisTemplate.opsForValue().get(key);

            if (infoString != null) {
                try {
                    Map<String, Object>  map = objectMapper.readValue(infoString, new TypeReference<Map<String, Object>>(){});

                    String name = map.get("Name").toString();

                    if (name != null && !name.isEmpty()) {
                        namesList.add(name);
                    }
                } catch (Exception e) {
                    log.error(e.getMessage());
                }
            }
        }

        return namesList;
    }
}
