package com.caliverse.admin.dynamodb.service;

import com.caliverse.admin.domain.entity.EInitDataType;
import com.caliverse.admin.domain.entity.metadata.MetaLandData;
import com.caliverse.admin.domain.request.LandRequest;
import com.caliverse.admin.dynamodb.domain.atrrib.BuildingAttrib;
import com.caliverse.admin.dynamodb.domain.atrrib.LandAttrib;
import com.caliverse.admin.dynamodb.domain.doc.DynamoDBDocBase;
import com.caliverse.admin.dynamodb.domain.doc.OwnedLandDoc;
import com.caliverse.admin.dynamodb.entity.DynamodbOperationResult;
import com.caliverse.admin.dynamodb.repository.BuildingRepository;
import com.caliverse.admin.dynamodb.repository.LandRepository;
import com.caliverse.admin.dynamodb.repository.OwnedBuildingRepository;
import com.caliverse.admin.dynamodb.repository.OwnedLandRepository;
import com.caliverse.admin.global.common.annotation.DynamoDBTransaction;
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 java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Service
@RequiredArgsConstructor
@Slf4j
public class DynamodbLandService {
    private final LandRepository landRepository;
    private final OwnedLandRepository ownedLandRepository;
    private final OwnedBuildingRepository ownedBuildingRepository;
    private final BuildingRepository buildingRepository;

    private final DataInitializeHistoryService dataInitializeHistoryService;
    private final TransactionIdManager transactionIdManager;

    public boolean isLandOwner(Integer landId){
        LandAttrib attrib = landRepository.findLandAttrib(landId);
        if(attrib == null) return false;

        return !attrib.getOwnerUserGuid().isEmpty() && !attrib.getOwnerUserGuid().equals(DynamoDBConstants.EMPTY);
    }

    public LandAttrib getLandInfo(Integer landId){
        return landRepository.findLandAttrib(landId);
    }

    public String getLandOwnerCreateDate(String guid, Integer landId){
        OwnedLandDoc ownedLand = ownedLandRepository.findOwnedLand(guid, landId);
        return ownedLand == null ? "" : ownedLand.getCreatedDateTime();
    }

    @DynamoDBTransaction
    public void ChangesLandOwner(LandRequest landRequest){
        int landId = landRequest.getLandId();
        int buildingId = landRequest.getBuildingId();
        String guid = landRequest.getUserGuid();

        log.info("ChangesLandOwner land: {}, building: {}, guid: {}", landId, buildingId ,guid);

        LandAttrib landAttrib = landRepository.findLandAttrib(landId);
        if(landAttrib == null){
            landRepository.insertLand(landRequest);
            ownedLandRepository.insert(guid, landId);
        }else{
            ownedLandRepository.delete(landAttrib.getOwnerUserGuid(), landId);
            landRepository.updateLand(landRequest);
            ownedLandRepository.insert(guid, landId);
        }

        BuildingAttrib buildingAttrib = buildingRepository.findBuildingAttrib(buildingId);
        if(buildingAttrib == null){
            buildingRepository.insertBuilding(landRequest);
            ownedBuildingRepository.insert(guid, buildingId);
        }else{
            ownedBuildingRepository.delete(buildingAttrib.getOwnerUserGuid(), buildingId);
            buildingRepository.updateBuilding(landRequest);
            ownedBuildingRepository.insert(guid, buildingId);
        }
    }

    @DynamoDBTransaction
    public void initLandOwner(MetaLandData land, String guid){
        String tranId = transactionIdManager.getCurrentTransactionId();
        int landId = land.getLandId();
        int buildingId = land.getBuildingId();

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

        try{
            List<DynamoDBDocBase> dataList = new ArrayList<>();
            DynamodbOperationResult landResult = landRepository.initLandOwner(landId);
            if(landResult.isSuccess()){
                if(landResult.getData() != null) dataList.add(landResult.getData());
            }else{
                historySave(EInitDataType.LandOwned, tranId, false, landResult.getMessage(), dataList, map);
                throw new RuntimeException(landResult.getMessage());
            }
            DynamodbOperationResult buildingResult = buildingRepository.initBuildingOwner(buildingId);
            if(buildingResult.isSuccess()){
                if(landResult.getData() != null) dataList.add(buildingResult.getData());
            }else{
                historySave(EInitDataType.LandOwned, tranId, false, buildingResult.getMessage(), dataList, map);
                throw new RuntimeException(buildingResult.getMessage());
            }
            DynamodbOperationResult ownedLandResult = ownedLandRepository.initOwnedLand(guid, landId);
            if(ownedLandResult.isSuccess()){
                if(landResult.getData() != null) dataList.add(ownedLandResult.getData());
            }else{
                historySave(EInitDataType.LandOwned, tranId, false, ownedLandResult.getMessage(), dataList, map);
                throw new RuntimeException(ownedLandResult.getMessage());
            }
            DynamodbOperationResult ownedBuildingResult = ownedBuildingRepository.initOwnedBuilding(guid, buildingId);
            if(ownedBuildingResult.isSuccess()){
                if(landResult.getData() != null) dataList.add(ownedBuildingResult.getData());
            }else{
                historySave(EInitDataType.LandOwned, tranId, false, ownedBuildingResult.getMessage(), dataList, map);
                throw new RuntimeException(ownedBuildingResult.getMessage());
            }

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

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

    @DynamoDBTransaction
    public void initLandDesc(MetaLandData land){
        String tranId = transactionIdManager.getCurrentTransactionId();
        int landId = land.getLandId();
        int buildingId = land.getBuildingId();

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

        try{
            List<DynamoDBDocBase> dataList = new ArrayList<>();
            DynamodbOperationResult landResult = landRepository.initLandDesc(landId);
            if(landResult.isSuccess()){
                if(landResult.getData() != null) dataList.add(landResult.getData());
            }else{
                historySave(EInitDataType.LandDesc, tranId, false, landResult.getMessage(), dataList, map);
                throw new RuntimeException(landResult.getMessage());
            }
            DynamodbOperationResult buildingResult = buildingRepository.initBuildingDesc(buildingId);
            if(buildingResult.isSuccess()){
                if(landResult.getData() != null) dataList.add(buildingResult.getData());
            }else{
                historySave(EInitDataType.LandDesc, tranId, false, buildingResult.getMessage(), dataList, map);
                throw new RuntimeException(buildingResult.getMessage());
            }

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

        }catch (Exception e){
            historySave(EInitDataType.LandDesc, 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.isEmpty()) {
            dataList.forEach(data -> {
                if (data != null)
                    dataInitializeHistoryService.dynamodbDataInitHistory(dataType, tranId, isSuccess, msg, data, map);
            });
        }else{
            dataInitializeHistoryService.dynamodbDataInitHistory(dataType, tranId, isSuccess, msg, null, map);
        }
    }
}
