package com.bocloud.ims.service.resource.hmc.param2db;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.bocloud.cmp.model.hmc.enums.LogicalPartitionType;
import com.bocloud.cmp.model.hmc.enums.ShareProcessorType;
import com.bocloud.cmp.model.hmc.enums.VirtualAdapterTargetType;
import com.bocloud.cmp.model.hmc.enums.VirtualFabricAdapterType;
import com.bocloud.cmp.model.hmc.enums.VirtualNetworkAdapterType;
import com.bocloud.cmp.model.hmc.enums.VirtualScsiAdapterType;
import com.bocloud.common.model.RequestContext;
import com.bocloud.ims.common.enums.HmcStatus;
import com.bocloud.ims.entity.resource.hmc.HmdPartition;
import com.bocloud.ims.entity.resource.hmc.HmdProfile;
import com.bocloud.ims.entity.resource.hmc.HmdProfileHea;
import com.bocloud.ims.entity.resource.hmc.HmdServer;
import com.bocloud.ims.entity.resource.hmc.HmdServerHea;
import com.bocloud.ims.entity.resource.hmc.HmdServerIoAdapter;
import com.bocloud.ims.entity.resource.hmc.HmdServerSharedProcessorPool;
import com.bocloud.ims.entity.resource.hmc.HmdServerVirtualNetwork;
import com.bocloud.ims.entity.resource.hmc.HmdServerVirtualSwitch;
import com.bocloud.ims.entity.resource.hmc.HmdVirtualFabricAdapter;
import com.bocloud.ims.entity.resource.hmc.HmdVirtualIoAdapter;
import com.bocloud.ims.entity.resource.hmc.HmdVirtualNetworkAdapter;
import com.bocloud.ims.entity.resource.hmc.HmdVirtualScsiAdapter;
import com.bocloud.ims.repository.resource.hmc.HmdPartitionRepository;
import com.bocloud.ims.repository.resource.hmc.HmdServerHeaRepository;
import com.bocloud.ims.repository.resource.hmc.HmdServerIoAdapterRepository;
import com.bocloud.ims.repository.resource.hmc.HmdServerRepository;
import com.bocloud.ims.repository.resource.hmc.HmdServerSharedProcessorPoolRepository;
import com.bocloud.ims.repository.resource.hmc.HmdServerVirtualNetworkRepository;
import com.bocloud.ims.repository.resource.hmc.HmdServerVirtualSwitchRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

@Service
public class HmdCreatePartitionParam2Db implements HmdParam2Db<HmdPartition> {

    @Autowired private HmdServerRepository serverRepository;
    @Autowired private HmdPartitionRepository partitionRepository;
    @Autowired private HmdServerSharedProcessorPoolRepository serverSharedProcessorPoolRepository;
    @Autowired private HmdServerIoAdapterRepository serverIoAdapterRepository;
    @Autowired private HmdServerVirtualSwitchRepository serverVirtualSwitchRepository;
    @Autowired private HmdServerVirtualNetworkRepository serverVirtualNetworkRepository;
    @Autowired private HmdServerHeaRepository serverHeaRepository;

    @Override
    public HmdPartition param2db(String param, RequestContext context) {
        HmdPartition resultPartition = new HmdPartition();
        resultPartition.setPending(true);
        HmdProfile resultProfile = new HmdProfile();
        resultProfile.setPending(true);
        resultPartition.setProfiles(Collections.singletonList(resultProfile));

        Assert.notNull(param, "参数错误");
        JSONObject paramPartition = JSON.parseObject(param);
        Assert.notNull(paramPartition, "参数错误");
        Long serverId = paramPartition.getLong("serverId");
        Assert.notNull(serverId, "缺少参数serverId");
        HmdServer server = serverRepository.getById(serverId);
        Assert.notNull(server, "未找到id为" + serverId + "的服务器或该服务器已被删除");
        String partitionName = paramPartition.getString("name");
        Assert.notNull(partitionName, "缺少参数name");
        String partitionType = paramPartition.getString("partitionType");
        Assert.notNull(partitionType, "缺少参数partitionType");
        LogicalPartitionType logicalPartitionType = LogicalPartitionType.byTypeNullable(partitionType);
        Assert.notNull(partitionType, "参数partitionType取值不正确，支持的取值：" +
            Arrays.stream(LogicalPartitionType.values()).map(LogicalPartitionType::getType).collect(Collectors.joining(","))
        );

        resultPartition.setStatus(HmcStatus.PARTITION.CREATING.getName());
        resultPartition.setServerId(serverId);
        resultPartition.setServer(server);
        resultPartition.setName(partitionName);
        resultPartition.setType(logicalPartitionType.getType());
        resultPartition.setCurrentProfileSync(paramPartition.getString("currentProfileSync"));


        JSONObject paramProfile = paramPartition.getJSONObject("hmcLparProfile");
        String profileName = paramProfile.getString("name");
        Assert.notNull(profileName, "缺少参数hmcLparProfile.name");

        resultProfile.setBootMode(paramProfile.getString("bootMode"));
        resultProfile.setMaxVirtualIoslots(paramProfile.getInteger("maxVirtualIoslots"));
        resultProfile.setAssignAllResources(paramProfile.getBoolean("assignAllResources"));
        resultProfile.setConnMonitor(paramProfile.getBoolean("connMonitor"));
        resultProfile.setAutoStart(paramProfile.getBoolean("autoStart"));
        resultProfile.setRedundantErrorPathReport(paramProfile.getBoolean("redundantErrorPathReport"));

        Boolean sharedProcessor = paramProfile.getBoolean("sharedProcessor");
        Assert.notNull(sharedProcessor, "缺少参数hmcLparProfile.sharedProcessor");
        if (sharedProcessor) {
            resultProfile.setSharedProcessor(true);
            resultProfile.setDedicatedProcessor(false);
            Long sharedProPoolId = paramProfile.getLong("sharedProPoolId");
            Assert.notNull(sharedProPoolId, "缺少参数hmcLparProfile.sharedProPoolId");
            HmdServerSharedProcessorPool processorPool = serverSharedProcessorPoolRepository.getById(sharedProPoolId);
            Assert.notNull(processorPool, "未找到id为" + sharedProPoolId + "的共享处理器池或该池已被删除");
            resultProfile.setMinProVirt(Optional.ofNullable(paramProfile.getInteger("minProVirt")).orElse(1));
            resultProfile.setDesProVirt(Optional.ofNullable(paramProfile.getInteger("desProVirt")).orElse(1));
            resultProfile.setMaxProVirt(Optional.ofNullable(paramProfile.getInteger("maxProVirt")).orElse(1));
            resultProfile.setMinProUnits(Optional.ofNullable(paramProfile.getDouble("minProUnits")).orElse(0.1));
            resultProfile.setDesProUnits(Optional.ofNullable(paramProfile.getDouble("desProUnits")).orElse(0.1));
            resultProfile.setMaxProUnits(Optional.ofNullable(paramProfile.getDouble("maxProUnits")).orElse(0.1));
            String proSharingMode = paramProfile.getString("proSharingMode");
            Assert.notNull(proSharingMode, "缺少参数hmcLparProfile.proSharingMode");
            ShareProcessorType shareProcessorType = ShareProcessorType.byTypeNullable(proSharingMode);
            Assert.notNull(proSharingMode, "参数partitionType.proSharingMode取值不正确，支持的取值：" +
                Arrays.stream(ShareProcessorType.values()).map(ShareProcessorType::name).collect(Collectors.joining(","))
            );
            resultProfile.setProSharingMode(shareProcessorType.name());
            if (shareProcessorType.equals(ShareProcessorType.UNCAPPED)) {
                Integer uncappedWeight = paramProfile.getInteger("uncappedWeight");
                Assert.notNull(proSharingMode, "缺少参数hmcLparProfile.uncappedWeight");
                resultProfile.setUncappedWeight(uncappedWeight);
            }
        } else {
            resultProfile.setSharedProcessor(false);
            resultProfile.setDedicatedProcessor(true);
            Integer minPro = paramProfile.getInteger("minPro");
            Integer desPro = paramProfile.getInteger("desPro");
            Integer maxPro = paramProfile.getInteger("maxPro");
            Assert.notNull(minPro, "缺少参数hmcLparProfile.minPro");
            Assert.notNull(desPro, "缺少参数hmcLparProfile.desPro");
            Assert.notNull(maxPro, "缺少参数hmcLparProfile.maxPro");
            resultProfile.setMinPro(minPro);
            resultProfile.setDesPro(desPro);
            resultProfile.setMaxPro(maxPro);
        }

        Integer minMemory = paramProfile.getInteger("minMemory");
        Integer desMemory = paramProfile.getInteger("desMemory");
        Integer maxMemory = paramProfile.getInteger("maxMemory");
        Assert.notNull(minMemory, "缺少参数hmcLparProfile.minMemory");
        Assert.notNull(desMemory, "缺少参数hmcLparProfile.desMemory");
        Assert.notNull(maxMemory, "缺少参数hmcLparProfile.maxMemory");
        resultProfile.setMinMemory(minMemory);
        resultProfile.setDesMemory(desMemory);
        resultProfile.setMaxMemory(maxMemory);

        JSONArray paramIoAdapters = paramProfile.getJSONArray("hmcProfileIoslot");
        if (paramIoAdapters != null) {
            List<HmdVirtualIoAdapter> resultIoAdapters = new ArrayList<>();
            for (int i = 0; i < paramIoAdapters.size(); i++) {
                JSONObject paramIoAdapter = paramIoAdapters.getJSONObject(i);
                Integer adapterId = paramIoAdapter.getInteger("adapterId");
                Assert.notNull(adapterId, "缺少参数hmcLparProfile.hmcProfileIoslot[" + i + "].adapterId");
                Boolean isRequired = paramIoAdapter.getBoolean("isRequired");
                Assert.notNull(isRequired, "缺少参数hmcLparProfile.hmcProfileIoslot[" + i + "].isRequired");
                HmdServerIoAdapter serverIoAdapter = serverIoAdapterRepository.getByAdapterId(serverId, adapterId);
                Assert.notNull(serverIoAdapter, "未找到adapterId为" + adapterId + "的IO适配器或该IO适配器已被删除");
                HmdVirtualIoAdapter resultIoAdapter = new HmdVirtualIoAdapter();
                resultIoAdapter.setPending(true);
                resultIoAdapter.setTargetType(VirtualAdapterTargetType.PROFILE.name());
                resultIoAdapter.setProfile(resultProfile);
                resultIoAdapter.setIsRequired(isRequired);
                resultIoAdapter.setAdapterId(serverIoAdapter.getId());
                resultIoAdapter.setIoAdapter(serverIoAdapter);
                resultIoAdapters.add(resultIoAdapter);
            }
            resultProfile.setIoAdapters(resultIoAdapters);
        }

        JSONArray paramNetworkAdapters = paramProfile.getJSONArray("hmcProfileNetworkAdapters");
        if (paramNetworkAdapters != null) {
            List<HmdVirtualNetworkAdapter> resultNetworkAdapters = new ArrayList<>();
            for (int i = 0; i < paramNetworkAdapters.size(); i++) {
                JSONObject paramNetworkAdapter = paramNetworkAdapters.getJSONObject(i);
                Integer adapterId = paramNetworkAdapter.getInteger("adapterId");
                Assert.notNull(adapterId, "缺少参数hmcLparProfile.hmcProfileNetworkAdapters[" + i + "].adapterId");
                Boolean isRequired = paramNetworkAdapter.getBoolean("isRequired");
                Assert.notNull(isRequired, "缺少参数hmcLparProfile.hmcProfileNetworkAdapters[" + i + "].isRequired");
                Integer vlanId = paramNetworkAdapter.getInteger("virtualVlanId");
                Assert.notNull(vlanId, "缺少参数hmcLparProfile.hmcProfileNetworkAdapters[" + i + "].virtualVlanId");
                Integer switchId = paramNetworkAdapter.getInteger("virtualSwitchId");
                Assert.notNull(switchId, "缺少参数hmcLparProfile.hmcProfileNetworkAdapters[" + i + "].virtualSwitchId");
                HmdServerVirtualSwitch virtualSwitch = serverVirtualSwitchRepository.getBySwitchId(serverId, switchId);
                Assert.notNull(virtualSwitch, "未找到switchId为" + switchId + "的虚拟交换机或该虚拟交换机已被删除");
                HmdServerVirtualNetwork virtualNetwork = serverVirtualNetworkRepository.getByVlanId(serverId, switchId, vlanId);
                Integer priority = paramNetworkAdapter.getInteger("priority");
                VirtualNetworkAdapterType adapterType = Optional.ofNullable(priority).map(p -> VirtualNetworkAdapterType.TRUNK).orElse(VirtualNetworkAdapterType.CLIENT);
                Boolean isTaggedVlanSupported = paramNetworkAdapter.getBoolean("isTaggedVlanSupported");
                Assert.notNull(isTaggedVlanSupported, "缺少参数hmcLparProfile.hmcProfileNetworkAdapters[" + i + "].isTaggedVlanSupported");
                String taggedVlanIds = null;
                if (isTaggedVlanSupported) {
                    taggedVlanIds = paramNetworkAdapter.getString("taggedVlanIds");
                    Assert.notNull(isTaggedVlanSupported, "缺少参数hmcLparProfile.hmcProfileNetworkAdapters[" + i + "].taggedVlanIds");
                }

                HmdVirtualNetworkAdapter resultNetworkAdapter = new HmdVirtualNetworkAdapter();
                resultNetworkAdapter.setPending(true);
                resultNetworkAdapter.setTargetType(VirtualAdapterTargetType.PROFILE.name());
                resultNetworkAdapter.setProfile(resultProfile);
                resultNetworkAdapter.setType(adapterType.name());
                resultNetworkAdapter.setAdapterId(adapterId);
                resultNetworkAdapter.setVirtualSwitchId(virtualSwitch.getId());
                resultNetworkAdapter.setVirtualSwitch(virtualSwitch);
                if (virtualNetwork != null) {
                    resultNetworkAdapter.setVirtualNetworkId(virtualNetwork.getId());
                    resultNetworkAdapter.setVirtualNetwork(virtualNetwork);
                }
                resultNetworkAdapter.setIsRequired(isRequired);
                resultNetworkAdapter.setVlanId(vlanId);
                resultNetworkAdapter.setPriority(priority);
                resultNetworkAdapter.setIsTaggedVlanSupported(isTaggedVlanSupported);
                resultNetworkAdapter.setTaggedVlanIds(taggedVlanIds);
                resultNetworkAdapters.add(resultNetworkAdapter);
            }
            resultProfile.setNetworkAdapters(resultNetworkAdapters);
        }

        JSONArray paramScsiAdapters = paramProfile.getJSONArray("hmcProfileScsiAdapters");
        if (paramScsiAdapters != null) {
            List<HmdVirtualScsiAdapter> resultScsiAdapters = new ArrayList<>();
            for (int i = 0; i < paramScsiAdapters.size(); i++) {
                JSONObject paramScsiAdapter = paramScsiAdapters.getJSONObject(i);
                Integer adapterId = paramScsiAdapter.getInteger("adapterId");
                Assert.notNull(adapterId, "缺少参数hmcLparProfile.hmcProfileScsiAdapters[" + i + "].adapterId");
                Boolean isRequired = paramScsiAdapter.getBoolean("isRequired");
                Assert.notNull(isRequired, "缺少参数hmcLparProfile.hmcProfileScsiAdapters[" + i + "].isRequired");
                String type = paramScsiAdapter.getString("type");
                Assert.notNull(type, "缺少参数hmcLparProfile.hmcProfileScsiAdapters[" + i + "].type");
                VirtualScsiAdapterType adapterType = VirtualScsiAdapterType.byTypeNullable(type);
                Assert.notNull(adapterType, "参数hmcLparProfile.hmcProfileScsiAdapters[" + i + "].type取值不正确，支持的取值：" +
                    Arrays.stream(VirtualScsiAdapterType.values()).map(VirtualScsiAdapterType::name).collect(Collectors.joining(","))
                );
                Integer remotePartitionId = paramScsiAdapter.getInteger("remotePartitionId");
                Assert.notNull(remotePartitionId, "缺少参数hmcLparProfile.hmcProfileScsiAdapters[" + i + "].remotePartitionId");
                HmdPartition remotePartition = partitionRepository.getByPartitionId(serverId, remotePartitionId);
                Assert.notNull(remotePartition, "未找到partitonId为" + remotePartitionId + "的逻辑分区或该逻辑分区已被删除");
                Integer remoteAdapterId = paramScsiAdapter.getInteger("remoteSlotNumber");
                Assert.notNull(remoteAdapterId, "缺少参数hmcLparProfile.hmcProfileScsiAdapters[" + i + "].remoteSlotNumber");

                HmdVirtualScsiAdapter resultScsiAdapter = new HmdVirtualScsiAdapter();
                resultScsiAdapter.setPending(true);
                resultScsiAdapter.setTargetType(VirtualAdapterTargetType.PROFILE.name());
                resultScsiAdapter.setProfile(resultProfile);
                resultScsiAdapter.setType(adapterType.name());
                resultScsiAdapter.setAdapterId(adapterId);
                resultScsiAdapter.setRemotePartitionId(remotePartition.getId());
                resultScsiAdapter.setRemotePartition(remotePartition);
                resultScsiAdapter.setRemoteAdapterId(remoteAdapterId);
                resultScsiAdapter.setIsRequired(isRequired);
                resultScsiAdapters.add(resultScsiAdapter);
            }
            resultProfile.setScsiAdapters(resultScsiAdapters);
        }

        JSONArray paramFabricAdapters = paramProfile.getJSONArray("hmcProfileFibreAdapters");
        if (paramFabricAdapters != null) {
            List<HmdVirtualFabricAdapter> resultFabricAdapters = new ArrayList<>();
            for (int i = 0; i < paramFabricAdapters.size(); i++) {
                JSONObject paramFabricAdapter = paramFabricAdapters.getJSONObject(i);
                Integer adapterId = paramFabricAdapter.getInteger("adapterId");
                Assert.notNull(adapterId, "缺少参数hmcLparProfile.hmcProfileFibreAdapters[" + i + "].adapterId");
                Boolean isRequired = paramFabricAdapter.getBoolean("isRequired");
                Assert.notNull(isRequired, "缺少参数hmcLparProfile.hmcProfileFibreAdapters[" + i + "].isRequired");
                String type = paramFabricAdapter.getString("type");
                Assert.notNull(type, "缺少参数hmcLparProfile.hmcProfileFibreAdapters[" + i + "].type");
                VirtualFabricAdapterType adapterType = VirtualFabricAdapterType.byTypeNullable(type);
                Assert.notNull(adapterType, "参数hmcLparProfile.hmcProfileFibreAdapters[" + i + "].type取值不正确，支持的取值：" +
                    Arrays.stream(VirtualScsiAdapterType.values()).map(VirtualScsiAdapterType::name).collect(Collectors.joining(","))
                );
                Integer remotePartitionId = paramFabricAdapter.getInteger("connectingPartitionId");
                Assert.notNull(remotePartitionId, "缺少参数hmcLparProfile.hmcProfileFibreAdapters[" + i + "].connectingPartitionId");
                HmdPartition remotePartition = partitionRepository.getByPartitionId(serverId, remotePartitionId);
                Assert.notNull(remotePartition, "未找到partitonId为" + remotePartitionId + "的逻辑分区或该逻辑分区已被删除");
                Integer remoteAdapterId = paramFabricAdapter.getInteger("connectingPartitionId");
                Assert.notNull(remoteAdapterId, "缺少参数hmcLparProfile.hmcProfileFibreAdapters[" + i + "].connectingPartitionId");

                HmdVirtualFabricAdapter resultFabricAdapter = new HmdVirtualFabricAdapter();
                resultFabricAdapter.setPending(true);
                resultFabricAdapter.setTargetType(VirtualAdapterTargetType.PROFILE.name());
                resultFabricAdapter.setProfile(resultProfile);
                resultFabricAdapter.setType(adapterType.name());
                resultFabricAdapter.setAdapterId(adapterId);
                resultFabricAdapter.setRemotePartitionId(remotePartition.getId());
                resultFabricAdapter.setRemotePartition(remotePartition);
                resultFabricAdapter.setRemoteAdapterId(remoteAdapterId);
                resultFabricAdapter.setIsRequired(isRequired);
                resultFabricAdapters.add(resultFabricAdapter);
            }
            resultProfile.setFabricAdapters(resultFabricAdapters);
        }

        JSONArray paramHeas = paramProfile.getJSONArray("hmcProfileLheas");
        if (paramHeas != null) {
            List<HmdProfileHea> resultHeas = new ArrayList<>();
            for (int i = 0; i < paramHeas.size(); i++) {
                JSONObject paramHea = paramHeas.getJSONObject(i);
                Integer adapterId = paramHea.getInteger("adapterId");
                Assert.notNull(adapterId, "缺少参数hmcLparProfile.hmcProfileLheas[" + i + "].adapterId");
                HmdServerHea serverHea = serverHeaRepository.getByAdapterId(serverId, adapterId);
                Assert.notNull(serverHea, "未找到adapterId为" + adapterId + "的主机以太网适配器或该适配器已被删除");
                Integer logicalPortId = paramHea.getInteger("logicalPortId");
                Assert.notNull(logicalPortId, "缺少参数hmcLparProfile.hmcProfileLheas[" + i + "].logicalPortId");
                Integer physicalPortId = paramHea.getInteger("physicalPortId");
                Assert.notNull(physicalPortId, "缺少参数hmcLparProfile.hmcProfileLheas[" + i + "].physicalPortId");
                Integer portGroupId = paramHea.getInteger("portGroupId");
                Assert.notNull(portGroupId, "缺少参数hmcLparProfile.hmcProfileLheas[" + i + "].portGroupId");
                String allowVlanIds = paramHea.getString("allowVlanIds");
                String allowMacAddresses = paramHea.getString("allowMacAddresses");

                HmdProfileHea resultHea = new HmdProfileHea();
                resultHea.setPending(true);
                resultHea.setProfile(resultProfile);
                resultHea.setHeaId(serverHea.getId());
                resultHea.setHea(serverHea);
                resultHea.setPortGroupId(portGroupId);
                resultHea.setPhysicalPortId(physicalPortId);
                resultHea.setLogicalPortId(logicalPortId);
                resultHea.setAllowedVlanIds(allowVlanIds);
                resultHea.setAllowedMacAddresses(allowMacAddresses);
                resultHeas.add(resultHea);
            }
            resultProfile.setHeas(resultHeas);
        }

        partitionRepository.syncInstance(resultPartition, null, context.getTarget());

        return resultPartition;
    }
}
