package com.caliverse.admin.domain.service;

import com.caliverse.admin.domain.RabbitMq.RabbitMqUtils;
import com.caliverse.admin.domain.RabbitMq.message.AuthAdminLevelType;
import com.caliverse.admin.domain.dao.admin.AdminMapper;
import com.caliverse.admin.domain.datacomponent.MetaDataHandler;
import com.caliverse.admin.domain.entity.metadata.MetaQuestData;
import com.caliverse.admin.domain.entity.*;
import com.caliverse.admin.domain.request.LandRequest;
import com.caliverse.admin.domain.request.UserReportRequest;
import com.caliverse.admin.domain.response.UserReportResponse;
import com.caliverse.admin.domain.response.UsersResponse;
import com.caliverse.admin.dynamodb.service.DynamoDBOperations;
import com.caliverse.admin.dynamodb.domain.atrrib.LandAuctionActivityAttrib;
import com.caliverse.admin.dynamodb.domain.atrrib.LandAuctionHighestBidUserAttrib;
import com.caliverse.admin.dynamodb.domain.atrrib.LandAuctionRegistryAttrib;
import com.caliverse.admin.dynamodb.domain.doc.LandAuctionActivityDoc;
import com.caliverse.admin.dynamodb.domain.doc.LandAuctionHighestBidUserDoc;
import com.caliverse.admin.dynamodb.domain.doc.LandAuctionRegistryDoc;
import com.caliverse.admin.dynamodb.entity.ELandAuctionResult;
import com.caliverse.admin.global.common.annotation.DynamoDBTransaction;
import com.caliverse.admin.global.common.code.CommonCode;
import com.caliverse.admin.global.common.code.ErrorCode;
import com.caliverse.admin.global.common.constants.CommonConstants;
import com.caliverse.admin.global.common.constants.DynamoDBConstants;
import com.caliverse.admin.global.common.exception.RestApiException;
import com.caliverse.admin.global.common.utils.CommonUtils;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import lombok.extern.slf4j.Slf4j;
import org.json.JSONObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import software.amazon.awssdk.enhanced.dynamodb.DynamoDbEnhancedClient;
import software.amazon.awssdk.enhanced.dynamodb.DynamoDbTable;
import software.amazon.awssdk.enhanced.dynamodb.Key;
import software.amazon.awssdk.enhanced.dynamodb.TableSchema;
import software.amazon.awssdk.services.dynamodb.DynamoDbClient;
import software.amazon.awssdk.services.dynamodb.model.*;

import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.BiConsumer;
import java.util.stream.IntStream;
import java.util.stream.Stream;

@Slf4j
@Service
public class DynamoDBService {
    @Value("${amazon.dynamodb.metaTable}")
    private String metaTable;

    private final DynamoDbClient dynamoDbClient;
    private final DynamoDbEnhancedClient enhancedClient;
    private final DynamoDBOperations DynamoDBOperations;

    private final AdminMapper adminMapper;
    private final MetaDataHandler metaDataHandler;
    //private final HistoryService historyService;
    private final ObjectMapper mapper = new ObjectMapper();

    @Autowired
    public DynamoDBService(DynamoDbClient dynamoDbClient,
                           AdminMapper adminMapper,
                           HistoryService historyService,
                           MetaDataHandler metaDataHandler,
                           DynamoDbEnhancedClient enhancedClient,
                           DynamoDBOperations DynamoDBOperations) {
        this.dynamoDbClient = dynamoDbClient;
        this.adminMapper = adminMapper;
        this.metaDataHandler = metaDataHandler;
        this.enhancedClient = enhancedClient;
        this.DynamoDBOperations = DynamoDBOperations;
    }

    // guid check
    public boolean isGuidChecked(String guid) {
        Map<String, AttributeValue> item = getItem("user_base#"+guid,"empty");

        return item.isEmpty();
    }

    // nickname > guid
    public String getNickNameByGuid(String primaryKey) {
        Map<String, Object> resMap = new HashMap<>();
        Map<String, AttributeValue> key = new HashMap<>();
        key.put("PK", AttributeValue.builder().s("user_nickname_registry#global").build());
        key.put("SK", AttributeValue.builder().s(primaryKey).build());
        // GetItem 요청을 만듭니다.
        GetItemRequest getItemRequest = GetItemRequest.builder()
                .tableName(metaTable)
                .key(key)
                .build();

        try {
            // GetItem 요청을 실행하고 응답을 받습니다.
            GetItemResponse response = dynamoDbClient.getItem(getItemRequest);

            // 응답에서 원하는 속성을 가져옵니다.
            AttributeValue attributeValue = response.item().get("UserNicknameRegistryAttrib");

            if (attributeValue != null) {
                String attrJsonString = attributeValue.s();
                // JSON 문자열을 파싱합니다.
                ObjectMapper objectMapper = new ObjectMapper();
                JsonNode attrJson = objectMapper.readTree(attrJsonString);

                // 원하는 필드를 추출합니다.
                return attrJson.get("user_guid").asText();

            }
            return primaryKey;
        } catch (Exception e) {
            log.error("getNickNameByGuid exception: {}", e.getMessage());
            throw new RestApiException(CommonCode.ERROR.getHttpStatus(), ErrorCode.DYNAMODB_CONNECTION_ERROR.getMessage());
        }
    }

    // guid > nickname
    public String getGuidByName(String guid){
        Map<String, AttributeValue> item = getItem("nickname#"+guid,"empty");

        if(item.isEmpty()) return null;

        Map<String, Object> attrMap = CommonUtils.stringByObject(item.get("NicknameAttrib").s());

        return CommonUtils.objectToString(attrMap.get("nickname"));
    }

    // guid > account_id
    public String getGuidByAccountId(String guid){
        Map<String, AttributeValue> item = getItem("user_base#"+guid,"empty");

        if(item.isEmpty()) return null;

        Map<String, Object> attrMap = CommonUtils.stringByObject(item.get("UserBaseAttrib").s());

        return CommonUtils.objectToString(attrMap.get("account_id"));
    }

    //  account_id > guid
    public String getAccountIdByGuid(Long id){
        Map<String, AttributeValue> item = getItem("account_base#"+id,"empty");

        if(item.isEmpty()) return null;

        Map<String, Object> attrMap = CommonUtils.stringByObject(item.get("AccountBaseAttrib").s());

        return CommonUtils.objectToString(attrMap.get("user_guid"));
    }

    //  유저 언어타입
    public String getUserLanguage(String guid){
        String account_id = getGuidByAccountId(guid);
        Map<String, AttributeValue> item = getItem("account_base#" + account_id,"empty");

        if(item.isEmpty()) return null;

        Map<String, Object> attrMap = CommonUtils.stringByObject(item.get("AccountBaseAttrib").s());

        return CommonUtils.objectToString(attrMap.get("language_type"));
    }

    // 유저조회 타입별 분기
    public Map<String,String> findUsersBykey(String searchType, String searchKey){
        Map<String, String> resultMap = new HashMap<>();
        Map<String, AttributeValue> key = new HashMap<>();
        try {
            if(searchType.equals(SEARCHTYPE.NAME.name())){
                return getUsersByName(searchKey.toLowerCase()); //nickname은 무조건 소문자
            }else if(searchType.equals(SEARCHTYPE.GUID.name())){
                return getUsersByGuid(searchKey);
            }else if(searchType.equals(SEARCHTYPE.ACCOUNT.name())){
                return getUsersByAccountId(searchKey);
            }
            //else if(searchType.equals(SEARCHTYPE.TEMP_DATA.name())){
            //    return historyService.insertTempMetaData();
            //}


            return resultMap;
        } catch (Exception e) {
            log.error("findUsersBykey exception: {}", e.getMessage());
            throw new RestApiException(CommonCode.ERROR.getHttpStatus(), ErrorCode.DYNAMODB_CONNECTION_ERROR.getMessage());
        }
    }

    // 유저조회 닉네임
    // return guid, 닉네임
    public Map<String, String> getUsersByName(String searchKey){
        Map<String,String> resultMap = null;

        QueryRequest queryRequest = QueryRequest.builder()
                .tableName(metaTable)
                .keyConditionExpression("PK = :pkValue AND SK = :skValue") // 파티션 키와 조건식 설정
//                .expressionAttributeValues(Map.of(":pkValue", AttributeValue.builder().s("nickname#"+searchKey).build()
//                        ,":skValue", AttributeValue.builder().s("nickname#").build()))
                .expressionAttributeValues(Map.of(":pkValue", AttributeValue.builder().s("user_nickname_registry#global").build()
                        ,":skValue", AttributeValue.builder().s(searchKey).build()))
                .build();

        try{
            // 쿼리 실행
            QueryResponse response = dynamoDbClient.query(queryRequest);

            // 응답에서 원하는 속성을 가져옵니다.
            for (Map<String, AttributeValue> item : response.items()) {
//                AttributeValue attrValue = item.get("Attr");
                AttributeValue attrValue = item.get("UserNicknameRegistryAttrib");
                if (attrValue != null) {
                    resultMap = new HashMap<>();
                    // "Attr" 속성의 값을 읽어옵니다.
                    String attrJson = attrValue.s();

                    // JSON 문자열을 파싱하여 Map 또는 다른 객체로 변환합니다.
                    ObjectMapper objectMapper = new ObjectMapper();
                    Map<String, Object> attrMap = objectMapper.readValue(attrJson, new TypeReference<Map<String, Object>>() {
                    });

//                    resultMap.put("guid", (String) attrMap.get("AccountGuid"));
//                    resultMap.put("nickname", (String) attrMap.get("AccountId"));
                    resultMap.put("guid", (String) attrMap.get("user_guid"));
                    resultMap.put("nickname", searchKey);
                }
            }
            return resultMap;
        }catch (Exception e){
            log.error("getUsersByName exception: {}", e.getMessage());
            throw new RestApiException(CommonCode.ERROR.getHttpStatus(), ErrorCode.DYNAMODB_CONNECTION_ERROR.getMessage());
        }

    }

    // 유저조회 guid
    // return guid, account_id
    public Map<String, String> getUsersByGuid(String searchKey){
        Map<String,String> resultMap = null;

        QueryRequest queryRequest = QueryRequest.builder()
                .tableName(metaTable)
                .keyConditionExpression("PK = :pkValue AND SK = :skValue") // 파티션 키와 조건식 설정
                .expressionAttributeValues(Map.of(":pkValue", AttributeValue.builder().s("user_base#"+searchKey).build()
                        ,":skValue", AttributeValue.builder().s("empty").build()))
                .build();

        try{
            // 쿼리 실행
            QueryResponse response = dynamoDbClient.query(queryRequest);

            // 응답에서 원하는 속성을 가져옵니다.
            for (Map<String, AttributeValue> item : response.items()) {
                AttributeValue attrValue = item.get("UserBaseAttrib");
                if (attrValue != null) {
                    resultMap = new HashMap<>();
                    // "Attr" 속성의 값을 읽어옵니다.
                    String attrJson = attrValue.s();

                    // JSON 문자열을 파싱하여 Map 또는 다른 객체로 변환합니다.
                    ObjectMapper objectMapper = new ObjectMapper();
                    Map<String, Object> attrMap = objectMapper.readValue(attrJson, new TypeReference<Map<String, Object>>() {
                    });

                    resultMap.put("guid", searchKey);
                    resultMap.put("nickname", (String) attrMap.get("account_id"));
                }
            }
            return resultMap;
        }catch (Exception e){
            log.error("getUsersByGuid exception: {}", e.getMessage());
            throw new RestApiException(CommonCode.ERROR.getHttpStatus(), ErrorCode.DYNAMODB_CONNECTION_ERROR.getMessage());
        }

    }

    //유저조회 account_id
    //return guid, account_id
    public Map<String, String> getUsersByAccountId(String searchKey){
        Map<String,String> resultMap = null;

        QueryRequest queryRequest = QueryRequest.builder()
                .tableName(metaTable)
                .keyConditionExpression("PK = :pkValue AND SK = :skValue") // 파티션 키와 조건식 설정
                .expressionAttributeValues(Map.of(":pkValue", AttributeValue.builder().s("account_base#"+searchKey).build()
                        ,":skValue", AttributeValue.builder().s("empty").build()))
                .build();

        try{
            // 쿼리 실행
            QueryResponse response = dynamoDbClient.query(queryRequest);

            // 응답에서 원하는 속성을 가져옵니다.
            for (Map<String, AttributeValue> item : response.items()) {
                AttributeValue attrValue = item.get("AccountBaseAttrib");
                if (attrValue != null) {
                    resultMap = new HashMap<>();
                    // "Attr" 속성의 값을 읽어옵니다.
                    String attrJson = attrValue.s();

                    // JSON 문자열을 파싱하여 Map 또는 다른 객체로 변환합니다.
                    ObjectMapper objectMapper = new ObjectMapper();
                    Map<String, Object> attrMap = objectMapper.readValue(attrJson, new TypeReference<Map<String, Object>>() {
                    });

                    resultMap.put("guid", (String) attrMap.get("user_guid"));
                    resultMap.put("nickname", (String) attrMap.get("account_id"));
                }
            }
            return resultMap;
        }catch (Exception e){
            log.error("getUsersByAccountId exception: {}", e.getMessage());
            throw new RestApiException(CommonCode.ERROR.getHttpStatus(), ErrorCode.DYNAMODB_CONNECTION_ERROR.getMessage());
        }

    }


    public Map<String, Object> getAccountInfo(String guid){
        Map<String, Object> resMap = new HashMap<>();

        String key = "PK = :pkValue AND SK = :skValue";
        Map<String, AttributeValue> values = Map.of(":pkValue", AttributeValue.builder().s("account_base#"+guid).build()
                ,":skValue", AttributeValue.builder().s("empty").build());

        try {
            // 쿼리 실행
            QueryResponse response = executeQuery(key, values);

            // 응답에서 원하는 속성을 가져옵니다.
            for (Map<String, AttributeValue> item : response.items()) {
                AttributeValue attrValue = item.get("AccountBaseAttrib");
                if (attrValue != null) {
                    // "Attr" 속성의 값을 읽어옵니다.
                    String attrJson = attrValue.s();

                    // JSON 문자열을 파싱하여 Map 또는 다른 객체로 변환합니다.
                    ObjectMapper objectMapper = new ObjectMapper();
                    Map<String, Object> attrMap = objectMapper.readValue(attrJson, new TypeReference<Map<String, Object>>() {});

                    resMap.put("userInfo", UsersResponse.UserInfo.builder()
                            .aid(CommonUtils.objectToString(attrMap.get("user_guid")))
                            .userId(CommonUtils.objectToString(attrMap.get("account_id")))
                            .nation(LANGUAGETYPE.values()[CommonUtils.objectToInteger(attrMap.get("language_type"))])
                            //
                            .membership(CommonUtils.objectToString(null))
                            //todo 친구 추천 코드 임시 null 값으로 셋팅 23.09.20
                            .friendCode(CommonUtils.objectToString(null))
                            .createDt(CommonUtils.objectToString(attrMap.get("created_datetime")))
                            .accessDt(CommonUtils.objectToString(attrMap.get("login_datetime")))
                            .endDt(CommonUtils.objectToString(attrMap.get("logout_datetime")))
                            .walletUrl(CommonUtils.objectToString(attrMap.get("connect_facewallet")))
                            .adminLevel(CommonUtils.objectToString(attrMap.get("auth_amdin_level_type")))
                            //todo 예비슬롯 임시 null 값으로 셋팅 23.09.20
                            .spareSlot(CommonUtils.objectToString(null))
                            .build());
                }
            }
            log.info("getAccountInfo UserInfo: {}", resMap);

            return resMap;
        } catch (Exception e) {
            throw new RestApiException(CommonCode.ERROR.getHttpStatus(), ErrorCode.DYNAMODB_CONNECTION_ERROR.getMessage());
        }
    }

    // 유저조회 - 기본정보
    public Map<String, Object> getCharInfo(String guid){
        Map<String, Object> resMap = new HashMap<>();

        String key = "PK = :pkValue AND SK = :skValue";
        Map<String, AttributeValue> values = Map.of(":pkValue", AttributeValue.builder().s("money#"+guid).build()
                ,":skValue", AttributeValue.builder().s("empty").build());

        try {
            // 쿼리 실행
            QueryResponse response = executeQuery(key, values);

            // 응답에서 원하는 속성을 가져옵니다.
            for (Map<String, AttributeValue> item : response.items()) {

                //캐릭터 CharInfo 조회
                AttributeValue charValue = item.get("MoneyAttrib");
                if (charValue != null) {
                    // "Attr" 속성의 값을 읽어옵니다.
                    Map<String, AttributeValue> attrMap = charValue.m();

                    resMap.put("charInfo", UsersResponse.CharInfo.builder()
                            .characterName(getGuidByName(guid))
                            .level(CommonUtils.objectToString(null))
                            .goldCali(CommonUtils.objectToString(attrMap.get("gold").n()))
                            .redCali(CommonUtils.objectToString(attrMap.get("calium").n()))
                            .blackCali(CommonUtils.objectToString(attrMap.get("ruby").n()))
                            .blueCali(CommonUtils.objectToString(attrMap.get("sapphire").n()))
                            .build());
                }
            }
            log.info("getCharInfo CharInfo: {}", resMap);

            return resMap;
        } catch (Exception e) {
            throw new RestApiException(CommonCode.ERROR.getHttpStatus(), ErrorCode.DYNAMODB_CONNECTION_ERROR.getMessage());
        }
    }

    // 유저조회 - 아바타
    public Map<String, Object> getAvatarInfo(String guid){
        Map<String, Object> resMap = new HashMap<>();

        String key = "PK = :pkValue";
        Map<String, AttributeValue> values = Map.of(":pkValue", AttributeValue.builder().s("character_base#"+guid).build());

        try {
            excuteItems(executeQuery(key, values), "CharacterBaseAttrib")
            .forEach(attrMap -> {
                Map<String, Object> profile = (Map<String, Object>) attrMap.get("appearance_profile");

                //Object customValue = attrMap.get("CustomValue");
                resMap.put("avatarInfo", UsersResponse.AvatarInfo.builder()
                        .characterId(CommonUtils.objectToString(attrMap.get("character_guid")))
                        .basicstyle(CommonUtils.objectToString(profile.get("basic_style")))
                        .hairstyle(CommonUtils.objectToString(profile.get("hair_style")))
                        .facesCustomizing(CommonUtils.objectToIntArray(profile.get("custom_values")))
                        .bodyshape(CommonUtils.objectToString(profile.get("body_shape")))
                        .build());
            });
            log.info("getAvatarInfo AvatarInfo: {}", resMap);

            return resMap;
        } catch (Exception e) {
            throw new RestApiException(CommonCode.ERROR.getHttpStatus(), ErrorCode.DYNAMODB_CONNECTION_ERROR.getMessage());
        }
    }

    //퀘스트 조회
    public List<UsersResponse.QuestInfo> getQuest(String guid){
        List<UsersResponse.QuestInfo> res = new ArrayList<>();
        String key = "PK = :pkValue";
        Map<String, AttributeValue> values = Map.of(":pkValue", AttributeValue.builder().s("quest#"+guid).build());

        try {
            excuteItems(executeQuery(key, values), "QuestAttrib")
                    .forEach(attrMap -> {
                        Integer questId = (Integer) attrMap.get("quest_id");
                        Integer current_task_no = (Integer)attrMap.get("current_task_num");
                        List<MetaQuestData> metaQuests = metaDataHandler.getMetaQuestData(questId);
                        // 상세보기 퀘스트 전체 리스트

                        List<UsersResponse.Quest> detailQuests = metaQuests.stream()
                                .map(metaData -> UsersResponse.Quest.builder()
                                        .questId(metaData.getQuestId())
                                        .taskNo(metaData.getTaskNum())
                                        .questName(metaDataHandler.getTextStringData(metaData.getTaskName()))
                                        .counter(metaData.getCounter())
                                        .status(current_task_no > metaData.getTaskNum() ? "완료" : "미완료" )
                                        .build())
                                .toList();

                        //퀘스트 명칭
                        String taskName = metaQuests.stream()
                                .filter(attr -> attr.getTaskNum().equals(current_task_no))
                                .map(MetaQuestData::getTaskName)
                                .findFirst().orElse(null);

                        UsersResponse.QuestInfo questInfo = UsersResponse.QuestInfo.builder()
                                .questId(questId)
                                .questName(metaDataHandler.getTextStringData(taskName))
                                .status(CommonUtils.objectToString(attrMap.get("is_complete")))
                                .assignTime((String) attrMap.get("quest_assign_time"))
                                .type((String) attrMap.get("quest_type"))
                                .startTime((String) attrMap.get("task_start_time"))
                                .completeTime((String) attrMap.get("quest_complete_time"))
                                .currentTaskNum((Integer) attrMap.get("current_task_num"))
                                .detailQuest(detailQuests)
                                .build();

                        res.add(questInfo);
                    });
            log.info("getQuest QuestInfo: {}", res);

            return res;

        } catch (Exception e) {
            throw new RestApiException(CommonCode.ERROR.getHttpStatus(), ErrorCode.DYNAMODB_CONNECTION_ERROR.getMessage());
        }
    }

    //guid 로 item 테이블 조회
    public Map<String, Object> getItemTable(String guid){
        QueryRequest queryRequest = QueryRequest.builder()
                .tableName(metaTable)
                .keyConditionExpression("PK = :pkValue AND SK = :skValue") // 파티션 키와 조건식 설정
                .expressionAttributeValues(
                        Map.of(":pkValue", AttributeValue.builder().s("item#"+guid).build()
                                ,":skValue", AttributeValue.builder().s("item#"+guid).build()))
                .build();

        try {
            // 쿼리 실행
            QueryResponse response = dynamoDbClient.query(queryRequest);

            // 응답에서 원하는 속성을 가져옵니다.
            for (Map<String, AttributeValue> item : response.items()) {
                AttributeValue attrValue = item.get("Attr");
                if (attrValue != null) {
                    // "Attr" 속성의 값을 읽어옵니다.
                    String attrJson = attrValue.s();

                    // JSON 문자열을 파싱하여 Map 또는 다른 객체로 변환합니다.
                    ObjectMapper objectMapper = new ObjectMapper();
                    // JSON 문자열을 Map으로 파싱
                    Map<String, Object> attrMap = objectMapper.readValue(attrJson, new TypeReference<Map<String, Object>>() {});

                    return attrMap;
                }
            }

            return null;
        } catch (Exception e) {
            throw new RestApiException(CommonCode.ERROR.getHttpStatus(), ErrorCode.DYNAMODB_CONNECTION_ERROR.getMessage());
        }
    }

    public void insertUpdateData(String guid, String type, boolean flag) {

        // 업데이트할 데이터 맵 생성
        Map<String, AttributeValue> key = new HashMap<>();
        key.put("PK", AttributeValue.builder().s("char#"+guid).build());
        key.put("SK", AttributeValue.builder().s("char#"+guid).build());

        Map<String, AttributeValueUpdate> attributeUpdates = new HashMap<>();

        attributeUpdates.put(type, AttributeValueUpdate.builder()
                .action(AttributeAction.PUT)
                .value(AttributeValue.builder().bool(flag).build())
                .build());

        // UpdateItem 요청 작성
        UpdateItemRequest updateItemRequest = UpdateItemRequest.builder()
                .tableName(metaTable)
                .key(key)
                .attributeUpdates(attributeUpdates)
                .build();

        // 데이터 업데이트 또는 인서트 요청
        dynamoDbClient.updateItem(updateItemRequest);
    }

    // dynamoDB 쿼리 리턴
    public QueryResponse executeQuery(String key, Map<String, AttributeValue> values) {
        QueryRequest getItemRequest = QueryRequest.builder()
                .tableName(metaTable)
                .keyConditionExpression(key)
                .expressionAttributeValues(values)
                .build();

        return dynamoDbClient.query(getItemRequest);
    }

    public Map<String, AttributeValue> getItem(String partitionKey, String sortKey) {
        Map<String, AttributeValue> keyMap = new HashMap<>();
        keyMap.put("PK", AttributeValue.builder().s(partitionKey).build());
        keyMap.put("SK", AttributeValue.builder().s(sortKey).build());
        try{
            // GetItem 요청 작성
            GetItemRequest getItemRequest = GetItemRequest.builder()
                    .tableName(metaTable)
                    .key(keyMap)
                    .build();

            // 아이템 가져오기
            GetItemResponse getItemResponse = dynamoDbClient.getItem(getItemRequest);
            return getItemResponse.item();
        }catch (Exception e){
            log.error("getItem Fail: {}", e.getMessage());
            throw new RestApiException(CommonCode.ERROR.getHttpStatus(), ErrorCode.DYNAMODB_CONNECTION_ERROR.getMessage());
        }

    }

    public Stream<Map<String, Object>> excuteItems (QueryResponse response, String attrip){
        return response.items().stream()
                .map(item -> item.get(attrip))
                .filter(Objects::nonNull)
                .map(AttributeValue::s)
                .map(attrJson -> {
                    ObjectMapper objectMapper = new ObjectMapper();
                    try {
                        return objectMapper.readValue(attrJson, new TypeReference<Map<String, Object>>() {});
                    } catch (JsonProcessingException e) {
                        throw new RuntimeException("JSON parsing error", e);
                    }
                });
    }

    public boolean isWhiteOrBlackUser(String accountId){
        String key = "PK = :pkValue";
        Map<String, AttributeValue> values = Map.of(":pkValue", AttributeValue.builder().s("account_base#"+accountId).build());
        AtomicBoolean isFlag = new AtomicBoolean(false);

        excuteItems(executeQuery(key, values), "AccountBaseAttrib")
                .forEach(attrMap -> {
                    String[] blockPolicy = CommonUtils.objectToStringArray(attrMap.get("block_policy"));

                    if(Arrays.stream(blockPolicy).findAny().isEmpty()){
                        isFlag.set(false);
                    }else{
                        isFlag.set(true);
                    }
                });

        return isFlag.get();
//        if (attributeValue == null || attributeValue.s() == null) {
//            // 속성 값이 없거나 문자열이 아닌 경우에 대한 처리
//            return false;
//        }
//
//        // 속성 값을 문자열로 가져옴
//        String isFlag = attributeValue.s();
//
//        // "true" 문자열과 대소문자 구분 없이 비교하여 boolean 값으로 반환
//        return isFlag.equalsIgnoreCase("true");
//        if(attr == null) return false;


    }

    public void updateBlockUserStart(BlackList blockUser){
        try{
            String accountId = getGuidByAccountId(blockUser.getGuid());
            SANCTIONS reasonType = blockUser.getSanctions();
//            SANCTIONSTYPE policyType = blockUser.getType();
//            List<SANCTIONSTYPE> listPolicyType = new ArrayList<>();
//            listPolicyType.add(policyType);
            DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSSSSS");
            String startTime = blockUser.getStartDt().format(formatter);
            String endTime = blockUser.getEndDt().format(formatter);

            Map<String, AttributeValue> item = getItem("account_base#" + accountId,"empty");

            String InfoJson = item.get("AccountBaseAttrib").s();
            log.info("updateBlockUserStart Before AccountBaseAttrib: {}", InfoJson);

            ObjectMapper objectMapper = new ObjectMapper();
            JsonNode infoNode = objectMapper.readTree(InfoJson);

            ((ObjectNode) infoNode).put("block_start_datetime", startTime);
            ((ObjectNode) infoNode).put("block_end_datetime", endTime);
            ArrayNode policyArray = objectMapper.createArrayNode();
            policyArray.add(blockUser.getType().toString());
            ((ObjectNode) infoNode).set("block_policy", policyArray);
//            ((ObjectNode) infoNode).put("block_policy", listPolicyType.toString());
            ((ObjectNode) infoNode).put("block_reason", reasonType.toString());

            String updatedInfoJson = infoNode.toString();
            String nowDateTime = LocalDateTime.now().format(formatter);
            log.info("updateBlockUserStart Tobe AccountBaseAttrib: {}", updatedInfoJson);

            Map<String, AttributeValue> expressionAttributeValues = new HashMap<>();
            expressionAttributeValues.put(":newAttrib", AttributeValue.builder().s(updatedInfoJson).build());
            expressionAttributeValues.put(":nowDate", AttributeValue.builder().s(nowDateTime).build());

            String updateExpression = "SET AccountBaseAttrib = :newAttrib, UpdatedDateTime = :nowDate";

            UpdateItemRequest updateRequest = UpdateItemRequest.builder()
                    .tableName(metaTable)
                    .key(Map.of(
                            "PK", AttributeValue.builder().s("account_base#" + accountId).build(),
                            "SK", AttributeValue.builder().s("empty").build()))
                    .updateExpression(updateExpression)
                    .expressionAttributeValues(expressionAttributeValues)
                    .returnValues(ReturnValue.ALL_NEW) // 업데이트 후의 값을 반환하려면 지정
                    .build();


            dynamoDbClient.updateItem(updateRequest);
        }catch(Exception e){
            log.error("updateBlockUserStart: " + e.getMessage());
            throw new RestApiException(CommonCode.ERROR.getHttpStatus(), ErrorCode.DYNAMODB_CONNECTION_ERROR.getMessage() );
        }
    }

    public void updateBlockUserEnd(String guid){
        try{
            String accountId = getGuidByAccountId(guid);
            DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSSSSS");
            String endTime = LocalDateTime.of(9999, 12, 31, 23, 59, 59, 999999900).format(formatter);

            Map<String, AttributeValue> item = getItem("account_base#" + accountId,"empty");

            String InfoJson = item.get("AccountBaseAttrib").s();
            log.info("updateBlockUserEnd Before AccountBaseAttrib: {}", InfoJson);

            ObjectMapper objectMapper = new ObjectMapper();
            JsonNode infoNode = objectMapper.readTree(InfoJson);

            ((ObjectNode) infoNode).put("block_start_datetime", endTime);
            ((ObjectNode) infoNode).put("block_end_datetime", endTime);
            ((ObjectNode) infoNode).put("block_policy", new ArrayList<>().toString());
            ((ObjectNode) infoNode).put("block_reason", "");

            String updatedInfoJson = infoNode.toString();
            String nowDateTime = LocalDateTime.now().format(formatter);
            log.info("updateBlockUserEnd Tobe AccountBaseAttrib: {}", updatedInfoJson);

            Map<String, AttributeValue> expressionAttributeValues = new HashMap<>();
            expressionAttributeValues.put(":newAttrib", AttributeValue.builder().s(updatedInfoJson).build());
            expressionAttributeValues.put(":nowDate", AttributeValue.builder().s(nowDateTime).build());

            String updateExpression = "SET AccountBaseAttrib = :newAttrib, UpdatedDateTime = :nowDate";

            UpdateItemRequest updateRequest = UpdateItemRequest.builder()
                    .tableName(metaTable)
                    .key(Map.of(
                            "PK", AttributeValue.builder().s("account_base#" + accountId).build(),
                            "SK", AttributeValue.builder().s("empty").build()))
                    .updateExpression(updateExpression)
                    .expressionAttributeValues(expressionAttributeValues)
                    .returnValues(ReturnValue.ALL_NEW) // 업데이트 후의 값을 반환하려면 지정
                    .build();

            dynamoDbClient.updateItem(updateRequest);
        }catch(Exception e){
            log.error("updateBlockUserEnd: {}", e.getMessage());
            throw new RestApiException(CommonCode.ERROR.getHttpStatus(), ErrorCode.DYNAMODB_CONNECTION_ERROR.getMessage() );
        }
    }

    // 닉네임 변경
    public void updateNickname(String guid,String nickname,String newNickname){
        try{
            // char#guid 에서 CharInfo-> DisplayName 변경
            updateCharInfo(guid, newNickname);

            // nickname#xxx 에서 Attr-> AccountId 변경
            createNewNickName(guid,newNickname);

            // 기존 nickname 항목 삭제 처리
            deleteNickname(nickname);
        }catch (Exception e){
            log.error("updateNickname: {}", e.getMessage());
            throw new RestApiException(CommonCode.ERROR.getHttpStatus(), ErrorCode.DYNAMODB_CONNECTION_ERROR.getMessage() );
        }

    }

    // GM 권한 변경
    public void updateAdminLevel(String guid, String type){
        AuthAdminLevelType adminLevel = RabbitMqUtils.getUserAdminLevelType(type);

        try{
            String accountId = getGuidByAccountId(guid);
            Map<String, AttributeValue> item = getItem("account_base#" + accountId, "empty");

            String InfoJson = item.get("AccountBaseAttrib").s();
            log.info("updateAdminLevel Before AccountBaseAttrib: {}", InfoJson);

            ObjectMapper objectMapper = new ObjectMapper();
            JsonNode infoNode = objectMapper.readTree(InfoJson);

            ((ObjectNode) infoNode).put("auth_amdin_level_type", adminLevel.getNumber());

            String updatedInfoJson = infoNode.toString();
            log.info("updateAdminLevel Tobe AccountBaseAttrib: {}", updatedInfoJson);

            Map<String, AttributeValue> expressionAttributeValues = new HashMap<>();
            expressionAttributeValues.put(":newAttrib", AttributeValue.builder().s(updatedInfoJson).build());

            String updateExpression = "SET AccountBaseAttrib = :newAttrib";

            UpdateItemRequest updateRequest = UpdateItemRequest.builder()
                    .tableName(metaTable)
                    .key(Map.of(
                            "PK", AttributeValue.builder().s("account_base#" + accountId).build(),
                            "SK", AttributeValue.builder().s("empty").build()))
                    .updateExpression(updateExpression)
                    .expressionAttributeValues(expressionAttributeValues)
                    .returnValues(ReturnValue.ALL_NEW) // 업데이트 후의 값을 반환하려면 지정
                    .build();


            dynamoDbClient.updateItem(updateRequest);
        }catch (Exception e){
            log.error("updateAdminLevel: {}", e.getMessage());
            throw new RestApiException(CommonCode.ERROR.getHttpStatus(), ErrorCode.DYNAMODB_CONNECTION_ERROR.getMessage() );
        }

    }

    public void updateCharInfo(String guid, String newNickname) throws JsonProcessingException {

        // 기존 CharInfo 값 가져오기
        Map<String, AttributeValue> item = getItem("char#" + guid, "char#" + guid);
        String charInfoJson = item.get("CharInfo").s();

        // CharInfo JSON 문자열을 파싱
        ObjectMapper objectMapper = new ObjectMapper();
        JsonNode charInfoNode = objectMapper.readTree(charInfoJson);

        // 원하는 속성 변경
        ((ObjectNode) charInfoNode).put("DisplayName", newNickname);

        // 변경된 CharInfo JSON 문자열
        String updatedCharInfoJson = charInfoNode.toString();

        // 업데이트할 내용을 정의
        Map<String, AttributeValue> expressionAttributeValues = new HashMap<>();
        expressionAttributeValues.put(":newNickName", AttributeValue.builder().s(updatedCharInfoJson).build());

        // 업데이트 표현식을 정의
        String updateExpression = "SET CharInfo = :newNickName";
        // 업데이트 요청 생성
        UpdateItemRequest updateRequest = UpdateItemRequest.builder()
                .tableName(metaTable)
                .key(Map.of(
                        "PK", AttributeValue.builder().s("char#" + guid).build(),
                        "SK", AttributeValue.builder().s("char#" + guid).build()))
                .updateExpression(updateExpression)
                .expressionAttributeValues(expressionAttributeValues)
                .returnValues(ReturnValue.ALL_NEW) // 업데이트 후의 값을 반환하려면 지정
                .build();


        dynamoDbClient.updateItem(updateRequest);
    }
    public void createNewNickName(String guid, String newNickname) {
        String attrJson = String.format("{\"AccountGuid\":\"%s\",\"AccountId\":\"%s\"}", guid, newNickname);

        Map<String, AttributeValue> itemAttributes = new HashMap<>();
        itemAttributes.put("PK", AttributeValue.builder().s("user_nickname_registry#global").build());
        itemAttributes.put("SK", AttributeValue.builder().s(newNickname).build());
        itemAttributes.put("Attr", AttributeValue.builder().s(attrJson).build());
        itemAttributes.put("Type", AttributeValue.builder().s("NickName").build());

        PutItemRequest item = PutItemRequest.builder()
                .tableName(metaTable)
                .item(itemAttributes)
                .build();

        dynamoDbClient.putItem(item);

    }
    public void deleteNickname(String nickname) {

        Map<String, AttributeValue> itemAttributes = new HashMap<>();
        itemAttributes.put("PK", AttributeValue.builder().s("nickname#" + nickname).build());
        itemAttributes.put("SK", AttributeValue.builder().s("nickname#").build());

        DeleteItemRequest  request = DeleteItemRequest.builder()
                .tableName(metaTable)
                .key(itemAttributes)
                .build();

        dynamoDbClient.deleteItem(request);

    }

    //신고 내역 조회
    public List<UserReportResponse.Report> getUserReportList(Map<String,String> requestParam) {

        List<UserReportResponse.Report> list = new ArrayList<>();
        String startTime = CommonUtils.objectToString(requestParam.get("start_dt"));
        String endTime = CommonUtils.objectToString(requestParam.get("end_dt"));

        String expression = "PK = :pkValue and SK BETWEEN :skStartDt AND :skEndDt";

        /*
        LocalDateTime startDt =CommonUtils.stringToTime(startTime);
        LocalDateTime endDt = CommonUtils.stringToTime(endTime);

        int months = CommonUtils.calculateMonths(startDt, endDt);
        Map<String, AttributeValue> expressionAttributeValues = new HashMap<>();
        for (int i = 0 ; i < months; i++){
            expressionAttributeValues = new HashMap<>();
            expressionAttributeValues.put(":pkValue", AttributeValue.builder().s("userReport#" + startDt.getYear()
                    +String.format("%02d", startDt.plusMonths(i).getMonthValue())).build());
            expressionAttributeValues.put(":skStartDt", AttributeValue.builder().s("report#" + startDt).build());
            expressionAttributeValues.put(":skEndDt", AttributeValue.builder().s("report#" + endDt).build());
            QueryRequest queryRequest = QueryRequest.builder()
                    .tableName(metaTable)
                    .keyConditionExpression(expression)
                    .expressionAttributeValues(expressionAttributeValues)
                    .build();
            try {
                QueryResponse response = dynamoDbClient.query(queryRequest);

                // 응답에서 원하는 속성을 가져옵니다.
                for (Map<String, AttributeValue> item : response.items()) {
                    AttributeValue attrValue = item.get("ReportInfo");
                    if (attrValue != null) {
                        // "Attr" 속성의 값을 읽어옵니다.
                        String attrJson = attrValue.s();

                        // JSON 문자열을 파싱하여 Map 또는 다른 객체로 변환합니다.
                        ObjectMapper objectMapper = new ObjectMapper();
                        // JSON 문자열을 Map으로 파싱
                        Map<String, Object> attrMap = objectMapper.readValue(attrJson, new TypeReference<Map<String, Object>>() {});
                        //담당자 검색
                        Map<String, Object> replyInfoMap = null;
                        if(item.get("ReplyInfo")!= null){
                            //담당자 검색
                            String replyInfo = item.get("ReplyInfo").s();
                            replyInfoMap = objectMapper.readValue(replyInfo, new TypeReference<Map<String, Object>>() {});
                        };

                        Map createTime = (Map)attrMap.get("CreateTime");
                        Map reTime = (Map)attrMap.get("ResolutionTime");
                        // "Seconds" 값을 Instant으로 변환하고 "Nanos" 값을 더함
                        Instant createInstant = Instant.ofEpochSecond(
                                Long.valueOf(CommonUtils.objectToString(createTime.get("Seconds")))
                        ).plusNanos(
                                Integer.valueOf(CommonUtils.objectToString(createTime.get("Nanos")))
                        );
                        Instant reInstant = Instant.ofEpochSecond(
                                Long.valueOf(CommonUtils.objectToString(reTime.get("Seconds")))
                        ).plusNanos(
                                Integer.valueOf(CommonUtils.objectToString(reTime.get("Nanos")))
                        );
                        UserReportResponse.Report report = UserReportResponse.Report.builder()
                                .pk(item.get("PK").s())
                                .sk(item.get("SK").s())
                                .reporterGuid(attrMap.get("ReporterGuid").toString())
                                .reporterNickName(attrMap.get("ReporterNickName").toString())
                                .targetGuid(attrMap.get("TargetGuid").toString())
                                .targetNickName(attrMap.get("TargetNickName").toString())
                                .reportType(Arrays.stream(REPORTTYPE.values())
                                        .filter(r->r.getName().equals(attrMap.get("Reason").toString()))
                                        .findFirst().orElse(null))
                                .title(attrMap.get("Title").toString())
                                .detail(attrMap.get("Detail").toString())
                                .state(attrMap.get("State").toString().equals("1")? STATUS.UNRESOLVED:STATUS.RESOLVED)
                                .createTime(createInstant.atZone(ZoneOffset.UTC).toLocalDateTime())
                                .resolutionTime(Integer.valueOf(reTime.get("Seconds").toString()) == 0?null:
                                        reInstant.atZone(ZoneOffset.UTC).toLocalDateTime())
                                .managerEmail(item.get("ReplyInfo")!= null?
                                        CommonUtils.objectToString(replyInfoMap.get("ManagerEmail")):""
                                )
                                .build();

                        list.add(report);
                    }
                }
            }catch (JsonProcessingException jpe){
                log.error("getUserReportList JsonProcessingException: {}", jpe.getMessage());
                throw new RestApiException(CommonCode.ERROR.getHttpStatus(), ErrorCode.DYNAMODB_CONNECTION_ERROR.getMessage());
            }catch (Exception e){
                log.error("getUserReportList: {}", e.getMessage());
                throw new RestApiException(CommonCode.ERROR.getHttpStatus(), ErrorCode.DYNAMODB_CONNECTION_ERROR.getMessage());
            }
        }*/
        return list;
    }

    //신고내역 상세보기
    public UserReportResponse.ResultData getUserReportDetail(Map<String,String> requestParam){
        UserReportResponse.ResultData resultData = UserReportResponse.ResultData.builder().build();
        Map<String, AttributeValue> expressionAttributeValues = new HashMap<>();
        expressionAttributeValues.put(":pkValue", AttributeValue.builder().s(requestParam.get("pk")).build());
        expressionAttributeValues.put(":skValue", AttributeValue.builder().s(requestParam.get("sk")).build());
        QueryRequest queryRequest = QueryRequest.builder()
                .tableName(metaTable)
                .keyConditionExpression("PK = :pkValue and SK = :skValue")
                .expressionAttributeValues(expressionAttributeValues)
                .build();
        try{
            QueryResponse response = dynamoDbClient.query(queryRequest);
            for (Map<String, AttributeValue> item : response.items()) {
                AttributeValue ReportInfo = item.get("ReportInfo");
                if (ReportInfo != null) {
                    // "Attr" 속성의 값을 읽어옵니다.
                    String attrJson = ReportInfo.s();
                    // JSON 문자열을 파싱하여 Map 또는 다른 객체로 변환합니다.
                    ObjectMapper objectMapper = new ObjectMapper();
                    Map<String, Object> attrMap = objectMapper.readValue(attrJson, new TypeReference<Map<String, Object>>() {});

                    Map createTime = (Map)attrMap.get("CreateTime");
                    Map reTime = (Map)attrMap.get("ResolutionTime");
                    // "Seconds" 값을 Instant으로 변환하고 "Nanos" 값을 더함
                    Instant createInstant = Instant.ofEpochSecond(
                            Long.valueOf(CommonUtils.objectToString(createTime.get("Seconds")))
                    ).plusNanos(
                            Integer.valueOf(CommonUtils.objectToString(createTime.get("Nanos")))
                    );
                    Instant reInstant = Instant.ofEpochSecond(
                            Long.valueOf(CommonUtils.objectToString(reTime.get("Seconds")))
                    ).plusNanos(
                            Integer.valueOf(CommonUtils.objectToString(reTime.get("Nanos")))
                    );
                    resultData.setReport(UserReportResponse.Report.builder()
                            .reporterGuid(attrMap.get("ReporterGuid").toString())
                            .reporterNickName(attrMap.get("ReporterNickName").toString())
                            .targetGuid(attrMap.get("TargetGuid").toString())
                            .targetNickName(attrMap.get("TargetNickName").toString())
                            .reportType(Arrays.stream(REPORTTYPE.values())
                                    .filter(r -> r.getName().equals(attrMap.get("Reason").toString()))
                                    .findFirst().orElse(null))
                            .title(attrMap.get("Title").toString())
                            .detail(attrMap.get("Detail").toString())
                            .state(attrMap.get("State").toString().equals("1") ? STATUS.UNRESOLVED : STATUS.RESOLVED)
                            .createTime(createInstant.atZone(ZoneOffset.UTC).toLocalDateTime())
                            .resolutionTime(Integer.valueOf(reTime.get("Seconds").toString()) == 0 ? null :
                                    reInstant.atZone(ZoneOffset.UTC).toLocalDateTime())
                            .build());
                }
            }
            return resultData;
        }catch (JsonProcessingException jpe){
            log.error("getUserReportDetail JsonProcessingException: {}", jpe.getMessage());
            throw new RestApiException(CommonCode.ERROR.getHttpStatus(), ErrorCode.DYNAMODB_CONNECTION_ERROR.getMessage());
        }catch (Exception e){
            log.error("getUserReportDetail: {}", e.getMessage());
            throw new RestApiException(CommonCode.ERROR.getHttpStatus(), ErrorCode.DYNAMODB_CONNECTION_ERROR.getMessage());
        }

    }
    public UserReportResponse.ResultData getUserReplyDetail(Map<String,String> requestParam){
        UserReportResponse.ResultData resultData = UserReportResponse.ResultData.builder().build();
        Map<String, AttributeValue> expressionAttributeValues = new HashMap<>();
        expressionAttributeValues.put(":pkValue", AttributeValue.builder().s(requestParam.get("pk")).build());
        expressionAttributeValues.put(":skValue", AttributeValue.builder().s(requestParam.get("sk")).build());
        QueryRequest queryRequest = QueryRequest.builder()
                .tableName(metaTable)
                .keyConditionExpression("PK = :pkValue and SK = :skValue")
                .expressionAttributeValues(expressionAttributeValues)
                .build();
        try{
            QueryResponse response = dynamoDbClient.query(queryRequest);
            for (Map<String, AttributeValue> item : response.items()) {
                AttributeValue ReplyInfo = item.get("ReplyInfo");
                if(ReplyInfo != null){
                    //담당자 검색
                    String replyInfo = item.get("ReplyInfo").s();
                    // JSON 문자열을 파싱하여 Map 또는 다른 객체로 변환합니다.
                    ObjectMapper objectMapper = new ObjectMapper();
                    Map<String, Object> replyInfoMap = objectMapper.readValue(replyInfo, new TypeReference<Map<String, Object>>() {});
                    resultData.setReply(
                            UserReportResponse.Reply.builder()
                                    .title(replyInfoMap.get("Title").toString())
                                    .detail(replyInfoMap.get("Detail").toString())
                                    .managerEmail(replyInfoMap.get("ManagerEmail").toString())
                                    .managerNickName(replyInfoMap.get("ManagerNickName").toString())
                                    .reporterNickName(replyInfoMap.get("ReporterNickName").toString())
                                    .build()
                    );
                };
            }
            return resultData;
        }catch (JsonProcessingException jpe){
            log.error("getUserReplyDetail JsonProcessingException: {}", jpe.getMessage());
            throw new RestApiException(CommonCode.ERROR.getHttpStatus(), ErrorCode.DYNAMODB_CONNECTION_ERROR.getMessage());
        }catch (Exception e){
            log.error("getUserReplyDetail: {}", e.getMessage());
            throw new RestApiException(CommonCode.ERROR.getHttpStatus(), ErrorCode.DYNAMODB_CONNECTION_ERROR.getMessage());
        }

    }
    //신고 내역 답장
    public void reportReply(UserReportRequest userReportRequest){

        String replyInfo = String.format("{\"Title\":\"%s\",\"Detail\":\"%s\"" +
                        ",\"ManagerEmail\":\"%s\",\"ManagerNickName\":\"%s\"" +
                        ",\"ReporterNickName\":\"%s\"}"
                , userReportRequest.getTitle(), userReportRequest.getDetail()
                , CommonUtils.getAdmin().getEmail(), adminMapper.findByEmail(CommonUtils.getAdmin().getEmail()).get().getName()
                , userReportRequest.getReporterNickName());

        Map<String, AttributeValue> expressionAttributeValues = new HashMap<>();
        expressionAttributeValues.put(":newValue", AttributeValue.builder().s(replyInfo).build());

        // 업데이트 표현식을 정의
        String updateExpression = "SET ReplyInfo = :newValue";

        UpdateItemRequest item = UpdateItemRequest.builder()
                .tableName(metaTable)
                .key(Map.of(
                        "PK", AttributeValue.builder().s(userReportRequest.getPk()).build(),
                        "SK", AttributeValue.builder().s(userReportRequest.getSk()).build()))
                .updateExpression(updateExpression)
                .expressionAttributeValues(expressionAttributeValues)
                .returnValues(ReturnValue.ALL_NEW) // 업데이트 후의 값을 반환하려면 지정
                .build();

        dynamoDbClient.updateItem(item);

    }

    public void changeReportStatus(UserReportRequest userReportRequest){
        try {

            // 기존 CharInfo 값 가져오기
            Map<String, AttributeValue> item = getItem(userReportRequest.getPk(), userReportRequest.getSk());
            String reportInfoJson = item.get("ReportInfo").s();

            // ReportInfo JSON 문자열을 파싱
            ObjectMapper objectMapper = new ObjectMapper();
            JsonNode reportInfoNode = objectMapper.readTree(reportInfoJson);

            Instant now = Instant.now();
            long seconds = now.getEpochSecond();
            int nanos = now.getNano();

            // 원하는 속성 변경
            ((ObjectNode) reportInfoNode).put("State", 2);
            ((ObjectNode) reportInfoNode.get("ResolutionTime")).put("Seconds", seconds);
            ((ObjectNode) reportInfoNode.get("ResolutionTime")).put("Nanos", nanos);

            // 변경된 ReportInfo JSON 문자열
            String updatedInfoJson = reportInfoNode.toString();

            // 업데이트할 내용을 정의
            Map<String, AttributeValue> expressionAttributeValues = new HashMap<>();
            expressionAttributeValues.put(":newValue", AttributeValue.builder().s(updatedInfoJson).build());

            // 업데이트 표현식을 정의
            String updateExpression = "SET ReportInfo = :newValue";
            // 업데이트 요청 생성
            UpdateItemRequest updateRequest = UpdateItemRequest.builder()
                    .tableName(metaTable)
                    .key(Map.of(
                            "PK", AttributeValue.builder().s(userReportRequest.getPk()).build(),
                            "SK", AttributeValue.builder().s(userReportRequest.getSk()).build()))
                    .updateExpression(updateExpression)
                    .expressionAttributeValues(expressionAttributeValues)
                    .returnValues(ReturnValue.ALL_NEW) // 업데이트 후의 값을 반환하려면 지정
                    .build();


            dynamoDbClient.updateItem(updateRequest);
        }catch (JsonProcessingException jpe){
            log.error("changeReportStatus JsonProcessingException: {}", jpe.getMessage());
            throw new RestApiException(CommonCode.ERROR.getHttpStatus(), ErrorCode.DYNAMODB_CONNECTION_ERROR.getMessage());
        }catch (Exception e){
            log.error("changeReportStatus: {}", e.getMessage());
            throw new RestApiException(CommonCode.ERROR.getHttpStatus(), ErrorCode.DYNAMODB_CONNECTION_ERROR.getMessage());
        }
    }
    public void dummy(Map<String, String> map){
        Instant now = Instant.now(); // 현재 시간을 얻습니다.
        LocalDateTime createTime = LocalDateTime.parse(map.get("CreateTime"), DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSSSSSSS'Z'"));
        Instant instant = createTime.atZone(ZoneId.of("UTC")).toInstant(); // 현재 시간을 초로 얻습니다.
        String replyInfo = String.format("{\"ReporterGuid\":\"%s\",\"ReporterNickName\":\"%s\"" +
                        ",\"TargetGuid\":\"%s\",\"TargetNickName\":\"%s\"" +
                        ",\"Reason\":\"%s\",\"Title\":\"%s\"" +
                        ",\"Detail\":\"%s\",\"State\":\"%s\"" +
                        ",\"CreateTime\":{\"Seconds\":%s,\"Nanos\":%s}" +
                        ",\"ResolutionTime\":{\"Seconds\":%s,\"Nanos\":%s}}"
                , map.get("ReporterGuid"), map.get("ReporterNickName")
                , map.get("TargetGuid"), map.get("TargetNickName")
                , map.get("Reason"),  map.get("Title")
                , map.get("Detail"),  map.get("State")
                , instant.getEpochSecond(),  instant.getNano()
                , 0,  0);

        Map<String, AttributeValue> expressionAttributeValues = new HashMap<>();
        expressionAttributeValues.put(":newValue", AttributeValue.builder().s(replyInfo).build());

        // 업데이트 표현식을 정의
        String updateExpression = "SET ReportInfo = :newValue";

        UpdateItemRequest item = UpdateItemRequest.builder()
                .tableName(metaTable)
                .key(Map.of(
                        "PK", AttributeValue.builder().s(map.get("pk")).build(),
                        "SK", AttributeValue.builder().s(map.get("sk")).build()))
                .updateExpression(updateExpression)
                .expressionAttributeValues(expressionAttributeValues)
                .returnValues(ReturnValue.ALL_NEW) // 업데이트 후의 값을 반환하려면 지정
                .build();

        dynamoDbClient.updateItem(item);
    }

    //아이템 내역 조회
    public List<ItemList> getItems(String guid){
        List<ItemList> list = new ArrayList<>();

        String key = "PK = :pkValue";
        Map<String, AttributeValue> values = Map.of(":pkValue", AttributeValue.builder().s("item#"+guid).build());

//        QueryRequest queryRequest = QueryRequest.builder()
//                .tableName(metaTable)
//                .keyConditionExpression("PK = :pkValue") // 파티션 키와 조건식 설정
//                .expressionAttributeValues(Map.of(":pkValue", AttributeValue.builder().s("item#"+guid).build()))
//                .build();

        try {
            // 쿼리 실행
            QueryResponse response = executeQuery(key, values);

            int row = 1;
            // 응답에서 원하는 속성을 가져옵니다.
            for (Map<String, AttributeValue> item : response.items()) {
                AttributeValue attrValue = item.get("ItemAttrib");
                if (attrValue != null) {
                    // "Attr" 속성의 값을 읽어옵니다.
                    String attrJson = attrValue.s();

                    // JSON 문자열을 파싱하여 Map 또는 다른 객체로 변환합니다.
                    ObjectMapper objectMapper = new ObjectMapper();
                    Map<String, Object> attrMap = objectMapper.readValue(attrJson, new TypeReference<Map<String, Object>>() {
                    });

                    String item_nm = metaDataHandler.getMetaItemNameData(CommonUtils.objectToInteger(attrMap.get("item_meta_id")));
                    ItemList itemInfo = ItemList.builder()
                            .rowNum((long) row)
                            .guid(guid)
                            .itemId(attrMap.get("item_meta_id").toString())
                            .itemName(metaDataHandler.getTextStringData(item_nm))
                            .status(ItemList.STATUS.PERMITTED)
                            .restoreType("")
                            .createBy(item.get("CreatedDateTime").s()).build();

                    list.add(itemInfo);

                    row++;
                }
            }
            log.info("getItems Response ItemInfo: {}", list);
        }
        catch (JsonProcessingException jpe){
            log.error("getItems JsonProcessingException: {}", jpe.getMessage());
            throw new RestApiException(CommonCode.ERROR.getHttpStatus(), ErrorCode.DYNAMODB_CONNECTION_ERROR.getMessage());
        }catch (Exception e){
            log.error("getItems: {}", e.getMessage());
            throw new RestApiException(CommonCode.ERROR.getHttpStatus(), ErrorCode.DYNAMODB_CONNECTION_ERROR.getMessage());
        }
        return list;
    }

    //아이템 - 의상 조회
    public Map<String, Object> getCloth(String guid){
        Map<String, Object> resultMap = new HashMap<>();

        String key = "PK = :pkValue";
        Map<String, AttributeValue> values = Map.of(":pkValue", AttributeValue.builder().s("item#"+guid).build());

        UsersResponse.ClothInfo.ClothInfoBuilder clothInfo = UsersResponse.ClothInfo.builder();

        Map<CLOTHSMALLTYPE, BiConsumer<UsersResponse.ClothInfo.ClothInfoBuilder, UsersResponse.ClothItem>> setterMap = new HashMap<>();
        setterMap.put(CLOTHSMALLTYPE.SHIRT, UsersResponse.ClothInfo.ClothInfoBuilder::clothShirt);
        setterMap.put(CLOTHSMALLTYPE.DRESS, UsersResponse.ClothInfo.ClothInfoBuilder::clothDress);
        setterMap.put(CLOTHSMALLTYPE.OUTER, UsersResponse.ClothInfo.ClothInfoBuilder::clothOuter);
        setterMap.put(CLOTHSMALLTYPE.PANTS, UsersResponse.ClothInfo.ClothInfoBuilder::clothPants);
        setterMap.put(CLOTHSMALLTYPE.GLOVES, UsersResponse.ClothInfo.ClothInfoBuilder::clothGloves);
        setterMap.put(CLOTHSMALLTYPE.RING, UsersResponse.ClothInfo.ClothInfoBuilder::clothRing);
        setterMap.put(CLOTHSMALLTYPE.BRACELET, UsersResponse.ClothInfo.ClothInfoBuilder::clothBracelet);
        setterMap.put(CLOTHSMALLTYPE.BAG, UsersResponse.ClothInfo.ClothInfoBuilder::clothBag);
        setterMap.put(CLOTHSMALLTYPE.BACKPACK, UsersResponse.ClothInfo.ClothInfoBuilder::clothBackpack);
        setterMap.put(CLOTHSMALLTYPE.CAP, UsersResponse.ClothInfo.ClothInfoBuilder::clothCap);
        setterMap.put(CLOTHSMALLTYPE.MASK, UsersResponse.ClothInfo.ClothInfoBuilder::clothMask);
        setterMap.put(CLOTHSMALLTYPE.GLASSES, UsersResponse.ClothInfo.ClothInfoBuilder::clothGlasses);
        setterMap.put(CLOTHSMALLTYPE.EARRING, UsersResponse.ClothInfo.ClothInfoBuilder::clothEarring);
        setterMap.put(CLOTHSMALLTYPE.NECKLACE, UsersResponse.ClothInfo.ClothInfoBuilder::clothNecklace);
        setterMap.put(CLOTHSMALLTYPE.SHOES, UsersResponse.ClothInfo.ClothInfoBuilder::clothShoes);
        setterMap.put(CLOTHSMALLTYPE.SOCKS, UsersResponse.ClothInfo.ClothInfoBuilder::clothSocks);
        setterMap.put(CLOTHSMALLTYPE.ANKLET, UsersResponse.ClothInfo.ClothInfoBuilder::clothAnklet);

        try {
            excuteItems(executeQuery(key, values), "ItemAttrib")
            .filter(attrMap -> attrMap.containsKey("equiped_inven_type") && (int) attrMap.get("equiped_inven_type") == 1)
            .forEach(attrMap -> {
                int pos = (int) attrMap.get("equiped_pos");
                String smallType = metaDataHandler.getMetaClothSmallTypeData(pos);
                int item_id = CommonUtils.objectToInteger(attrMap.get("item_meta_id"));

                UsersResponse.ClothItem clothItem = UsersResponse.ClothItem.builder()
                        .cloth(CommonUtils.objectToString(attrMap.get("item_meta_id")))
                        .clothName(metaDataHandler.getTextStringData(metaDataHandler.getMetaItemNameData(item_id)))
                        .slotType(metaDataHandler.getMetaClothSlotTypeData(pos))
                        .smallType(smallType)
                        .build();

                // ClothItem을 CLOTHSMALLTYPE 위치에 넣어 준다
                setterMap.getOrDefault(CLOTHSMALLTYPE.valueOf(smallType), (builder, item) -> {})
                        .accept(clothInfo, clothItem);
            });

            resultMap.put("clothInfo", clothInfo.build());
            log.info("getCloth Response clothInfo: {}", clothInfo);

        }catch (Exception e){
            log.error("getCloth: {}", e.getMessage());
            throw new RestApiException(CommonCode.ERROR.getHttpStatus(), ErrorCode.DYNAMODB_CONNECTION_ERROR.getMessage());
        }
        return resultMap;
    }

    //아이템 - 도구 조회
    public Map<String, Object> getTools(String guid){
        Map<String, Object> resultMap = new HashMap<>();

        String key = "PK = :pkValue";
        Map<String, AttributeValue> values = Map.of(":pkValue", AttributeValue.builder().s("item#"+guid).build());

        UsersResponse.SlotInfo.SlotInfoBuilder slotInfo = UsersResponse.SlotInfo.builder();

        Map<Integer, BiConsumer<UsersResponse.SlotInfo.SlotInfoBuilder, UsersResponse.ToolItem>> setterMap = Map.of(
                1, UsersResponse.SlotInfo.SlotInfoBuilder::Slot1,
                2, UsersResponse.SlotInfo.SlotInfoBuilder::Slot2,
                3, UsersResponse.SlotInfo.SlotInfoBuilder::Slot3,
                4, UsersResponse.SlotInfo.SlotInfoBuilder::Slot4
        );

        try {
            excuteItems(executeQuery(key, values), "ItemAttrib")
            .filter(attrMap -> attrMap.containsKey("equiped_inven_type") && (int) attrMap.get("equiped_inven_type") == 2)
            .forEach(attrMap -> {
                int pos = (int) attrMap.get("equiped_pos");
//                        String smallType = metaDataHandler.getMetaClothSmallTypeData(pos);
                int item_id = CommonUtils.objectToInteger(attrMap.get("item_meta_id"));
                String item_nm = metaDataHandler.getTextStringData(metaDataHandler.getMetaItemNameData(item_id));
                UsersResponse.ToolItem toolItem = UsersResponse.ToolItem.builder()
                        .toolId(CommonUtils.objectToString(attrMap.get("item_meta_id")))
//                        .toolName(metaDataHandler.getMetaToolData(CommonUtils.objectToInteger(attrMap.get("item_meta_id"))).getToolName())
                        .toolName(item_nm)
                        .build();

                // ClothItem을 CLOTHSMALLTYPE 위치에 넣어 준다
                setterMap.getOrDefault(pos, (builder, item) -> {})
                        .accept(slotInfo, toolItem);
            });

            resultMap.put("toolSlotInfo", slotInfo.build());
            log.info("getTools Response toolSlotInfo: {}", slotInfo);

        }catch (Exception e){
            log.error("getTools: {}", e.getMessage());
            throw new RestApiException(CommonCode.ERROR.getHttpStatus(), ErrorCode.DYNAMODB_CONNECTION_ERROR.getMessage());
        }
        return resultMap;
    }

    //아이템 - 인벤토리 조회
    public UsersResponse.InventoryInfo getInvenItems(String guid){
        String key = "PK = :pkValue";
        Map<String, AttributeValue> values = Map.of(":pkValue", AttributeValue.builder().s("item#"+guid).build());

        List<UsersResponse.Item> clothList = new ArrayList<>();
        List<UsersResponse.Item> propList = new ArrayList<>();
        List<UsersResponse.Item> beautyList = new ArrayList<>();
        List<UsersResponse.Item> tattooList = new ArrayList<>();
        List<UsersResponse.Item> currencyList = new ArrayList<>();
        List<UsersResponse.Item> etcList = new ArrayList<>();

        try {
            excuteItems(executeQuery(key, values), "ItemAttrib")
                    .filter(attrMap -> attrMap.containsKey("equiped_inven_type") && (int) attrMap.get("equiped_inven_type") == 0)
                    .forEach(attrMap -> {
                        int item_id = (int) attrMap.get("item_meta_id");
                        String item_nm = metaDataHandler.getTextStringData(metaDataHandler.getMetaItemNameData(item_id));
                        String item_type = metaDataHandler.getMetaItemLargeTypeData(item_id);

                        UsersResponse.Item inventory = UsersResponse.Item.builder()
                                .itemId(CommonUtils.objectToString(item_id))
                                .itemName(item_nm)
                                .count(CommonUtils.objectToDouble(attrMap.get("item_stack_count")))
                                .itemGuid(CommonUtils.objectToString(attrMap.get("item_guid")))
                                .build();

                        if(item_type.isEmpty()) {
                            etcList.add(inventory);
                        }else{
                            switch (ITEMLARGETYPE.valueOf(item_type)){
                                case CLOTH -> clothList.add(inventory);
                                case PROP -> propList.add(inventory);
                                case BEAUTY -> beautyList.add(inventory);
                                case TATTOO -> tattooList.add(inventory);
                                case CURRENCY -> currencyList.add(inventory);
                                default -> etcList.add(inventory);
                        }}
                    });

            log.info("getInvenItems Response cloth: {}, prop: {}, beauty: {}, tattoo: {}, currency: {}, etc: {}", clothList, propList, beautyList, tattooList, currencyList, etcList);

            return UsersResponse.InventoryInfo.builder()
                    .cloth(clothList)
                    .prop(propList)
                    .beauty(beautyList)
                    .tattoo(tattooList)
                    .currency(currencyList)
                    .etc(etcList)
                    .build();

        }catch (Exception e){
            log.error("getInvenItems: {}", e.getMessage());
            throw new RestApiException(CommonCode.ERROR.getHttpStatus(), ErrorCode.DYNAMODB_CONNECTION_ERROR.getMessage());
        }
    }

    // 유저 조회 - 메일
    public List<UsersResponse.Mail> getMail(String guid, String type){
        List<UsersResponse.Mail> resList = new ArrayList<>();

        String key = "PK = :pkValue";
        Map<String, AttributeValue> values = null;
        if(type.equals(SEARCHTYPE.SEND.name())){
            values = Map.of(":pkValue", AttributeValue.builder().s("sent_mail#"+guid).build());
        }else{
            values = Map.of(":pkValue", AttributeValue.builder().s("recv_mail#"+guid).build());
        }

        try {
            excuteItems(executeQuery(key, values), "MailAttrib")
                    .forEach(attrMap -> {
                        List<UsersResponse.MailItem> itemList = new ArrayList<>();
                        for (Map<String,Object> val : (List<Map<String,Object>>)attrMap.get("item_list")){
                            UsersResponse.MailItem item = new UsersResponse.MailItem();
                            item.setItemId(CommonUtils.objectToString(val.get("ItemId")));
                            item.setCount(CommonUtils.objectToDouble(val.get("Count")));
                            String item_nm = metaDataHandler.getMetaItemNameData(CommonUtils.objectToInteger(val.get("ItemId")));
                            item.setItemName(metaDataHandler.getTextStringData(item_nm));
                            itemList.add(item);
                        }

                        UsersResponse.Mail mail = UsersResponse.Mail.builder()
                                .mailGuid(CommonUtils.objectToString(attrMap.get("mail_guid")))
                                .createDt(CommonUtils.objectToString(attrMap.get("create_time")))
                                .title(CommonUtils.objectToString(attrMap.get("title")))
                                .content(CommonUtils.objectToString(attrMap.get("text")))
                                .receiveNickname(CommonUtils.objectToString(attrMap.get("receiver_nickname")))
                                .senderNickname(CommonUtils.objectToString(attrMap.get("sender_nickname")))
                                .isGetItem((boolean)attrMap.get("is_get_item"))
                                .status((boolean) attrMap.get("is_read"))
                                .isSystemMail((boolean) attrMap.get("is_system_mail"))
                                .mailItemList(itemList)
                                .build();

                        resList.add(mail);
                    });
            log.info("getMail Response MailInfo: {}", resList);

            return resList;
        } catch (Exception e) {
            log.error("getMail: {}", e.getMessage());
            throw new RestApiException(CommonCode.ERROR.getHttpStatus(), ErrorCode.DYNAMODB_CONNECTION_ERROR.getMessage());
        }
    }

    // 유저 조회 - 우편 삭제
    public String deleteMail(String type, String guid, String mail_guid) {
        Map<String, AttributeValue> itemAttributes = new HashMap<>();
        if(type.equals("SEND")){
            itemAttributes.put("PK", AttributeValue.builder().s("sent_mail#" + guid).build());
        }else{
            itemAttributes.put("PK", AttributeValue.builder().s("recv_mail#" + guid).build());
        }
        itemAttributes.put("SK", AttributeValue.builder().s(mail_guid).build());
        try {
            Map<String, AttributeValue> item = null;
            if(type.equals("SEND")){
                item = getItem("sent_mail#" + guid, mail_guid);
                log.info("deleteMail PK: {}, SK: {}", "sent_mail#" + guid, mail_guid);
            }else{
                item = getItem("recv_mail#" + guid, mail_guid);
                log.info("deleteMail PK: {}, SK: {}", "recv_mail#" + guid, mail_guid);
            }

            DeleteItemRequest request = DeleteItemRequest.builder()
                    .tableName(metaTable)
                    .key(itemAttributes)
                    .build();

            DeleteItemResponse response = dynamoDbClient.deleteItem(request);

            if(response.sdkHttpResponse().isSuccessful())
                return item.toString();

            return "";
        }catch (ConditionalCheckFailedException e) {
            log.error("deleteUsersMail Conditional check failed: {}", e.getMessage());
            throw new RestApiException(CommonCode.ERROR.getHttpStatus(), ErrorCode.DYNAMODB_CONNECTION_ERROR.getMessage());
        }catch(Exception e){
            log.error("deleteUsersMail: {}", e.getMessage());
            throw new RestApiException(CommonCode.ERROR.getHttpStatus(), ErrorCode.DYNAMODB_CONNECTION_ERROR.getMessage());
        }
    }

    // 유저 조회 - 우편 아이템 삭제
    public JSONObject updateMailItem(String type, String guid, String mail_guid, Long itemId, double count, double newCount) {
        try {
            Map<String, AttributeValue> item = null;
            Map<String, AttributeValue> key = new HashMap<>();
            if(type.equals("SEND")){
                item = getItem("sent_mail#" + guid, mail_guid);
                key = Map.of("PK", AttributeValue.builder().s("sent_mail#" + guid).build(),"SK", AttributeValue.builder().s(mail_guid).build());
            }else{
                item = getItem("recv_mail#" + guid, mail_guid);
                key = Map.of("PK", AttributeValue.builder().s("recv_mail#" + guid).build(),"SK", AttributeValue.builder().s(mail_guid).build());
            }

            String InfoJson = item.get("MailAttrib").s();

            ObjectMapper objectMapper = new ObjectMapper();
            JsonNode infoNode = objectMapper.readTree(InfoJson);
            log.info("updateMailItem Before updatedInfoJson: {}", infoNode.toString());

            ArrayNode itemListNode = (ArrayNode) infoNode.get("item_list");

            // Java 17 스타일의 IntStream을 사용하여 itemId를 찾고 처리
            OptionalInt indexOpt = IntStream.range(0, itemListNode.size())
                    .filter(i -> itemListNode.get(i).get("ItemId").asInt() == itemId)
                    .findFirst();

            if (indexOpt.isEmpty()) {
                log.error("updateMailItem mail item not found");
                throw new RestApiException(CommonCode.ERROR.getHttpStatus(), ErrorCode.DYNAMODB_CONNECTION_ERROR.getMessage());
            }

            int index = indexOpt.getAsInt();
            JsonNode itemNode = itemListNode.get(index);

            if (count > newCount) {
                // count 수정
                ((ObjectNode) itemNode).put("Count", count - newCount);
            } else {
                // item 삭제
                itemListNode.remove(index);
            }

            String updatedInfoJson = infoNode.toString();
            log.info("updateMailItem Tobe updatedInfoJson: {}", updatedInfoJson);

            Map<String, AttributeValue> expressionAttributeValues = new HashMap<>();
            expressionAttributeValues.put(":newAttrib", AttributeValue.builder().s(updatedInfoJson).build());

            String updateExpression = "SET MailAttrib = :newAttrib";

            UpdateItemRequest updateRequest = UpdateItemRequest.builder()
                    .tableName(metaTable)
                    .key(key)
                    .updateExpression(updateExpression)
                    .expressionAttributeValues(expressionAttributeValues)
                    .returnValues(ReturnValue.ALL_NEW) // 업데이트 후의 값을 반환하려면 지정
                    .build();


            dynamoDbClient.updateItem(updateRequest);

            JSONObject jsonObject = new JSONObject();
            jsonObject.put("data(before)", InfoJson);
            jsonObject.put("data(after)", updatedInfoJson);
            return jsonObject;
        }catch (ConditionalCheckFailedException e) {
            log.error("deleteUsersMail Conditional check failed: {}", e.getMessage());
            throw new RestApiException(CommonCode.ERROR.getHttpStatus(), ErrorCode.DYNAMODB_CONNECTION_ERROR.getMessage());
        }catch(Exception e){
            log.error("deleteUsersMail: {}", e.getMessage());
            throw new RestApiException(CommonCode.ERROR.getHttpStatus(), ErrorCode.DYNAMODB_CONNECTION_ERROR.getMessage());
        }
    }

    // 아이템 삭제
    public String deleteItem(String guid, String item_guid) {
        Map<String, AttributeValue> itemAttributes = new HashMap<>();
        itemAttributes.put("PK", AttributeValue.builder().s("item#" + guid).build());
        itemAttributes.put("SK", AttributeValue.builder().s(item_guid).build());
        try {
            Map<String, AttributeValue> item = getItem("item#" + guid, item_guid);
            log.info("deleteItem PK: {}, SK: {}", "item#" + guid, item_guid);

            DeleteItemRequest request = DeleteItemRequest.builder()
                    .tableName(metaTable)
                    .key(itemAttributes)
                    .build();

            DeleteItemResponse response = dynamoDbClient.deleteItem(request);

            if(response.sdkHttpResponse().isSuccessful())
                return item.toString();

            return "";
        }catch (ConditionalCheckFailedException e) {
            log.error("deleteItem Conditional check failed: {}", e.getMessage());
            throw new RestApiException(CommonCode.ERROR.getHttpStatus(), ErrorCode.DYNAMODB_CONNECTION_ERROR.getMessage());
        }catch(Exception e){
            log.error("deleteItem: {}", e.getMessage());
            throw new RestApiException(CommonCode.ERROR.getHttpStatus(), ErrorCode.DYNAMODB_CONNECTION_ERROR.getMessage());
        }
    }

    // 아이템 정보 수정
    public JSONObject updateItem(String guid, String item_guid, int cnt) {
        try{

            Map<String, AttributeValue> item = getItem("item#" + guid, item_guid);

            String InfoJson = item.get("ItemAttrib").s();

            ObjectMapper objectMapper = new ObjectMapper();
            JsonNode infoNode = objectMapper.readTree(InfoJson);
            log.info("updateItem Before UpdateInfo : {}", infoNode.toString());

            ((ObjectNode) infoNode).put("item_stack_count", cnt);

            String updatedInfoJson = infoNode.toString();
            log.info("updateItem Tobe UpdateInfo : {}", updatedInfoJson);

            Map<String, AttributeValue> expressionAttributeValues = new HashMap<>();
            expressionAttributeValues.put(":newAttrib", AttributeValue.builder().s(updatedInfoJson).build());

            String updateExpression = "SET ItemAttrib = :newAttrib";

            UpdateItemRequest updateRequest = UpdateItemRequest.builder()
                    .tableName(metaTable)
                    .key(Map.of(
                            "PK", AttributeValue.builder().s("item#" + guid).build(),
                            "SK", AttributeValue.builder().s(item_guid).build()))
                    .updateExpression(updateExpression)
                    .expressionAttributeValues(expressionAttributeValues)
                    .returnValues(ReturnValue.ALL_NEW) // 업데이트 후의 값을 반환하려면 지정
                    .build();


            dynamoDbClient.updateItem(updateRequest);

            JSONObject jsonObject = new JSONObject();
            jsonObject.put("data(before)", InfoJson);
            jsonObject.put("data(after)", updatedInfoJson);
            return jsonObject;
        }catch(Exception e){
            log.error("updateItem: {}", e.getMessage());
            throw new RestApiException(CommonCode.ERROR.getHttpStatus(), ErrorCode.DYNAMODB_CONNECTION_ERROR.getMessage() );
        }
    }

    // 아이템 - 타투 죄회
    public List<UsersResponse.Tattoo> getTattoo(String guid){Map<String, Object> resultMap = new HashMap<>();
        List<UsersResponse.Tattoo> resTatto = new ArrayList<>();
        String key = "PK = :pkValue";
        Map<String, AttributeValue> values = Map.of(":pkValue", AttributeValue.builder().s("item#"+guid).build());

        try {
            excuteItems(executeQuery(key, values), "ItemAttrib")
                    .filter(attrMap -> attrMap.containsKey("equiped_inven_type") && (int) attrMap.get("equiped_inven_type") == 3)
                    .forEach(attrMap -> {
                        int pos = CommonUtils.objectToInteger(attrMap.get("equiped_pos"));
                        if(pos == 0) return;

                        UsersResponse.Tattoo tattoo = new UsersResponse.Tattoo();
                        Long item_id = CommonUtils.objectToLong(attrMap.get("item_meta_id"));
                        tattoo.setItemId(item_id);
                        tattoo.setItemGuid(CommonUtils.objectToString(attrMap.get("Item_guid")));
                        tattoo.setLevel(Integer.valueOf(CommonUtils.objectToString(attrMap.get("level"))));
                        tattoo.setItemName(metaDataHandler.getTextStringData(metaDataHandler.getMetaItemNameData(item_id.intValue())));
                        tattoo.setSlot(pos);
                        resTatto.add(tattoo);
                    });
            log.info("getTattoo Response TattoInfo: {}", resTatto);

        }catch (Exception e){
            log.error("getTattoo: {}", e.getMessage());
            throw new RestApiException(CommonCode.ERROR.getHttpStatus(), ErrorCode.DYNAMODB_CONNECTION_ERROR.getMessage());
        }

        return resTatto;
    }

    public String insertSystemMail(int id, ArrayNode titleList, ArrayNode textList, ArrayNode senderList, LocalDateTime start_dt, LocalDateTime end_dt, ArrayNode itemList) {
        try {

            // Attrib에 저장할 JSON 생성
            ObjectMapper objectMapper = new ObjectMapper();
            ObjectNode infoNode = objectMapper.createObjectNode();
            infoNode.put("attrib_type", DynamoDBConstants.ATTRIB_SYSTEMMAIL);
            infoNode.put("mail_id", id);
            infoNode.set("sender_nickname", senderList);
            infoNode.set("title", titleList);
            infoNode.set("text", textList);
            infoNode.put("start_time", CommonUtils.convertUTCDate(start_dt));
            infoNode.put("end_time", CommonUtils.convertUTCDate(end_dt));
            infoNode.set("item_list", itemList);

            String infoJson = infoNode.toString();
            log.info("insertSystemMail SystemMetaMailAttrib: {}", infoJson);

            // 추가 데이터
            Map<String, AttributeValue> itemValues = new HashMap<>();
            itemValues.put("PK", AttributeValue.builder().s(DynamoDBConstants.PK_KEY_SYSTEM_MAIL).build());
            itemValues.put("SK", AttributeValue.builder().s(String.valueOf(id)).build());
            itemValues.put("CreatedDateTime", AttributeValue.builder().s(CommonUtils.convertUTCDate(LocalDateTime.now())).build());
            itemValues.put("DeletedDateTime", AttributeValue.builder().s(DynamoDBConstants.MIN_DATE).build());
            itemValues.put("DocType", AttributeValue.builder().s(DynamoDBConstants.DOC_SYSTEMMAIL).build());
            itemValues.put("SystemMetaMailAttrib", AttributeValue.builder().s(infoJson).build());
            itemValues.put("RestoredDateTime", AttributeValue.builder().s(DynamoDBConstants.MIN_DATE).build());
            itemValues.put("UpdatedDateTime", AttributeValue.builder().s(CommonUtils.convertUTCDate(LocalDateTime.now())).build());

            PutItemRequest putRequest = PutItemRequest.builder()
                    .tableName(metaTable)
                    .item(itemValues)
                    .build();

            dynamoDbClient.putItem(putRequest);

            return itemValues.toString();
        } catch (Exception e) {
            log.error("insertSystemMail: {}", e.getMessage());
            throw new RestApiException(CommonCode.ERROR.getHttpStatus(), ErrorCode.DYNAMODB_CONNECTION_ERROR.getMessage());
        }
    }

    public String deleteSystemMail(String id) {
        Map<String, AttributeValue> itemAttributes = new HashMap<>();
        itemAttributes.put("PK", AttributeValue.builder().s(DynamoDBConstants.PK_KEY_SYSTEM_MAIL).build());
        itemAttributes.put("SK", AttributeValue.builder().s(id).build());
        try {
            Map<String, AttributeValue> item = getItem(DynamoDBConstants.PK_KEY_SYSTEM_MAIL, id);

            DeleteItemRequest request = DeleteItemRequest.builder()
                    .tableName(metaTable)
                    .key(itemAttributes)
                    .build();

            DeleteItemResponse response = dynamoDbClient.deleteItem(request);

            if(response.sdkHttpResponse().isSuccessful())
                return item.toString();

            return "";
        }catch (ConditionalCheckFailedException e) {
            log.error("deleteSystemMail Conditional check failed: {}", e.getMessage());
            throw new RestApiException(CommonCode.ERROR.getHttpStatus(), ErrorCode.DYNAMODB_CONNECTION_ERROR.getMessage());
        }catch(Exception e){
            log.error("deleteSystemMail: {}", e.getMessage());
            throw new RestApiException(CommonCode.ERROR.getHttpStatus(), ErrorCode.DYNAMODB_CONNECTION_ERROR.getMessage());
        }
    }

    public String updateSystemMail(String id, ArrayNode titleList, ArrayNode textList, LocalDateTime start_dt, LocalDateTime end_dt, ArrayNode itemList) {
        try{

            Map<String, AttributeValue> item = getItem(DynamoDBConstants.PK_KEY_SYSTEM_MAIL, id);

            String InfoJson = item.get("SystemMetaMailAttrib").s();

            ObjectMapper objectMapper = new ObjectMapper();
            JsonNode infoNode = objectMapper.readTree(InfoJson);

            ((ObjectNode) infoNode).set("title", titleList);
            ((ObjectNode) infoNode).set("text", textList);
            ((ObjectNode) infoNode).put("start_time", CommonUtils.convertUTCDate(start_dt));
            ((ObjectNode) infoNode).put("end_time", CommonUtils.convertUTCDate(end_dt));
            ((ObjectNode) infoNode).set("item_list", itemList);

            String updatedInfoJson = infoNode.toString();

            Map<String, AttributeValue> expressionAttributeValues = new HashMap<>();
            expressionAttributeValues.put(":newAttrib", AttributeValue.builder().s(updatedInfoJson).build());

            String updateExpression = "SET SystemMetaMailAttrib = :newAttrib";

            UpdateItemRequest updateRequest = UpdateItemRequest.builder()
                    .tableName(metaTable)
                    .key(Map.of(
                            "PK", AttributeValue.builder().s(DynamoDBConstants.PK_KEY_SYSTEM_MAIL).build(),
                            "SK", AttributeValue.builder().s(id).build()))
                    .updateExpression(updateExpression)
                    .expressionAttributeValues(expressionAttributeValues)
                    .returnValues(ReturnValue.ALL_NEW) // 업데이트 후의 값을 반환하려면 지정
                    .build();


            dynamoDbClient.updateItem(updateRequest);

            JSONObject jsonObject = new JSONObject();
            jsonObject.put("data(before)", InfoJson);
            jsonObject.put("data(after)", updatedInfoJson);
            return jsonObject.toString();
        }catch(Exception e){
            log.error("updateSystemMail: {}", e.getMessage());
            throw new RestApiException(CommonCode.ERROR.getHttpStatus(), ErrorCode.DYNAMODB_CONNECTION_ERROR.getMessage() );
        }
    }

    // 친구 목록
    public List<UsersResponse.Friend> getFriendList(String guid){
        List<UsersResponse.Friend> resList = new ArrayList<>();

        String key = "PK = :pkValue";
        Map<String, AttributeValue> values = Map.of(":pkValue", AttributeValue.builder().s("friend#"+guid).build());

        AtomicInteger idx = new AtomicInteger(1);

        try {
            excuteItems(executeQuery(key, values), "FriendAttrib")
                    .forEach(attrMap -> {
                        UsersResponse.Friend friend = new UsersResponse.Friend();
                        friend.setRowNum(idx.getAndIncrement());
                        String friend_guid = CommonUtils.objectToString(attrMap.get("friend_guid"));
                        friend.setFriendGuid(friend_guid);
                        friend.setFriendName(getGuidByName(friend_guid));
                        friend.setReceiveDt(CommonUtils.objectToString(attrMap.get("create_time")));
                        friend.setLanguage(LANGUAGETYPE.values()[Integer.parseInt(getUserLanguage(friend_guid))].toString());
                        resList.add(friend);
                    });
            log.info("getFriendList FriendInfo: {}", resList);
        }catch (Exception e){
            log.error("getFriendList: {}", e.getMessage());
            throw new RestApiException(CommonCode.ERROR.getHttpStatus(), ErrorCode.DYNAMODB_CONNECTION_ERROR.getMessage());
        }
        return resList;
    }

    // 유저 차단 목록
    public List<UsersResponse.Friend> getUserBlockList(String guid){
        List<UsersResponse.Friend> resList = new ArrayList<>();

        String key = "PK = :pkValue";
        Map<String, AttributeValue> values = Map.of(":pkValue", AttributeValue.builder().s("block#"+guid).build());

        AtomicInteger idx = new AtomicInteger(1);

        try {
            QueryResponse response = executeQuery(key, values);

            // 응답에서 원하는 속성을 가져옵니다.
            for (Map<String, AttributeValue> item : response.items()) {
                AttributeValue attrValue = item.get("BlockUserAttrib");
                if (attrValue != null) {
                    String attrJson = attrValue.s();

                    ObjectMapper objectMapper = new ObjectMapper();
                    Map<String, Object> attrMap = objectMapper.readValue(attrJson, new TypeReference<Map<String, Object>>() {
                    });

                    UsersResponse.Friend friend = new UsersResponse.Friend();
                    friend.setRowNum(idx.getAndIncrement());
                    String block_guid = CommonUtils.objectToString(attrMap.get("guid"));
                    friend.setFriendGuid(block_guid);
                    friend.setFriendName(getGuidByName(block_guid));
                    friend.setReceiveDt(CommonUtils.objectToString(item.get("CreatedDateTime").s()));
                    friend.setLanguage(LANGUAGETYPE.values()[Integer.parseInt(getUserLanguage(block_guid))].toString());

                    resList.add(friend);
                }
            }
            log.info("getUserBlockList FriendInfo: {}", resList);
        }catch (Exception e){
            log.error("getUserBlockList: {}", e.getMessage());
            throw new RestApiException(CommonCode.ERROR.getHttpStatus(), ErrorCode.DYNAMODB_CONNECTION_ERROR.getMessage());
        }
        return resList;
    }

    //마이홈
    public UsersResponse.Myhome getMyhome(String guid){
        UsersResponse.Myhome myhome = new UsersResponse.Myhome();
        List<UsersResponse.Item> itemList = new ArrayList<>();

        String key = "PK = :pkValue";
        Map<String, AttributeValue> values = Map.of(":pkValue", AttributeValue.builder().s("my_home#" + guid).build());
        try {
            excuteItems(executeQuery(key, values), "MyHomeAttrib")
                    .forEach(attrMap -> {
                        String myhome_guid = CommonUtils.objectToString(attrMap.get("myhome_guid"));
                        myhome.setMyhomeGuid(myhome_guid);
                        myhome.setMyhomeName(CommonUtils.objectToString(attrMap.get("myhome_name")));
                        String second_key = "PK = :pkValue";
                        Map<String, AttributeValue> second_values = Map.of(":pkValue", AttributeValue.builder().s("item#"+myhome_guid).build());
                        excuteItems(executeQuery(second_key, second_values), "ItemAttrib").forEach(attrMap2 -> {
                            String item_id = CommonUtils.objectToString(attrMap2.get("item_meta_id"));
                            String item_name = metaDataHandler.getMetaItemNameData(Integer.parseInt(item_id));
                            UsersResponse.Item item = UsersResponse.Item.builder()
                                    .itemId(item_id)
                                    .itemName(metaDataHandler.getTextStringData(item_name))
                                    .count(CommonUtils.objectToDouble(attrMap2.get("item_stack_count")))
                                    .itemGuid(CommonUtils.objectToString(attrMap2.get("item_guid")))
                                    .build();
                            itemList.add(item);
                        });
                        myhome.setPropList(itemList);
                    });
            log.info("getMyhome myhomedInfo: {}", myhome);
        }catch (Exception e){
            log.error("getMyhome: {}", e.getMessage());
            throw new RestApiException(CommonCode.ERROR.getHttpStatus(), ErrorCode.DYNAMODB_CONNECTION_ERROR.getMessage());
        }
        return myhome;
    }

    // 칼리움 수량
    public float getCaliumTotal(){
        try {
            float total = 0;
            Map<String, AttributeValue> response = getItem(DynamoDBConstants.PK_KEY_CALIUM, "empty");

            AttributeValue attributeValue = response.get(DynamoDBConstants.ATTRIB_CALIUM);

            if (attributeValue != null) {
                Map<String, AttributeValue> attrib = attributeValue.m();
                Map<String, AttributeValue> storageMap = attrib.get("calium_operator_storage").m();

                total = Float.parseFloat(storageMap.get("operator_total_calium").n());
            }
            log.info("getCaliumTotal calium total: {}", total);
            return total;
        }catch (Exception e){
            log.error("getCaliumTotal: {}", e.getMessage());
            throw new RestApiException(CommonCode.ERROR.getHttpStatus(), ErrorCode.DYNAMODB_CONNECTION_ERROR.getMessage());
        }
    }

    public String updateCaliumTotal(float caliumCnt) {
        try{
            Map<String, AttributeValue> item = getItem(DynamoDBConstants.PK_KEY_CALIUM, "empty");

            String InfoJson = item.get(DynamoDBConstants.ATTRIB_CALIUM).m().toString();

            float currentTotal = Float.parseFloat(item.get(DynamoDBConstants.ATTRIB_CALIUM).m().get("calium_operator_storage").m().get("operator_total_calium").n());
            float sumTotal = currentTotal + caliumCnt;
            log.info("updateCaliumTotal currentTotal: {}, newCaliumCnt: {}", currentTotal, caliumCnt);

            DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSSSSS");
            String nowDateTime = LocalDateTime.now().format(formatter);

            try {
                String updateExpression = "SET " + DynamoDBConstants.ATTRIB_CALIUM + ".calium_operator_storage.operator_total_calium = :newCalium, "
                        + DynamoDBConstants.ATTRIB_CALIUM  + ".calium_operator_storage.operator_calium_fill_up_date = :newDate, "
                        + "UpdatedDateTime = :newDate";
                log.info("updateCaliumTotal update Query: {}", updateExpression);

                Map<String, AttributeValue> expressionAttributeValues = new HashMap<>();
                expressionAttributeValues.put(":newCalium",
                        AttributeValue.builder().n(String.valueOf(sumTotal)).build());
                expressionAttributeValues.put(":newDate",
                        AttributeValue.builder().s(nowDateTime).build());

                UpdateItemRequest updateRequest = UpdateItemRequest.builder()
                        .tableName(metaTable)
                        .key(Map.of(
                                "PK", AttributeValue.builder().s(DynamoDBConstants.PK_KEY_CALIUM).build(),
                                "SK", AttributeValue.builder().s("empty").build()))
                        .updateExpression(updateExpression)
                        .expressionAttributeValues(expressionAttributeValues)
                        .returnValues(ReturnValue.ALL_NEW) // 업데이트 후의 값을 반환하려면 지정
                        .build();

                UpdateItemResponse updateResponse = dynamoDbClient.updateItem(updateRequest);

                JSONObject jsonObject = new JSONObject();
                jsonObject.put("data(before)", InfoJson);
                jsonObject.put("data(after)", updateResponse.attributes().get(DynamoDBConstants.ATTRIB_CALIUM).m().toString());
                return jsonObject.toString();
            }catch(Exception e){
                log.error("updateCaliumTotal Error occurred during update. Rolling back to original value: {}", e.getMessage());

                String updateExpression = "SET " + DynamoDBConstants.ATTRIB_CALIUM + ".calium_operator_storage.operator_total_calium = :oldAttrib";

                Map<String, AttributeValue> expressionAttributeValues = new HashMap<>();
                expressionAttributeValues.put(":oldAttrib",
                        AttributeValue.builder().n(String.valueOf(currentTotal)).build()); // 여기서 20은 새로운 값입니다

                UpdateItemRequest updateRequest = UpdateItemRequest.builder()
                        .tableName(metaTable)
                        .key(Map.of(
                                "PK", AttributeValue.builder().s(DynamoDBConstants.PK_KEY_CALIUM).build(),
                                "SK", AttributeValue.builder().s("empty").build()))
                        .updateExpression(updateExpression)
                        .expressionAttributeValues(expressionAttributeValues)
                        .returnValues(ReturnValue.ALL_NEW) // 업데이트 후의 값을 반환하려면 지정
                        .build();

                try{
                    UpdateItemResponse updateResponse = dynamoDbClient.updateItem(updateRequest);
                }catch(Exception rollbackError){
                    log.error("updateCaliumTotal Failed to rollback: {}", rollbackError.getMessage());
                    throw rollbackError;
                }
                throw e;
            }
        }catch(Exception e){
            log.error("updateCaliumTotal: {}", e.getMessage());
            throw new RestApiException(CommonCode.ERROR.getHttpStatus(), ErrorCode.DYNAMODB_CONNECTION_ERROR.getMessage() );
        }
    }

//    public String insertLandAuction(LandRequest landRequest) {
//        try {
//            LocalDateTime nowDate = LocalDateTime.now();
//
//            // LandAuctionRegistryAttrib 객체 생성
//            LandAuctionRegistryAttrib attrib = new LandAuctionRegistryAttrib();
//            attrib.setLandMetaId(landRequest.getLandId());
//            attrib.setAuctionNumber(landRequest.getAuctionSeq());
//            attrib.setAuctionReservationNoticeStartTime(CommonUtils.convertUTCDate(landRequest.getResvStartDt()));
//            attrib.setBidCurrencyType(landRequest.getCurrencyType());
//            attrib.setAuctionStartTime(CommonUtils.convertUTCDate(landRequest.getAuctionStartDt()));
//            attrib.setAuctionEndTime(CommonUtils.convertUTCDate(landRequest.getAuctionEndDt()));
//            attrib.setBidStartPrice(landRequest.getStartPrice());
//            attrib.setIsCancelAuction(CommonConstants.FALSE);
//            attrib.setAuctionState(CommonConstants.NONE);
//            attrib.setAuctionResult(CommonConstants.NONE);
//            attrib.setRegisteredVersionTime(CommonUtils.convertUTCDate(nowDate));
//            attrib.setProcessVersionTime(DynamoDBConstants.MIN_DATE);
//
//            // LandAuctionRegistry 객체 생성
//            LandAuctionRegistryDoc registry = new LandAuctionRegistryDoc();
//            registry.setPK(DynamoDBConstants.PK_KEY_LANDAUCTION);
//            registry.setSK(String.format("%s#%s", landRequest.getLandId(), landRequest.getAuctionSeq()));
//            registry.setDocType(DynamoDBConstants.DOC_LANDAUCTION);
//            registry.setAttribValue(attrib);
//            registry.setCreatedDateTime(CommonUtils.convertUTCDate(nowDate));
//            registry.setUpdatedDateTime(CommonUtils.convertUTCDate(nowDate));
//            registry.setDeletedDateTime(DynamoDBConstants.MIN_DATE);
//            registry.setRestoredDateTime(DynamoDBConstants.MIN_DATE);
//
//            TableSchema<LandAuctionRegistryDoc> schema = TableSchema.fromBean(LandAuctionRegistryDoc.class);
//
//            DynamoDbTable<LandAuctionRegistryDoc> table = enhancedClient.table(metaTable, schema);
//
//            table.putItem(registry);
//
//            return registry.toString();
//
//        } catch (DynamoDbException e) {
//            log.error("insertLandAuction Failed to insert new item: {}", e.getMessage());
//            throw new RestApiException(CommonCode.ERROR.getHttpStatus(),
//                    ErrorCode.DYNAMODB_INSERT_ERROR.getMessage());
//        } catch (Exception e) {
//            log.error("insertLandAuction Error: {}", e.getMessage());
//            throw new RestApiException(CommonCode.ERROR.getHttpStatus(),
//                    ErrorCode.DYNAMODB_CONNECTION_ERROR.getMessage());
//        }
//    }

    @DynamoDBTransaction
    public JSONObject insertLandAuctionRegistryWithActivity(LandRequest landRequest) {
        String registry_result = insertLandAuction(landRequest);
        String activity_result = upsertLandAuctionActive(landRequest);

        JSONObject jsonObject = new JSONObject();
        jsonObject.put("land_auction_registry_result", registry_result);
        jsonObject.put("land_auction_active_result", activity_result);
        return jsonObject;
    }

    public String insertLandAuction(LandRequest landRequest) {
        LocalDateTime nowDate = LocalDateTime.now();

        // LandAuctionRegistryAttrib 객체 생성
        LandAuctionRegistryAttrib attrib = new LandAuctionRegistryAttrib();
        attrib.setLandMetaId(landRequest.getLandId());
        attrib.setAuctionNumber(landRequest.getAuctionSeq());
        attrib.setAuctionReservationNoticeStartTime(CommonUtils.convertUTCDate(landRequest.getResvStartDt()));
        attrib.setBidCurrencyType(landRequest.getCurrencyType());
        attrib.setAuctionStartTime(CommonUtils.convertUTCDate(landRequest.getAuctionStartDt()));
        attrib.setAuctionEndTime(CommonUtils.convertUTCDate(landRequest.getAuctionEndDt()));
        attrib.setBidStartPrice(landRequest.getStartPrice());
        attrib.setIsCancelAuction(CommonConstants.FALSE);
        attrib.setAuctionState(CommonConstants.NONE);
        attrib.setAuctionResult(CommonConstants.NONE);
        attrib.setRegisteredVersionTime(CommonUtils.convertUTCDate(nowDate));
        attrib.setProcessVersionTime(DynamoDBConstants.MIN_DATE);

        // LandAuctionRegistry 객체 생성
        LandAuctionRegistryDoc registry = new LandAuctionRegistryDoc();
        registry.setPK(DynamoDBConstants.PK_KEY_LAND_AUCTION);
        registry.setSK(String.format("%s#%s", landRequest.getLandId(), landRequest.getAuctionSeq()));
        registry.setDocType(DynamoDBConstants.DOC_LANDAUCTION);
        registry.setAttribValue(attrib);
        registry.setCreatedDateTime(CommonUtils.convertUTCDate(nowDate));
        registry.setUpdatedDateTime(CommonUtils.convertUTCDate(nowDate));
        registry.setDeletedDateTime(DynamoDBConstants.MIN_DATE);
        registry.setRestoredDateTime(DynamoDBConstants.MIN_DATE);

        DynamoDBOperations.addPutItem(registry, LandAuctionRegistryDoc.class);

        return registry.toString();
    }

    public String updateLandAuction(LandRequest landRequest) {
        try {
            TableSchema<LandAuctionRegistryDoc> schema = TableSchema.fromBean(LandAuctionRegistryDoc.class);

            DynamoDbTable<LandAuctionRegistryDoc> table = enhancedClient.table(metaTable, schema);

            Key key = Key.builder()
                    .partitionValue(DynamoDBConstants.PK_KEY_LAND_AUCTION)
                    .sortValue(String.format("%s#%s", landRequest.getLandId(), landRequest.getAuctionSeq()))
                    .build();

            LandAuctionRegistryDoc existingRegistry = table.getItem(key);
            if (existingRegistry == null) {
                throw new RestApiException(CommonCode.ERROR.getHttpStatus(),
                        ErrorCode.DYNAMODB_CONNECTION_ERROR.getMessage());
            }

            LandAuctionRegistryAttrib before = existingRegistry.getAttribValue();

            // JSON을 객체로 변환하여 업데이트
            LandAuctionRegistryAttrib attrib = before;
            attrib.setAuctionReservationNoticeStartTime(CommonUtils.convertUTCDate(landRequest.getResvStartDt()));
            attrib.setAuctionStartTime(CommonUtils.convertUTCDate(landRequest.getAuctionStartDt()));
            attrib.setAuctionEndTime(CommonUtils.convertUTCDate(landRequest.getAuctionEndDt()));
            attrib.setBidStartPrice(landRequest.getStartPrice());
            attrib.setRegisteredVersionTime(CommonUtils.convertUTCDate(LocalDateTime.now()));

            // Registry 업데이트
            existingRegistry.setAttribValue(attrib);
            existingRegistry.setUpdatedDateTime(CommonUtils.convertUTCDate(LocalDateTime.now()));

            table.updateItem(existingRegistry);

            JSONObject response = new JSONObject();
            response.put("data(before)", mapper.writeValueAsString(before));
            response.put("data(after)", mapper.writeValueAsString(attrib));
            return response.toString();

        } catch (DynamoDbException e) {
            log.error("updateLandAuction Failed to update existing item: {}", e.getMessage());
            throw new RestApiException(CommonCode.ERROR.getHttpStatus(),
                    ErrorCode.DYNAMODB_UPDATE_ERROR.getMessage());
        } catch (Exception e) {
            log.error("updateLandAuction Error: {}", e.getMessage());
            throw new RestApiException(CommonCode.ERROR.getHttpStatus(),
                    ErrorCode.DYNAMODB_CONNECTION_ERROR.getMessage());
        }
    }

    public String cancelLandAuction(LandAuction auctionInfo) {
        try {
            TableSchema<LandAuctionRegistryDoc> schema = TableSchema.fromBean(LandAuctionRegistryDoc.class);

            DynamoDbTable<LandAuctionRegistryDoc> table = enhancedClient.table(metaTable, schema);

            Key key = Key.builder()
                    .partitionValue(DynamoDBConstants.PK_KEY_LAND_AUCTION)
                    .sortValue(String.format("%s#%s", auctionInfo.getLandId(), auctionInfo.getAuctionSeq()))
                    .build();

            LandAuctionRegistryDoc existingRegistry = table.getItem(key);
            if (existingRegistry == null) {
                throw new RestApiException(CommonCode.ERROR.getHttpStatus(),
                        ErrorCode.DYNAMODB_CONNECTION_ERROR.getMessage());
            }

            LandAuctionRegistryAttrib before = existingRegistry.getAttribValue();

            // JSON을 객체로 변환하여 업데이트
            LandAuctionRegistryAttrib attrib = before;
            attrib.setIsCancelAuction(CommonConstants.TRUE);
            attrib.setAuctionResult(ELandAuctionResult.CANCELED.getName());
            attrib.setRegisteredVersionTime(CommonUtils.convertUTCDate(LocalDateTime.now()));

            // Registry 업데이트
            existingRegistry.setAttribValue(attrib);
            existingRegistry.setUpdatedDateTime(CommonUtils.convertUTCDate(LocalDateTime.now()));

            table.updateItem(existingRegistry);

            JSONObject response = new JSONObject();
            response.put("data(before)", mapper.writeValueAsString(before));
            response.put("data(after)", mapper.writeValueAsString(attrib));
            return response.toString();

        } catch (DynamoDbException e) {
            log.error("cancelLandAuction Failed to update existing item: {}", e.getMessage());
            throw new RestApiException(CommonCode.ERROR.getHttpStatus(),
                    ErrorCode.DYNAMODB_UPDATE_ERROR.getMessage());
        } catch (Exception e) {
            log.error("cancelLandAuction Error: {}", e.getMessage());
            throw new RestApiException(CommonCode.ERROR.getHttpStatus(),
                    ErrorCode.DYNAMODB_CONNECTION_ERROR.getMessage());
        }
    }

    public String upsertLandAuctionActive(LandRequest landRequest){
        Key key = Key.builder()
                .partitionValue(DynamoDBConstants.PK_KEY_LAND_AUCTION_ACTIVE)
                .sortValue(landRequest.getLandId().toString())
                .build();

        LandAuctionActivityDoc item = DynamoDBOperations.getItem(key, LandAuctionActivityDoc.class);

        String resultJson;

        if (item == null) {
            resultJson = insertLandAuctionActive(landRequest);
        }else{
            resultJson = updateLandAuctionActive(landRequest, item);
        }

        return resultJson;
    }

    public String insertLandAuctionActive(LandRequest landRequest){
        LocalDateTime nowDate = LocalDateTime.now();

        LandAuctionActivityAttrib attrib = new LandAuctionActivityAttrib();
        attrib.setLandMetaId(landRequest.getLandId());
        attrib.setAuctionNumber(landRequest.getAuctionSeq());

        LandAuctionActivityDoc activityDoc = new LandAuctionActivityDoc();
        activityDoc.setPK(DynamoDBConstants.PK_KEY_LAND_AUCTION_ACTIVE);
        activityDoc.setSK(landRequest.getLandId().toString());
        activityDoc.setDocType(DynamoDBConstants.DOC_LANDAUCTION_ACTIVE);
        activityDoc.setAttribValue(attrib);
        activityDoc.setCreatedDateTime(CommonUtils.convertUTCDate(nowDate));
        activityDoc.setUpdatedDateTime(CommonUtils.convertUTCDate(nowDate));

        DynamoDBOperations.addPutItem(activityDoc, LandAuctionActivityDoc.class);

        try {
            return mapper.writeValueAsString(activityDoc.getAttribValue());
        }catch(JsonProcessingException e){
            log.error("insertLandAuctionActive JsonProcessingException: {}", e.getMessage());
            throw new RestApiException(CommonCode.ERROR.getHttpStatus(), ErrorCode.DYNAMODB_JSON_PARSE_ERROR.getMessage());
        }
    }

    public String updateLandAuctionActive(LandRequest landRequest, LandAuctionActivityDoc existingDoc){
        LandAuctionActivityAttrib attrib = existingDoc.getAttribValue();
        attrib.setAuctionNumber(landRequest.getAuctionSeq());

        existingDoc.setAttribValue(attrib);
        existingDoc.setUpdatedDateTime(CommonUtils.convertUTCDate(LocalDateTime.now()));

        DynamoDBOperations.addUpdateItem(existingDoc, LandAuctionActivityDoc.class);

        try {
            return mapper.writeValueAsString(existingDoc.getAttribValue());
        }catch(JsonProcessingException e){
            log.error("updateLandAuctionActive JsonProcessingException: {}", e.getMessage());
            throw new RestApiException(CommonCode.ERROR.getHttpStatus(), ErrorCode.DYNAMODB_JSON_PARSE_ERROR.getMessage());
        }
    }

//    public String insertLandAuctionActive(LandRequest landRequest) {
//        try {
//            TableSchema<LandAuctionActivityDoc> schema = TableSchema.fromBean(LandAuctionActivityDoc.class);
//
//            DynamoDbTable<LandAuctionActivityDoc> table = enhancedClient.table(metaTable, schema);
//            LocalDateTime nowDate = LocalDateTime.now();
//
//            Key key = Key.builder()
//                    .partitionValue(DynamoDBConstants.PK_KEY_LANDAUCTION_ACTIVE)
//                    .sortValue(landRequest.getLandId().toString())
//                    .build();
//
//            LandAuctionActivityDoc activity = table.getItem(key);
//            String resultJson;
//
//            if (activity == null) {
//                // 새로운 데이터 생성
//                LandAuctionActivityAttrib attrib = new LandAuctionActivityAttrib();
//                attrib.setLandMetaId(landRequest.getLandId());
//                attrib.setAuctionNumber(landRequest.getAuctionSeq());
//
//                activity = new LandAuctionActivityDoc();
//                activity.setPK(DynamoDBConstants.PK_KEY_LANDAUCTION_ACTIVE);
//                activity.setSK(landRequest.getLandId().toString());
//                activity.setDocType(DynamoDBConstants.DOC_LANDAUCTION_ACTIVE);
//                activity.setAttribValue(attrib);
//                activity.setCreatedDateTime(CommonUtils.convertUTCDate(nowDate));
//                activity.setUpdatedDateTime(CommonUtils.convertUTCDate(nowDate));
////                activity.setDeletedDateTime(DynamoDBConstants.MIN_DATE);
////                activity.setRestoredDateTime(DynamoDBConstants.MIN_DATE);
//
//                table.putItem(activity);
//                resultJson = mapper.writeValueAsString(attrib);
//
//            } else {
//                // 기존 데이터 업데이트
//                LandAuctionActivityAttrib attrib = activity.getAttribValue();
//                attrib.setAuctionNumber(landRequest.getAuctionSeq());
//
//                activity.setAttribValue(attrib);
//                activity.setUpdatedDateTime(CommonUtils.convertUTCDate(nowDate));
//
//                table.updateItem(activity);
//                resultJson = mapper.writeValueAsString(attrib);
//            }
//
//            return resultJson;
//
//        } catch (DynamoDbException e) {
//            log.error("insertLandAuctionActive DB operation failed: {}", e.getMessage());
//            throw new RestApiException(CommonCode.ERROR.getHttpStatus(),
//                    ErrorCode.DYNAMODB_INSERT_ERROR.getMessage());
//        } catch (Exception e) {
//            log.error("insertLandAuctionActive Fail: {}", e.getMessage());
//            throw new RestApiException(CommonCode.ERROR.getHttpStatus(),
//                    ErrorCode.DYNAMODB_CONNECTION_ERROR.getMessage());
//        }
//    }

    public LandAuctionRegistryAttrib getLandAuctionRegistry(Integer land_id, Integer auction_seq){
        try {
            DynamoDbTable<LandAuctionRegistryDoc> table = enhancedClient.table(metaTable,
                    TableSchema.fromBean(LandAuctionRegistryDoc.class));

            Key key = Key.builder()
                    .partitionValue(DynamoDBConstants.PK_KEY_LAND_AUCTION)
                    .sortValue(String.format("%s#%s", land_id, auction_seq))
                    .build();

            LandAuctionRegistryDoc registry = table.getItem(key);
            if (registry == null) {
                throw new RestApiException(CommonCode.ERROR.getHttpStatus(), ErrorCode.DYNAMODB_CONNECTION_ERROR.getMessage());
            }

            return registry.getAttribValue();
        }catch (Exception e){
            log.error("getLandAuctionRegistry: {}", e.getMessage());
            throw new RestApiException(CommonCode.ERROR.getHttpStatus(), ErrorCode.DYNAMODB_CONNECTION_ERROR.getMessage());
        }
    }

    public LandAuctionHighestBidUserAttrib getLandAuctionHighestUser(Integer land_id, Integer auction_seq){
        try {
            DynamoDbTable<LandAuctionHighestBidUserDoc> table = enhancedClient.table(metaTable,
                    TableSchema.fromBean(LandAuctionHighestBidUserDoc.class));

            Key key = Key.builder()
                    .partitionValue(DynamoDBConstants.PK_KEY_LAND_AUCTION_HIGHEST_USER)
                    .sortValue(String.format("%s#%s", land_id, auction_seq))
                    .build();

            LandAuctionHighestBidUserDoc highestBidUser = table.getItem(key);
            if (highestBidUser == null) {
                throw new RestApiException(CommonCode.ERROR.getHttpStatus(), ErrorCode.DYNAMODB_CONNECTION_ERROR.getMessage());
            }

            return highestBidUser.getAttribValue();
        }catch (Exception e){
            log.error("getLandAuctionHighestUser: {}", e.getMessage());
            throw new RestApiException(CommonCode.ERROR.getHttpStatus(), ErrorCode.DYNAMODB_CONNECTION_ERROR.getMessage());
        }
    }
}
