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

import com.caliverse.admin.domain.request.RankRequest;
import com.caliverse.admin.dynamodb.domain.atrrib.RankingScheduleAttrib;
import com.caliverse.admin.dynamodb.domain.doc.RankingScheduleDoc;
import com.caliverse.admin.dynamodb.entity.DynamodbOperationResult;
import com.caliverse.admin.dynamodb.entity.EIntervalType;
import com.caliverse.admin.dynamodb.repository.BaseDynamoDBRepository;
import com.caliverse.admin.dynamodb.repository.RankingSchedulerRepository;
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.DynamoDBConstants;
import com.caliverse.admin.global.common.exception.RestApiException;
import com.caliverse.admin.global.common.utils.CommonUtils;
import com.caliverse.admin.mongodb.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.HashMap;
import java.util.Map;

import static com.caliverse.admin.global.common.utils.CommonUtils.convertUTCDate;

@Component
@Slf4j
public class RankingScheduleRepositoryImpl extends BaseDynamoDBRepository<RankingScheduleDoc> implements RankingSchedulerRepository {
    public RankingScheduleRepositoryImpl(DynamoDBOperations operations, DynamodbHistoryLogService dynamodbHistoryLogService, ObjectMapper objectMapper) {
        super(operations, RankingScheduleDoc.class, dynamodbHistoryLogService, objectMapper);
    }

    private boolean isEvent(Integer sk){
        Key key = Key.builder()
                .partitionValue(DynamoDBConstants.PK_KEY_RANKING_SCHEDULER)
                .sortValue(String.valueOf(sk))
                .build();

        RankingScheduleDoc doc = findById(key);

        return doc != null;
    }

    @Override
    public void insert(RankRequest rankRequest) {
        if(isEvent(rankRequest.getId().intValue())){
            log.error("insert EventId: {} is duplication", rankRequest.getId());
            throw new RestApiException(CommonCode.ERROR.getHttpStatus(), ErrorCode.DYNAMODB_CONNECTION_ERROR.getMessage());
        }

        LocalDateTime nowDate = LocalDateTime.now();

        try {
            RankingScheduleAttrib attrib = new RankingScheduleAttrib();
            attrib.setAttribType(DynamoDBConstants.ATTRIB_RANKING_SCHEDULER);
            attrib.setStartTime(convertUTCDate(rankRequest.getStartDt()));
            attrib.setEndTime(convertUTCDate(rankRequest.getEndDt()));
            attrib.setIntervalBaseTime(convertUTCDate(rankRequest.getBaseDt()));
            attrib.setRankingGuid(rankRequest.getGuid());
            attrib.setRankingMetaId(rankRequest.getMetaId());
            attrib.setEventActionScoreGroupId(rankRequest.getEventActionId());

            Map<EIntervalType, Integer> intervalList = new HashMap<>();
            intervalList.put(EIntervalType.Refresh, rankRequest.getRefreshInterval());
            intervalList.put(EIntervalType.Initialization, rankRequest.getInitializationInterval());
            intervalList.put(EIntervalType.Snapshot, rankRequest.getSnapshotInterval());
            attrib.setInterval(intervalList);

            RankingScheduleDoc doc = new RankingScheduleDoc();
            doc.setPK(DynamoDBConstants.PK_KEY_RANKING_SCHEDULER);
            doc.setSK(rankRequest.getGuid());
            doc.setDocType(DynamoDBConstants.DOC_RANKING_SCHEDULER);
            doc.setAttribValue(objectMapper.writeValueAsString(attrib));
            doc.setCreatedDateTime(convertUTCDate(nowDate));
            doc.setUpdatedDateTime(convertUTCDate(nowDate));
            doc.setDeletedDateTime(DynamoDBConstants.MIN_DATE);
            doc.setRestoredDateTime(DynamoDBConstants.MIN_DATE);

            save(doc);

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

    @Override
    public void update(RankRequest rankRequest) {
        LocalDateTime nowDate = LocalDateTime.now();

        try {
            Key key = Key.builder()
                    .partitionValue(DynamoDBConstants.PK_KEY_RANKING_SCHEDULER)
                    .sortValue(rankRequest.getGuid())
                    .build();

            RankingScheduleDoc beforeDoc = findById(key);

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

                RankingScheduleAttrib attrib = objectMapper.readValue(afterDoc.getAttribValue(), RankingScheduleAttrib.class);
                attrib.setStartTime(convertUTCDate(rankRequest.getStartDt()));
                attrib.setEndTime(convertUTCDate(rankRequest.getEndDt()));
                attrib.setIntervalBaseTime(convertUTCDate(rankRequest.getBaseDt()));
                attrib.setRankingGuid(rankRequest.getGuid());
                attrib.setRankingMetaId(rankRequest.getMetaId());
                attrib.setEventActionScoreGroupId(rankRequest.getEventActionId());

                Map<EIntervalType, Integer> intervalList = new HashMap<>();
                intervalList.put(EIntervalType.Refresh, rankRequest.getRefreshInterval());
                intervalList.put(EIntervalType.Initialization, rankRequest.getInitializationInterval());
                intervalList.put(EIntervalType.Snapshot, rankRequest.getSnapshotInterval());
                attrib.setInterval(intervalList);

                afterDoc.setAttribValue(objectMapper.writeValueAsString(attrib));
                afterDoc.setUpdatedDateTime(CommonUtils.convertUTCDate(nowDate));

                update(afterDoc);

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

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

    @Override
    public DynamodbOperationResult delete(String guid) {
        try{
            Key key = Key.builder()
                    .partitionValue(DynamoDBConstants.PK_KEY_RANKING_SCHEDULER)
                    .sortValue(guid)
                    .build();
            RankingScheduleDoc doc = findById(key);

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

                delete(detailKey);

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

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