package com.caliverse.admin.dynamodb.repository.Impl;

import com.caliverse.admin.domain.entity.HISTORYTYPE;
import com.caliverse.admin.domain.request.LandRequest;
import com.caliverse.admin.dynamodb.domain.atrrib.BuildingAttrib;
import com.caliverse.admin.dynamodb.domain.atrrib.LandAuctionRegistryAttrib;
import com.caliverse.admin.dynamodb.domain.doc.BuildingDoc;
import com.caliverse.admin.dynamodb.domain.doc.LandAuctionRegistryDoc;
import com.caliverse.admin.dynamodb.domain.doc.OwnedBuildingDoc;
import com.caliverse.admin.dynamodb.entity.DynamodbOperationResult;
import com.caliverse.admin.dynamodb.entity.ECurrencyType;
import com.caliverse.admin.dynamodb.entity.ELandAuctionResult;
import com.caliverse.admin.dynamodb.repository.BaseDynamoDBRepository;
import com.caliverse.admin.dynamodb.repository.LandAuctionRegistryRepository;
import com.caliverse.admin.dynamodb.service.DynamoDBOperations;
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.caliverse.admin.history.service.DynamodbHistoryLogService;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import software.amazon.awssdk.enhanced.dynamodb.Key;

import java.time.LocalDateTime;
import java.util.List;

@Component
@Slf4j
public class LandAuctionRegistryRepositoryImpl extends BaseDynamoDBRepository<LandAuctionRegistryDoc> implements LandAuctionRegistryRepository {

    public LandAuctionRegistryRepositoryImpl(DynamoDBOperations operations, DynamodbHistoryLogService historyLogService, ObjectMapper objectMapper) {
        super(operations, LandAuctionRegistryDoc.class, historyLogService, objectMapper);
    }

    @Override
    public int findAuctionNumber(Integer landId) {
        List<LandAuctionRegistryDoc> docs = findByPrefix(
                DynamoDBConstants.PK_KEY_LAND_AUCTION_REGISTRY,
                landId.toString()
        );

        if (docs.isEmpty()) return 0;

        LandAuctionRegistryDoc latestDoc = docs.stream().min((doc1, doc2) -> doc2.getSK().compareTo(doc1.getSK()))
                .orElse(null);

        if(latestDoc == null) return 0;

        LandAuctionRegistryAttrib attrib = latestDoc.getAttribValue();

        return attrib.getAuctionNumber();
    }

    @Override
    public LandAuctionRegistryAttrib findRegistryAttrib(Integer landId, Integer auctionSeq) {
        Key key = Key.builder()
                .partitionValue(DynamoDBConstants.PK_KEY_LAND_AUCTION_REGISTRY)
                .sortValue(String.format("%s#%s", landId, auctionSeq))
                .build();

        LandAuctionRegistryDoc doc = findById(key);
        return doc != null ? doc.getAttribValue() : null;
    }

    @Override
    public void insertAuction(LandRequest landRequest) {
        try {
            LocalDateTime nowDate = LocalDateTime.now();

            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);

            String sk = String.format("%s#%s", landRequest.getLandId(), landRequest.getAuctionSeq());

            LandAuctionRegistryDoc registry = new LandAuctionRegistryDoc();
            registry.setPK(DynamoDBConstants.PK_KEY_LAND_AUCTION_REGISTRY);
            registry.setSK(sk);
            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);

            log.info("LandAuctionRegistryDoc Insert Success: {}", objectMapper.writeValueAsString(registry));

            dynamodbHistoryLogService.insertHistoryLog(
                    HISTORYTYPE.LAND_AUCTION_ADD,
                    HISTORYTYPE.LAND_AUCTION_ADD.name(),
                    registry
            );

            save(registry);
        }catch (Exception e){
            log.error("Insert LandAuctionRegistry Error: {}", e.getMessage());
            throw new RestApiException(CommonCode.ERROR.getHttpStatus(), ErrorCode.DYNAMODB_CONNECTION_ERROR.getMessage());
        }
    }

    @Override
    public void updateAuction(LandRequest landRequest) {
        try {
            Key key = Key.builder()
                    .partitionValue(DynamoDBConstants.PK_KEY_LAND_AUCTION_REGISTRY)
                    .sortValue(String.format("%s#%s", landRequest.getLandId(), landRequest.getAuctionSeq()))
                    .build();

            LandAuctionRegistryDoc beforeDoc = findById(key);

            if (beforeDoc != null) {
                LandAuctionRegistryDoc afterDoc = deepCopy(beforeDoc, LandAuctionRegistryDoc.class);

                LandAuctionRegistryAttrib attrib = afterDoc.getAttribValue();
                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()));

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

                update(afterDoc);

                log.info("LandAuctionRegistryDoc Update Success: {}", objectMapper.writeValueAsString(afterDoc));

                dynamodbHistoryLogService.updateHistoryLog(
                        HISTORYTYPE.LAND_AUCTION_UPDATE,
                        HISTORYTYPE.LAND_AUCTION_UPDATE.name(),
                        beforeDoc,
                        afterDoc
                );
            }
        }catch (Exception e){
            log.error("Update LandAuctionRegistry Error: {}", e.getMessage());
            throw new RestApiException(CommonCode.ERROR.getHttpStatus(), ErrorCode.DYNAMODB_CONNECTION_ERROR.getMessage());
        }
    }

    @Override
    public void cancelAuction(Integer landId, Integer auctionSeq) {
        try {
            Key key = Key.builder()
                    .partitionValue(DynamoDBConstants.PK_KEY_LAND_AUCTION_REGISTRY)
                    .sortValue(String.format("%s#%s", landId, auctionSeq))
                    .build();

            LandAuctionRegistryDoc beforeDoc = findById(key);

            if (beforeDoc != null) {
                LandAuctionRegistryDoc afterDoc = deepCopy(beforeDoc, LandAuctionRegistryDoc.class);

                LandAuctionRegistryAttrib attrib = afterDoc.getAttribValue();
                attrib.setIsCancelAuction(CommonConstants.TRUE);
                attrib.setAuctionResult(ELandAuctionResult.CANCELED.getName());
                attrib.setRegisteredVersionTime(CommonUtils.convertUTCDate(LocalDateTime.now()));

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

                update(afterDoc);

                log.info("LandAuctionRegistryDoc Update Success: {}", objectMapper.writeValueAsString(afterDoc));

                dynamodbHistoryLogService.updateHistoryLog(
                        HISTORYTYPE.LAND_AUCTION_UPDATE,
                        HISTORYTYPE.LAND_AUCTION_UPDATE.name(),
                        beforeDoc,
                        afterDoc
                );
            }
        }catch (Exception e){
            log.error("Cancel LandAuctionRegistry Error: {}", e.getMessage());
            throw new RestApiException(CommonCode.ERROR.getHttpStatus(), ErrorCode.DYNAMODB_CONNECTION_ERROR.getMessage());
        }
    }

    @Override
    public DynamodbOperationResult initLandAuctionRegistry(Integer landId, Integer auctionSeq) {
        try{
            Key key = Key.builder()
                    .partitionValue(DynamoDBConstants.PK_KEY_LAND_AUCTION_REGISTRY)
                    .sortValue(String.format("%s#%s", landId, auctionSeq))
                    .build();
            LandAuctionRegistryDoc doc = findById(key);

            if(doc != null) {
                Key detailKey = Key.builder()
                        .partitionValue(doc.getPK())
                        .sortValue(doc.getSK())
                        .build();

                delete(detailKey);

                log.info("LandAuctionRegistryDoc Delete Success: {}", objectMapper.writeValueAsString(doc));

                dynamodbHistoryLogService.deleteHistoryLog(
                        HISTORYTYPE.LAND_AUCTION_INITIALIZE,
                        HISTORYTYPE.LAND_AUCTION_INITIALIZE.name(),
                        doc
                );

                return new DynamodbOperationResult(true, "", doc);
            }
            return new DynamodbOperationResult(true, "null", doc);
        }catch (Exception e){
            log.error("Init LandAuctionRegistry Error: {}", e.getMessage());
            return new DynamodbOperationResult(false, e.getMessage(), null);
        }
    }
}
