package com.caliverse.admin.domain.service;

import com.caliverse.admin.domain.dao.admin.LandMapper;
import com.caliverse.admin.domain.datacomponent.MetaDataHandler;
import com.caliverse.admin.domain.entity.*;
import com.caliverse.admin.dynamodb.domain.atrrib.LandAttrib;
import com.caliverse.admin.dynamodb.domain.atrrib.LandAuctionHighestBidUserAttrib;
import com.caliverse.admin.dynamodb.domain.atrrib.LandAuctionRegistryAttrib;
import com.caliverse.admin.domain.entity.metadata.MetaBuildingData;
import com.caliverse.admin.domain.entity.metadata.MetaLandData;
import com.caliverse.admin.domain.request.LandRequest;
import com.caliverse.admin.domain.response.LandResponse;
import com.caliverse.admin.dynamodb.entity.ELandAuctionResult;
import com.caliverse.admin.dynamodb.entity.ELandAuctionState;
import com.caliverse.admin.dynamodb.service.DynamodbLandAuctionService;
import com.caliverse.admin.dynamodb.service.DynamodbLandService;
import com.caliverse.admin.dynamodb.service.DynamodbService;
import com.caliverse.admin.dynamodb.service.DynamodbUserService;
import com.caliverse.admin.global.common.code.CommonCode;
import com.caliverse.admin.global.common.code.ErrorCode;
import com.caliverse.admin.global.common.code.SuccessCode;
import com.caliverse.admin.global.common.constants.CommonConstants;
import com.caliverse.admin.global.common.constants.MysqlConstants;
import com.caliverse.admin.global.common.utils.CommonUtils;
import com.caliverse.admin.global.common.utils.DateUtils;
import com.caliverse.admin.history.service.MysqlHistoryLogService;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.json.JSONObject;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.RequestParam;

import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.atomic.AtomicBoolean;

import static com.caliverse.admin.global.common.utils.CommonUtils.convertIsoByDatetime;
import static com.caliverse.admin.global.common.utils.DateUtils.stringToDateTime;
import static com.caliverse.admin.global.common.utils.DateUtils.stringISOToLocalDateTime;

@Service
@RequiredArgsConstructor
@Slf4j
public class LandService {

//    private final DynamoDBService dynamoDBService;
    private final DynamodbLandAuctionService dynamodbLandAuctionService;
    private final DynamodbLandService dynamodbLandService;
    private final DynamodbUserService dynamodbUserService;

    private final LandMapper landMapper;
    private final MetaDataHandler metaDataHandler;
    private final HistoryService historyService;
    private final ObjectMapper objectMapper;
    private final MysqlHistoryLogService mysqlHistoryLogService;
    private final DynamodbService dynamodbService;

    public LandResponse getLandInfo(@RequestParam Map<String, String> requestParam){
        String searchType = requestParam.getOrDefault("land_type", "ID");
        String searchData = requestParam.getOrDefault("land_data", "");
        String landSize = requestParam.getOrDefault("land_size", "ALL");
        String category = requestParam.getOrDefault("category", "ALL");
        String status = requestParam.getOrDefault("status", "ALL");
        String startDt = requestParam.getOrDefault("start_dt", "");
        String endDt = requestParam.getOrDefault("end_dt", "");
        int page = Integer.parseInt(requestParam.getOrDefault("page_no", "1"));
        int size = Integer.parseInt(requestParam.getOrDefault("page_size", "50"));
        String orderBy = requestParam.getOrDefault("orderby", "DESC");

        List<MetaLandData> landData = metaDataHandler.getMetaLandListData();
        List<MetaBuildingData> buildingData = metaDataHandler.getMetaBuildingListData();
        List<LandAuction> auctions = landMapper.getLandAuctionList(new HashMap());

        List<LandInfo> list = landData.stream()
                //필터 전처리(map 처리속도를 최대한 빠르게하기 위해서 먼저 필터 처리할수 있는건 한다)
                .filter(info -> {
                    boolean result = true;

                    if (!searchData.isEmpty()) {
                        if (searchType.equals("ID")) {
                            String landIdStr = String.valueOf(info.getLandId());
                            result = landIdStr.contains(searchData);
                        } else if (searchType.equals("NAME")) {
                            String landName = metaDataHandler.getTextStringData(info.getLandName());
                            result = landName.contains(searchData);
                        }
                    }

                    if (!landSize.equals("ALL")) {
                        result = info.getLandSize().contains(landSize);
                    }

                    return result;
                })
                .map(data -> buildLandInfo(data, buildingData, auctions)).filter(Objects::nonNull)
                .filter(info -> {
                    boolean result = true;

                    if (!status.equals("ALL")) {
                        result = info.getStatus().contains(status);
                    }

                    if (!category.equals("ALL")) {
                        result = info.getCategory().contains(category);
                    }

                    String createDate = info.getOwnerUserCreateDate();
                    if (!startDt.isEmpty() && !endDt.isEmpty()) {
                        if (createDate.isEmpty()) {
                            result = false;
                        } else {
                            LocalDateTime start_dt = stringISOToLocalDateTime(startDt);
                            LocalDateTime end_dt = stringISOToLocalDateTime(endDt);
                            LocalDateTime date = DateUtils.stringToLocalDateTime(createDate);
                            result = (date.isEqual(start_dt) || date.isAfter(start_dt)) &&
                                    (date.isEqual(end_dt) || date.isBefore(end_dt));
                        }
                    }

                    return result;
                })
                .sorted(orderBy.equals("ASC") ?
                        Comparator.comparing(LandInfo::getLandId).reversed() :
                        Comparator.comparing(LandInfo::getLandId))
                .toList();

        // 페이징 처리
        int totalItems = list.size();
        int totalPages = (int) Math.ceil((double) totalItems / size);
        page = (totalItems > 0 && page > totalPages) ? totalPages : page;

        List<LandInfo> pagedList = (totalItems == 0) ?
                new ArrayList<>() :
                list.subList((page - 1) * size, Math.min((page - 1) * size + size, totalItems));

        return LandResponse.builder()
                .resultData(LandResponse.ResultData.builder()
                        .landInfoList(pagedList)
                        .total(pagedList.size())
                        .totalAll(totalItems)
                        .pageNo(requestParam.get("page_no") != null ?
                                Integer.parseInt(requestParam.get("page_no")) : 1)
                        .build())
                .status(CommonCode.SUCCESS.getHttpStatus())
                .result(CommonCode.SUCCESS.getResult())
                .build();
    }

    private LandInfo buildLandInfo(MetaLandData data, List<MetaBuildingData> buildingData, List<LandAuction> auctions){
        try {
            int landId = data.getLandId();
            String editor = data.getEditor();
            boolean nonAction = data.isNonAuction();

            String ownerGuid = "";
            String ownerName = "";
            String ownerDate = "";
            double ownerPrice = 0;
            String category = "";
            String status = LandInfo.LAND_STATUS.NONE.toString();

            List<LandOwnerChange> ownerChanges = new ArrayList<>();

            if(editor.equals(CommonConstants.USER)){
                //경매 체크
                int auctionNumber = dynamodbLandAuctionService.getLandAuctionNumber(landId);
                if(auctionNumber > 0){
                    LandAuctionRegistryAttrib auctionRegistry = dynamodbLandAuctionService.getLandAuctionRegistry(landId, auctionNumber);
                    String auctionState = auctionRegistry.getAuctionState();
                    if (auctionState.equals(ELandAuctionState.STARTED.getName())) {
                        status = LandInfo.LAND_STATUS.AUCTION_RUNNING.toString();
                    } else if (auctionState.equals(ELandAuctionState.ENDED.getName())) {
                        String auctionResult = auctionRegistry.getAuctionResult();
                        if (auctionResult.equals(ELandAuctionResult.SUCCESSED.getName())) {
                            LandAuctionHighestBidUserAttrib bidUser = dynamodbLandAuctionService.getLandAuctionHighestUser(landId, auctionNumber);
                            status = LandInfo.LAND_STATUS.AUCTION_END.toString();
                            if (bidUser != null) {
                                ownerPrice = bidUser.getHighestBidPrice();
                            } else {
                                log.warn("LandAuction land: {}, auction_number: {} Ended Result Success bidUser null", landId, auctionNumber);
                            }
                        }
                    } else {
                        status = LandInfo.LAND_STATUS.AUCTION_WAIT.toString();
                    }
                }

                //랜드 존재
                LandAttrib land = dynamodbLandService.getLandInfo(landId);
                if(land != null){
                    ownerGuid = land.getOwnerUserGuid();
                    //소유 체크
                    if(!ownerGuid.isEmpty()){
                        String parsedDate = dynamodbLandService.getLandOwnerCreateDate(ownerGuid, landId);
                        ownerDate = parsedDate.isEmpty() ? "" : convertIsoByDatetime(parsedDate);
                        ownerName = dynamodbUserService.getGuidByName(ownerGuid);
                        if(status.equals(LandInfo.LAND_STATUS.NONE.toString())){
                            status = LandInfo.LAND_STATUS.OWNED.toString();
                        }
                    }
                }

                //변경 이력
                ownerChanges = landMapper.getLandOwnerChangeInfo(landId);
                if(!ownerChanges.isEmpty()){
                    long changesCount = ownerChanges.stream().filter(changeData -> changeData.getStatus().equals(LandOwnerChange.CHANGE_STATUS.WAIT)).count();
                    if(changesCount > 0){
                        status = LandInfo.LAND_STATUS.OWNED_WAIT.toString();
                    }
                }
            }else{
                ownerName = CommonConstants.CALIVERSE_NAME;
            }

            if(editor.equals(CommonConstants.CALIVERSE_CODE)){
                category = CommonConstants.LAND_PUBLIC;
            }else{
                if(nonAction){
                    category = CommonConstants.LAND_EVENT;
                }else{
                    category = CommonConstants.LAND_AUCTION;
                }
            }

            boolean isOwned = editor.equals(CommonConstants.USER) && nonAction && ownerGuid.isEmpty();

            MetaBuildingData buildingInfo = buildingData.stream()
                    .filter(building -> building.getBuildingId().equals(data.getBuildingId()))
                    .findFirst().get();

            return LandInfo.builder()
                    .id((long) landId)
                    .landId(landId)
                    .landName(metaDataHandler.getTextStringData(data.getLandName()))
                    .landDesc(metaDataHandler.getTextStringData(data.getLandDesc()))
                    .buildingId(data.getBuildingId())
                    .buildingName(metaDataHandler.getTextStringData(buildingInfo.getBuildingName()))
                    .nonAuction(nonAction)
                    .editor(editor)
                    .status(status)
                    .isOwned(isOwned)
                    .category(category)
                    .landSize(data.getLandSize())
                    .landType(data.getLandType())
                    .socket(buildingInfo.getInstanceSocket())
                    .ownerUserGuid(ownerGuid)
                    .ownerUserNickname(ownerName)
                    .ownerUserCreateDate(ownerDate)
                    .ownerPrice(String.valueOf(ownerPrice))
                    .ownerChanges(ownerChanges)
                    .build();
        }catch(Exception e){
            log.error("buildLandInfo", e);
        }
        return null;
    }

    // 랜드 메타데이터 정보 조회
    public LandResponse getLandList(){
        List<MetaLandData> landData = metaDataHandler.getMetaLandListData();
        List<LandResponse.Land> landList = landData.stream()
                .filter(land -> !land.isNonAuction() && land.getEditor().equals("USER"))
                .map(data -> LandResponse.Land.builder()
                        .id(data.getLandId())
                        .name(metaDataHandler.getTextStringData(data.getLandName()))
                        .desc(metaDataHandler.getTextStringData(data.getLandDesc()))
                        .owner(data.getOwner())
                        .nonAuction(data.isNonAuction())
                        .size(data.getLandSize())
                        .socket(data.getBuildingSocket())
                        .type(data.getLandType())
                        .buildingId(data.getBuildingId())
                        .build()
                )
                .sorted(Comparator.comparing(LandResponse.Land::getId))
                .toList();

        return LandResponse.builder()
                .resultData(LandResponse.ResultData.builder()
                        .landList(landList)
                        .build())
                .status(CommonCode.SUCCESS.getHttpStatus())
                .result(CommonCode.SUCCESS.getResult())
                .build();
    }
    
    // 빌딩 정보 조회
    public LandResponse getBuildingList(){
        List<MetaBuildingData> buildingData = metaDataHandler.getMetaBuildingListData();
        List<LandResponse.Building> buildingList = buildingData.stream()
                .map(data -> LandResponse.Building.builder()
                        .id(data.getBuildingId())
                        .name(metaDataHandler.getTextStringData(data.getBuildingName()))
                        .desc(metaDataHandler.getTextStringData(data.getBuildingDesc()))
                        .owner(data.getOwner())
                        .open(data.isBuildingOpen())
                        .size(data.getBuildingSize())
                        .socket(data.getInstanceSocket())
                        .build()
                ).toList();

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

    public LandResponse getLandDetail(Long id){

        LandAuction event = landMapper.getLandAuctionDetail(id);

        event.setMessageList(landMapper.getMessage(id));

        log.info("call User Email: {}, event_id: {}", CommonUtils.getAdmin().getEmail(), id);

        return LandResponse.builder()
                .status(CommonCode.SUCCESS.getHttpStatus())
                .result(CommonCode.SUCCESS.getResult())
                .resultData(LandResponse.ResultData.builder()
                        .auction(event)
                        .build())
                .build();
    }

    // 랜드 경매 조회
    public LandResponse getLandAuctionList(@RequestParam Map<String, String> requestParam){

        requestParam = CommonUtils.pageSetting(requestParam);

        List<LandAuction> list = landMapper.getLandAuctionList(requestParam);

        int allCnt = landMapper.getAllCnt(requestParam);

        return LandResponse.builder()
                .status(CommonCode.SUCCESS.getHttpStatus())
                .result(CommonCode.SUCCESS.getResult())
                .resultData(LandResponse.ResultData.builder()
                        .auctionList(list)
                        .total(landMapper.getTotal())
                        .totalAll(allCnt)
                        .pageNo(requestParam.get("page_no")!=null?
                                Integer.parseInt(requestParam.get("page_no")):1)
                        .build()
                )
                .build();
    }

    // 랜드 경매 상세조회
    public LandResponse getLandAuctionDetail(Long id){

        LandAuction landAuction = landMapper.getLandAuctionDetail(id);

        landAuction.setMessageList(landMapper.getMessage(id));

        log.info("call User Email: {}, id: {}", CommonUtils.getAdmin().getEmail(), id);

        return LandResponse.builder()
                .status(CommonCode.SUCCESS.getHttpStatus())
                .result(CommonCode.SUCCESS.getResult())
                .resultData(LandResponse.ResultData.builder()
                        .auction(landAuction)
                        .build())
                .build();
    }

    @Transactional(transactionManager = "transactionManager")
    public LandResponse postLandAuction(LandRequest landRequest){

        Integer land_id = landRequest.getLandId();
        int isLand = landMapper.getPossibleLand(land_id);
        if(isLand > 0){
            return LandResponse.builder()
                    .status(CommonCode.ERROR.getHttpStatus())
                    .result(ErrorCode.ERROR_LAND_AUCTION_IMPOSSIBLE.toString())
                    .build();
        }
        boolean isLandOwner = dynamodbLandService.isLandOwner(land_id);
        if(isLandOwner){
            return LandResponse.builder()
                    .status(CommonCode.ERROR.getHttpStatus())
                    .result(ErrorCode.ERROR_AUCTION_LAND_OWNER.toString())
                    .build();
        }

//        int nextSeq = landMapper.getMaxLandSeq(land_id) + 1;
        int next_auction_number = dynamodbLandAuctionService.getLandAuctionNumber(land_id) + 1;
        landRequest.setAuctionSeq(next_auction_number);
        landRequest.setCreateBy(CommonUtils.getAdmin().getId());

        int result = landMapper.postLandAuction(landRequest);
        log.info("AdminToolDB LandAuction Save: {}", landRequest);

        long auction_id = landRequest.getId();

        HashMap<String,String> map = new HashMap<>();
        map.put("id",String.valueOf(auction_id));

        //메시지 저장
//        if(landRequest.getMassageList()!= null && !landRequest.getMassageList().isEmpty()){
//            landRequest.getMassageList().forEach(
//                    item -> {
//                        map.put("title",item.getTitle());
//                        map.put("content",item.getContent());
//                        map.put("language",item.getLanguage());
//                        landMapper.insertMessage(map);
//                    }
//            );
//        }
//        log.info("AdminToolDB Message Save Complete");

        LandAuction auction_info = landMapper.getLandAuctionDetail(auction_id);
        auction_info.setMessageList(landMapper.getMessage(auction_id));

        mysqlHistoryLogService.insertHistoryLog(
                HISTORYTYPE.LAND_AUCTION_ADD,
                MysqlConstants.TABLE_NAME_LAND_AUCTION,
                HISTORYTYPE.LAND_AUCTION_ADD.name(),
                auction_info,
                CommonUtils.getAdmin().getEmail(),
                CommonUtils.getClientIp()
        );

        dynamodbLandAuctionService.insertLandAuctionRegistryWithActivity(landRequest);

        return LandResponse.builder()
                .status(CommonCode.SUCCESS.getHttpStatus())
                .result(CommonCode.SUCCESS.getResult())
                .resultData(LandResponse.ResultData.builder()
                        .message(SuccessCode.SAVE.getMessage())
                        .build())
                .build();
    }

    @Transactional(transactionManager = "transactionManager")
    public LandResponse postLandOwnerChanges(LandRequest landRequest){
        String guid = landRequest.getUserGuid();
        String nickname = dynamodbUserService.getGuidByName(guid);
        int landId = landRequest.getLandId();
        if(nickname.isEmpty() || !nickname.equals(landRequest.getUserName())){
            return LandResponse.builder()
                    .status(CommonCode.ERROR.getHttpStatus())
                    .result(ErrorCode.GUID_CHECK.toString())
                    .build();
        }

        int chk = landMapper.getPossibleLandOwnerChanges(landId);
        if(chk > 0){
            return LandResponse.builder()
                    .status(CommonCode.ERROR.getHttpStatus())
                    .result(ErrorCode.ERROR_LAND_OWNER_CHANGES_DUPLICATION.toString())
                    .build();
        }

        LandAttrib landInfo = dynamodbLandService.getLandInfo(landId);
        if(!landInfo.getOwnerUserGuid().isEmpty()){
            return LandResponse.builder()
                    .status(CommonCode.ERROR.getHttpStatus())
                    .result(ErrorCode.ERROR_LAND_OWNER_DUPLICATION.toString())
                    .build();
        }

        landRequest.setCreateBy(CommonUtils.getAdmin().getId());
        boolean is_reserve = landRequest.isReserve();
        if(!is_reserve){
            landRequest.setReservationDt(LocalDateTime.now());
        }

        int result = landMapper.postLandOwnerChange(landRequest);
        try {
            log.info("AdminToolDB LandOwnerChanges Save: {}", objectMapper.writeValueAsString(landRequest));
        } catch (JsonProcessingException e) {
            throw new RuntimeException(e);
        }

        long id = landRequest.getId();

        HashMap<String,Object> map = new HashMap<>();
        map.put("id",String.valueOf(id));

        LandOwnerChange info = landMapper.getLandOwnerChangeDetail(id);

        mysqlHistoryLogService.insertHistoryLog(
                HISTORYTYPE.LAND_OWNER_CHANGE_ADD,
                MysqlConstants.TABLE_NAME_LAND_OWNER_CHANGE,
                HISTORYTYPE.LAND_OWNER_CHANGE_ADD.name(),
                info,
                CommonUtils.getAdmin().getEmail(),
                CommonUtils.getClientIp()
        );

//        if(!is_reserve){
//            dynamodbLandService.ChangesLandOwner(landRequest);
//            map.put("status", LandOwnerChange.CHANGE_STATUS.FINISH);
//            updateLandOwnedChangeStatus(map);
//            dynamodbService.insertLandChangesMail(landRequest);
//        }

        return LandResponse.builder()
                .status(CommonCode.SUCCESS.getHttpStatus())
                .result(CommonCode.SUCCESS.getResult())
                .resultData(LandResponse.ResultData.builder()
                        .message(SuccessCode.SAVE.getMessage())
                        .build())
                .build();
    }

    @Transactional(transactionManager = "transactionManager")
    public LandResponse updateLandAuction(Long id, LandRequest landRequest) {
        landRequest.setId(id);
        landRequest.setUpdateBy(CommonUtils.getAdmin().getId());
        landRequest.setUpdateDt(LocalDateTime.now());

        LandAuction before_info = landMapper.getLandAuctionDetail(id);
//        before_info.setMessageList(landMapper.getMessage(id));

        if(!before_info.getStatus().equals(LandAuction.AUCTION_STATUS.WAIT) && !before_info.getStatus().equals(LandAuction.AUCTION_STATUS.RESV_START)){
            return LandResponse.builder()
                    .status(CommonCode.ERROR.getHttpStatus())
                    .result(ErrorCode.ERROR_AUCTION_STATUS_IMPOSSIBLE.toString())
                    .build();
        }

        int result = landMapper.updateLandAuction(landRequest);
        log.info("AdminToolDB LandAuction Update Complete: {}", landRequest);

        Map<String, String> map = new HashMap<>();
        map.put("id", String.valueOf(id));

        // message 테이블 데이터 삭제 처리 by mail_id
//        landMapper.deleteMessage(map);
//
//        // 메시지 업데이트
//        if (landRequest.getMassageList() != null && !landRequest.getMassageList().isEmpty()) {
//            landRequest.getMassageList().forEach(item -> {
//                map.put("title", item.getTitle());
//                map.put("content", item.getContent());
//                map.put("language", item.getLanguage());
//
//                landMapper.insertMessage(map);
//            });
//        }
//        log.info("AdminToolDB Message Update Complete");

        LandAuction after_info = landMapper.getLandAuctionDetail(id);
        after_info.setMessageList(landMapper.getMessage(id));

        mysqlHistoryLogService.updateHistoryLog(
                HISTORYTYPE.LAND_AUCTION_UPDATE,
                MysqlConstants.TABLE_NAME_LAND_AUCTION,
                HISTORYTYPE.LAND_AUCTION_UPDATE.name(),
                before_info,
                after_info,
                CommonUtils.getAdmin().getEmail(),
                CommonUtils.getClientIp()
        );

        dynamodbLandAuctionService.updateLandAuction(landRequest);


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

    @Transactional(transactionManager = "transactionManager")
    public LandResponse updateLandOwnerChanges(Long id, LandRequest landRequest) {
        landRequest.setId(id);
        landRequest.setUpdateBy(CommonUtils.getAdmin().getId());
        landRequest.setUpdateDt(LocalDateTime.now());

        Map<String, String> map = new HashMap<>();
        map.put("id", String.valueOf(id));

        LandOwnerChange before_info = landMapper.getLandOwnerChangeDetail(id);

        int result = landMapper.updateLandOwnerChange(landRequest);
        log.info("AdminToolDB LandOwnerChanges Update Complete: {}", landRequest);

        LandOwnerChange after_info = landMapper.getLandOwnerChangeDetail(id);

        mysqlHistoryLogService.updateHistoryLog(
                HISTORYTYPE.LAND_OWNER_CHANGE_UPDATE,
                MysqlConstants.TABLE_NAME_LAND_OWNER_CHANGE,
                HISTORYTYPE.LAND_OWNER_CHANGE_UPDATE.name(),
                before_info,
                after_info,
                CommonUtils.getAdmin().getEmail(),
                CommonUtils.getClientIp()
        );

        dynamodbLandService.ChangesLandOwner(landRequest);

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

    @Transactional(transactionManager = "transactionManager")
    public LandResponse deleteLandAuction(LandRequest landRequest){
        Map<String,Object> map = new HashMap<>();
        AtomicBoolean is_falil = new AtomicBoolean(false);

        landRequest.getList().forEach(
                item->{
                    Long auction_id = item.getId();
                    LandAuction auction_info = landMapper.getLandAuctionDetail(auction_id);
                    auction_info.setMessageList(landMapper.getMessage(auction_id));

                    if(!auction_info.getStatus().equals(LandAuction.AUCTION_STATUS.WAIT) && !auction_info.getStatus().equals(LandAuction.AUCTION_STATUS.RESV_START)){
                        is_falil.set(true);
                        return;
                    }

                    map.put("id", auction_id);
                    map.put("updateBy", CommonUtils.getAdmin().getId());
                    int result = landMapper.deleteLandAuction(map);
                    log.info("LandAuction Delete Complete: {}", item);

                    mysqlHistoryLogService.deleteHistoryLog(
                            HISTORYTYPE.LAND_AUCTION_DELETE,
                            MysqlConstants.TABLE_NAME_LAND_AUCTION,
                            HISTORYTYPE.LAND_AUCTION_DELETE.name(),
                            auction_info,
                            CommonUtils.getAdmin().getEmail(),
                            CommonUtils.getClientIp()
                    );

                    dynamodbLandAuctionService.cancelLandAuction(auction_info);

                    JSONObject jsonObject = new JSONObject();

                    //로그 기록
                    List<Message> message = landMapper.getMessage(item.getId());
                    if(!message.isEmpty()){
                        jsonObject.put("message",message.get(0).getTitle());
                    }
                    jsonObject.put("auction_info", auction_info);
//                    jsonObject.put("dynamoDB_result",land_auction_registry_result);
                    historyService.setLog(HISTORYTYPE.LAND_AUCTION_DELETE, jsonObject);
                }
        );

        if(is_falil.get()){
            return LandResponse.builder()
                    .status(CommonCode.ERROR.getHttpStatus())
                    .result(ErrorCode.ERROR_AUCTION_STATUS_IMPOSSIBLE.toString())
                    .build();
        }

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

    @Transactional(transactionManager = "transactionManager")
    public LandResponse deleteLandOwnerChanges(LandRequest landRequest){
        Long id = landRequest.getId();
        LandOwnerChange info = landMapper.getLandOwnerChangeDetail(id);

        //예약상태가 아니면 취소할 수 없다
        if(!info.getStatus().equals(LandOwnerChange.CHANGE_STATUS.WAIT)){
            return LandResponse.builder()
                    .status(CommonCode.ERROR.getHttpStatus())
                    .result(ErrorCode.ERROR_LAND_OWNER_CHANGES_RESERVATION.toString())
                    .build();
        }

        Map<String,Object> map = new HashMap<>();
        map.put("id", id);
        map.put("updateBy", CommonUtils.getAdmin().getId());
        int result = landMapper.deleteLandOwnerChanges(map);
        log.info("LandOwnerChanges Delete Complete: {}", landRequest);

        mysqlHistoryLogService.deleteHistoryLog(
                HISTORYTYPE.LAND_OWNER_CHANGE_DELETE,
                MysqlConstants.TABLE_NAME_LAND_OWNER_CHANGE,
                HISTORYTYPE.LAND_OWNER_CHANGE_DELETE.name(),
                info,
                CommonUtils.getAdmin().getEmail(),
                CommonUtils.getClientIp()
        );

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

    public List<LandAuction> getScheduleLandAuctionList(){
        return landMapper.getScheduleLandAuctionList();
    }

    public List<LandOwnerChange> getScheduleLandOwnerChangesList(){
        return landMapper.getScheduleLandOwnedChangeList();
    }

    public LandAuctionRegistryAttrib getLandAuctionRegistryAttrib(Integer land_id, Integer auction_seq){
        return dynamodbLandAuctionService.getLandAuctionRegistry(land_id, auction_seq);
    }

    public LandAuctionHighestBidUserAttrib getLandAuctionHighestUserAttrib(Integer land_id, Integer auction_seq){
        return dynamodbLandAuctionService.getLandAuctionHighestUser(land_id, auction_seq);
    }

    @Transactional(transactionManager = "transactionManager")
    public void updateLandAuctionStatus(Map<String,Object> map){
        try{
            landMapper.updateStatusLandAuction(map);
            log.info("updateLandAuctionStatus landAuction status changed: {}", map.get("status"));
        }catch(Exception e){
            log.error("updateLandAuction LandAuction Update Fail map: {}", map);
        }
    }

    @Transactional(transactionManager = "transactionManager")
    public void updateLandOwnedChangeStatus(Map<String,Object> map){
        try{
            landMapper.updateStatusLandOwnedChange(map);
            log.info("updateLandOwnedChangeStatus LandOwned status changed: {}", map.get("status"));
        }catch(Exception e){
            log.error("updateLandOwnedChangeStatus LandOwned Update Fail map: {}", map);
        }
    }
}
