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.doc.BuildingDoc;
import com.caliverse.admin.dynamodb.entity.ECurrencyType;
import com.caliverse.admin.dynamodb.entity.DynamodbOperationResult;
import com.caliverse.admin.dynamodb.repository.BaseDynamoDBRepository;
import com.caliverse.admin.dynamodb.repository.BuildingRepository;
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.history.service.DynamodbHistoryLogService;
import com.fasterxml.jackson.core.JsonProcessingException;
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 static com.caliverse.admin.global.common.utils.CommonUtils.convertUTCDate;

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

    @Override
    public BuildingAttrib findBuildingAttrib(Integer buildingId) {
        Key key = Key.builder()
                .partitionValue(DynamoDBConstants.PK_KEY_BUILDING + buildingId)
                .sortValue(DynamoDBConstants.EMPTY)
                .build();

        BuildingDoc doc = findById(key);
        if (doc == null) return null;
        String attribJson = doc.getAttribValue();
        try {
            return objectMapper.readValue(attribJson, BuildingAttrib.class);
        } catch (JsonProcessingException e) {
            throw new RestApiException(CommonCode.ERROR.getHttpStatus(),
                    ErrorCode.DYNAMODB_JSON_PARSE_ERROR.getMessage());
        }
    }

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

            int building_id = landRequest.getBuildingId();
            String guid = landRequest.getUserGuid();

            String pk = DynamoDBConstants.PK_KEY_BUILDING + building_id;

            BuildingAttrib attrib = new BuildingAttrib();
            attrib.setAttribType(DynamoDBConstants.ATTRIB_BUILDING);
            attrib.setBuildingName("");
            attrib.setBuildingMetaId(building_id);
            attrib.setDescription("");
            attrib.setOwnerUserGuid(guid);
            attrib.setRentalCurrencyAmount(0.0);
            attrib.setRentalCurrencyType(ECurrencyType.Calium.getValue());
            attrib.setRentalOpen(false);
            attrib.setBuildingGuid("");

            BuildingDoc doc = new BuildingDoc();
            doc.setPK(pk);
            doc.setSK(DynamoDBConstants.EMPTY);
            doc.setDocType(DynamoDBConstants.DOC_BUILDING);
            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);

            log.info("BuildingDoc Insert Success: {}", objectMapper.writeValueAsString(doc));

            dynamodbHistoryLogService.insertHistoryLog(
                    HISTORYTYPE.LAND_OWNER_CHANGE_ADD,
                    HISTORYTYPE.LAND_OWNER_CHANGE_ADD.name(),
                    doc
            );

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

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

        int buildingId_id = landRequest.getBuildingId();
        String guid = landRequest.getUserGuid();

        try {
            Key key = Key.builder()
                    .partitionValue(DynamoDBConstants.PK_KEY_BUILDING + buildingId_id)
                    .sortValue(DynamoDBConstants.EMPTY)
                    .build();

            BuildingDoc beforeDoc = findById(key);

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

                BuildingAttrib attrib = objectMapper.readValue(afterDoc.getAttribValue(), BuildingAttrib.class);
                attrib.setDescription("");
                attrib.setOwnerUserGuid(guid);

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

                update(afterDoc);

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

                dynamodbHistoryLogService.updateHistoryLog(
                        HISTORYTYPE.LAND_OWNER_CHANGE_UPDATE,
                        HISTORYTYPE.LAND_OWNER_CHANGE_UPDATE.name(),
                        beforeDoc,
                        afterDoc
                );
            }
        }catch (Exception e){
            throw new RestApiException(CommonCode.ERROR.getHttpStatus(), ErrorCode.DYNAMODB_CONNECTION_ERROR.getMessage());
        }
    }

    @Override
    public DynamodbOperationResult initBuildingOwner(int buildingId) {

        try {
            Key key = Key.builder()
                    .partitionValue(DynamoDBConstants.PK_KEY_BUILDING + buildingId)
                    .sortValue(DynamoDBConstants.EMPTY)
                    .build();

            BuildingDoc beforeDoc = findById(key);

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

                BuildingAttrib attrib = objectMapper.readValue(afterDoc.getAttribValue(), BuildingAttrib.class);
                attrib.setOwnerUserGuid("");

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

                update(afterDoc);

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

                dynamodbHistoryLogService.updateHistoryLog(
                        HISTORYTYPE.LAND_OWNED_INITIALIZE,
                        HISTORYTYPE.LAND_OWNED_INITIALIZE.name(),
                        beforeDoc,
                        afterDoc
                );
                return new DynamodbOperationResult(true, "", afterDoc);
            }
            return new DynamodbOperationResult(false, "null", null);
        }catch (Exception e){
            log.error("Init Building Owner Error: {}", e.getMessage());
            return new DynamodbOperationResult(false, e.getMessage(), null);
        }
    }

    @Override
    public DynamodbOperationResult initBuildingDesc(int buildingId) {

        try {
            Key key = Key.builder()
                    .partitionValue(DynamoDBConstants.PK_KEY_BUILDING + buildingId)
                    .sortValue(DynamoDBConstants.EMPTY)
                    .build();

            BuildingDoc beforeDoc = findById(key);

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

                BuildingAttrib attrib = objectMapper.readValue(afterDoc.getAttribValue(), BuildingAttrib.class);
                attrib.setDescription("");
                attrib.setBuildingName("");
                attrib.setRentalCurrencyAmount(0.0);
                attrib.setRentalOpen(false);
                attrib.setRentalCurrencyType(ECurrencyType.Calium.getValue());

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

                update(afterDoc);

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

                dynamodbHistoryLogService.updateHistoryLog(
                        HISTORYTYPE.LAND_DESC_INITIALIZE,
                        HISTORYTYPE.LAND_DESC_INITIALIZE.name(),
                        beforeDoc,
                        afterDoc
                );
                return new DynamodbOperationResult(true, "Success", afterDoc);
            }
            return new DynamodbOperationResult(true, "null", beforeDoc);
        }catch (Exception e){
            log.error("Init Building Desc Error: {}", e.getMessage());
            return new DynamodbOperationResult(false, e.getMessage(), null);
        }
    }
}
