package com.caliverse.admin.dynamodb.service;

import com.caliverse.admin.domain.entity.EInitDataType;
import com.caliverse.admin.domain.entity.LandAuction;
import com.caliverse.admin.domain.entity.metadata.MetaLandData;
import com.caliverse.admin.domain.request.LandRequest;
import com.caliverse.admin.dynamodb.domain.atrrib.LandAuctionRefundBidPriceAttrib;
import com.caliverse.admin.dynamodb.domain.doc.DynamoDBDocBase;
import com.caliverse.admin.dynamodb.domain.doc.LandAuctionRecordDoc;
import com.caliverse.admin.dynamodb.domain.doc.LandAuctionRefundBidPriceDoc;
import com.caliverse.admin.dynamodb.entity.DynamodbOperationResult;
import com.caliverse.admin.dynamodb.repository.*;
import com.caliverse.admin.global.common.annotation.DynamoDBTransaction;
import com.caliverse.admin.dynamodb.domain.atrrib.LandAuctionHighestBidUserAttrib;
import com.caliverse.admin.dynamodb.domain.atrrib.LandAuctionRegistryAttrib;
import com.caliverse.admin.global.common.constants.DynamoDBConstants;
import com.caliverse.admin.global.component.transaction.TransactionIdManager;
import com.caliverse.admin.history.service.DataInitializeHistoryService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import software.amazon.awssdk.enhanced.dynamodb.Key;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Service
@RequiredArgsConstructor
@Slf4j
public class DynamodbLandAuctionService {
    private final LandAuctionRegistryRepository registryRepository;
    private final LandAuctionActivityRepository activityRepository;
    private final LandAuctionHighestBidUserRepository highestBidUserRepository;
    private final LandAuctionRecordRepository landAuctionRecordRepository;
    private final LandAuctionRefundBidPriceRepository refundBidPriceRepository;

    private final DataInitializeHistoryService dataInitializeHistoryService;
    private final TransactionIdManager transactionIdManager;

    @DynamoDBTransaction
    public void insertLandAuctionRegistryWithActivity(LandRequest landRequest) {
        registryRepository.insertAuction(landRequest);
        highestBidUserRepository.insertHighestBidUser(landRequest);
//        activityRepository.upsertActivity(landRequest);   //로직변경으로 activity는 운영툴에서 안건드는걸로한다.
    }

    @DynamoDBTransaction
    public void updateLandAuction(LandRequest landRequest) {
        registryRepository.updateAuction(landRequest);
    }

    @DynamoDBTransaction
    public void cancelLandAuction(LandAuction auctionInfo) {
        registryRepository.cancelAuction(auctionInfo.getLandId(), auctionInfo.getAuctionSeq());
    }

    public LandAuctionRegistryAttrib getLandAuctionRegistry(Integer land_id, Integer auction_seq){
        return registryRepository.findRegistryAttrib(land_id, auction_seq);
    }

    public LandAuctionHighestBidUserAttrib getLandAuctionHighestUser(Integer land_id, Integer auction_seq){
        return highestBidUserRepository.findHighestBidUserAttrib(land_id, auction_seq);
    }

    public int getLandAuctionNumber(Integer landId){
//        return activityRepository.findAuctionNumber(landId);
        return registryRepository.findAuctionNumber(landId);
    }

    public int getLandAuctionRecordNumber(Integer landId){
        Key key = Key.builder()
                .partitionValue(DynamoDBConstants.PK_KEY_LAND_AUCTION_RECORD)
                .sortValue(String.valueOf(landId))
                .build();
        LandAuctionRecordDoc doc = landAuctionRecordRepository.findById(key);

        if(doc == null) return 0;

        return doc.getAttribValue().getAuctionNumber();
    }

    @DynamoDBTransaction
    public void initLandAuction(Integer landId, Integer auctionSeq, String guid){
        String tranId = transactionIdManager.getCurrentTransactionId();

        HashMap<String,String> map = new HashMap<>();
        map.put("landId", String.valueOf(landId));
        map.put("auctionSeq", String.valueOf(auctionSeq));

        try{
            List<DynamoDBDocBase> dataList = new ArrayList<>();
            DynamodbOperationResult registryResult = registryRepository.initLandAuctionRegistry(landId, auctionSeq);
            if(registryResult.isSuccess()){
                if(registryResult.getData() != null) dataList.add(registryResult.getData());
            }else{
                historySave(EInitDataType.LandAuction, tranId, false, registryResult.getMessage(), dataList, map);
                throw new RuntimeException(registryResult.getMessage());
            }

            DynamodbOperationResult activityResult = activityRepository.initLandAuctionActivity(landId, auctionSeq);
            if(activityResult.isSuccess()){
                if(activityResult.getData() != null) dataList.add(activityResult.getData());
            }else{
                historySave(EInitDataType.LandAuction, tranId, false, activityResult.getMessage(), dataList, map);
                throw new RuntimeException(activityResult.getMessage());
            }

            DynamodbOperationResult highestBidUserResult = highestBidUserRepository.initLandAuctionHighestBidUser(landId, auctionSeq);
            if(highestBidUserResult.isSuccess()){
                if(highestBidUserResult.getData() != null) dataList.add(highestBidUserResult.getData());
            }else{
                historySave(EInitDataType.LandAuction, tranId, false, highestBidUserResult.getMessage(), dataList, map);
                throw new RuntimeException(highestBidUserResult.getMessage());
            }

            DynamodbOperationResult recordResult = landAuctionRecordRepository.initLandAuctionRecord(landId);
            if(recordResult.isSuccess()){
                if(recordResult.getData() != null) dataList.add(recordResult.getData());
            }else{
                historySave(EInitDataType.LandAuction, tranId, false, recordResult.getMessage(), dataList, map);
                throw new RuntimeException(recordResult.getMessage());
            }
            if(guid != null && !guid.isEmpty()) {
                map.put("guid", guid);
                DynamodbOperationResult refundBidPriceResult = refundBidPriceRepository.initLandAuctionRefundBidPrice(guid, landId, auctionSeq);
                if (refundBidPriceResult.isSuccess()) {
                    if (refundBidPriceResult.getData() != null) dataList.add(refundBidPriceResult.getData());
                } else {
                    historySave(EInitDataType.LandAuction, tranId, false, refundBidPriceResult.getMessage(), dataList, map);
                    throw new RuntimeException(refundBidPriceResult.getMessage());
                }
            }else{
                List<LandAuctionRefundBidPriceDoc> refundList = refundBidPriceRepository.findAllScan(
                        DynamoDBConstants.PK_KEY_LAND_AUCTION_REFUND_BID_PRICE,
                        String.format("%s#%s", landId, auctionSeq)
                );
                refundList.forEach(refund -> {
                    LandAuctionRefundBidPriceAttrib attrib = refund.getAttribValue();
                    DynamodbOperationResult refundBidPriceResult = refundBidPriceRepository.initLandAuctionRefundBidPrice(attrib.getBidUserGuid(), attrib.getLandMetaId(), attrib.getAuctionNumber());
                    if (refundBidPriceResult.isSuccess()) {
                        if (refundBidPriceResult.getData() != null) dataList.add(refundBidPriceResult.getData());
                    } else {
                        historySave(EInitDataType.LandAuction, tranId, false, refundBidPriceResult.getMessage(), dataList, map);
                        throw new RuntimeException(refundBidPriceResult.getMessage());
                    }
                });
            }

            historySave(EInitDataType.LandAuction, tranId, true, "", dataList, map);

        }catch (Exception e){
            historySave(EInitDataType.LandAuction, tranId, false, e.getMessage(), null, map);
            throw new RuntimeException(e.getMessage());
        }
    }

    private void historySave(EInitDataType dataType, String tranId, boolean isSuccess, String msg, List<DynamoDBDocBase> dataList, Map map){
        if(dataList != null && !dataList.isEmpty()) {
            dataList.forEach(data -> {
                if(data != null)
                    dataInitializeHistoryService.dynamodbDataInitHistory(dataType, tranId, isSuccess, msg, data, map);
            });
        }else{
            dataInitializeHistoryService.dynamodbDataInitHistory(dataType, tranId, isSuccess, msg, null, map);
        }
    }
}
