package com.bocloud.ims.repository.resource.hmc;

import com.bocloud.cmp.model.hmc.enums.VirtualAdapterTargetType;
import com.bocloud.ims.entity.common.MapBuilder;
import com.bocloud.ims.entity.resource.hmc.HmdPartition;
import com.bocloud.ims.entity.resource.hmc.HmdProfile;
import com.bocloud.ims.entity.resource.hmc.HmdServer;
import com.bocloud.ims.entity.resource.hmc.HmdServerVirtualSwitch;
import com.bocloud.ims.entity.resource.hmc.HmdVirtualNetworkAdapter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Lookup;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
import org.springframework.stereotype.Repository;

import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.atomic.AtomicReference;

@Repository
public abstract class HmdVirtualNetworkAdapterRepository extends HmdGenericDao<HmdVirtualNetworkAdapter> {

    private static final Logger logger = LoggerFactory.getLogger(HmdVirtualNetworkAdapterRepository.class);

    public HmdVirtualNetworkAdapterRepository(JdbcTemplate jdbcTemplate, NamedParameterJdbcTemplate npJdbcTemplate) {
        super(jdbcTemplate, npJdbcTemplate);
    }

    @Lookup protected abstract HmdServerRepository serverRepository();
    @Lookup protected abstract HmdPartitionRepository partitionRepository();
    @Lookup protected abstract HmdProfileRepository profileRepository();
    @Lookup protected abstract HmdServerVirtualNetworkRepository serverVirtualNetworkRepository();
    @Lookup protected abstract HmdServerVirtualSwitchRepository serverVirtualSwitchRepository();

    @Override
    public void extra(HmdVirtualNetworkAdapter adapter) {
        Optional.of(adapter).map(HmdVirtualNetworkAdapter::getTargetType).map(VirtualAdapterTargetType::valueOf).ifPresent(targetType -> {
            switch (targetType) {
                case PARTITION: {
                    Optional.of(adapter).map(HmdVirtualNetworkAdapter::getTargetId).map(this.partitionRepository()::getById).ifPresent(adapter::setPartition);
                    break;
                }
                case PROFILE: {
                    Optional.of(adapter).map(HmdVirtualNetworkAdapter::getTargetId).map(this.profileRepository()::getById).ifPresent(adapter::setProfile);
                    break;
                }
                default:
                    throw new IllegalArgumentException("未知的类型：" + targetType.name());
            }
        });
        Optional.of(adapter).map(HmdVirtualNetworkAdapter::getVirtualSwitchId).map(this.serverVirtualSwitchRepository()::getById).ifPresent(adapter::setVirtualSwitch);
        Optional.of(adapter).map(HmdVirtualNetworkAdapter::getVirtualNetworkId).map(this.serverVirtualNetworkRepository()::getById).ifPresent(adapter::setVirtualNetwork);
    }

    public List<HmdVirtualNetworkAdapter> listByPartitionId(long partitionId) {
        Map<String, Object> map = MapBuilder.init()
            .put("a.target_id", partitionId)
            .put("a.type", VirtualAdapterTargetType.PARTITION.name())
            .get();
        return this.search(map);
    }

    public List<HmdVirtualNetworkAdapter> listByProfileId(long profileId) {
        Map<String, Object> map = MapBuilder.init()
            .put("a.target_id", profileId)
            .put("a.type", VirtualAdapterTargetType.PROFILE.name())
            .get();
        return this.search(map);
    }

    public HmdVirtualNetworkAdapter getByPartitionAdapterId(long partitionId, long adapterId) {
        Map<String, Object> map = MapBuilder.init()
            .put("a.target_id", partitionId)
            .put("a.type", VirtualAdapterTargetType.PARTITION.name())
            .put("a.adapter_id", adapterId)
            .get();
        return this.search(map).stream().findFirst().orElse(null);
    }

    public HmdVirtualNetworkAdapter getByProfileAdapterId(long partitionId, long adapterId) {
        Map<String, Object> map = MapBuilder.init()
            .put("a.target_id", partitionId)
            .put("a.type", VirtualAdapterTargetType.PROFILE.name())
            .put("a.adapter_id", adapterId)
            .get();
        return this.search(map).stream().findFirst().orElse(null);
    }

    public HmdVirtualNetworkAdapter getById(long id) {
        return this.search(Collections.singletonMap("a.id", id)).stream().findFirst().orElse(null);
    }

    @Override
    public void convertInstance(final HmdVirtualNetworkAdapter srcT, final HmdVirtualNetworkAdapter desT) {
        AtomicReference<HmdServer> server = new AtomicReference<>();
        Optional.of(srcT).map(HmdVirtualNetworkAdapter::getTargetType).map(VirtualAdapterTargetType::valueOf).ifPresent(targetType -> {
            switch (targetType) {
                case PARTITION: {
                    server.set(Optional.of(srcT)
                        .map(HmdVirtualNetworkAdapter::getPartition)
                        .map(HmdPartition::getServerId)
                        .map(this.serverRepository()::getById)
                        .orElse(null)
                    );
                    break;
                }
                case PROFILE: {
                    server.set(Optional.of(srcT)
                        .map(HmdVirtualNetworkAdapter::getProfile)
                        .map(HmdProfile::getPartitionId)
                        .map(this.partitionRepository()::getById)
                        .map(HmdPartition::getServerId)
                        .map(this.serverRepository()::getById)
                        .orElse(null)
                    );
                    break;
                }
                default:
                    throw new IllegalArgumentException("未知的类型：" + targetType.name());
            }
        });

        Optional<HmdServerVirtualSwitch> vSwitch = Optional.of(srcT).map(HmdVirtualNetworkAdapter::getVirtualSwitch)
            .map(HmdServerVirtualSwitch::getUuid).map(this.serverVirtualSwitchRepository()::getByUuid);
        vSwitch.map(HmdServerVirtualSwitch::getId).ifPresent(srcT::setVirtualSwitchId);
        vSwitch.ifPresent(srcT::setVirtualSwitch);

        if (!vSwitch.isPresent() && server.get() != null) {
            vSwitch = Optional.of(srcT).map(HmdVirtualNetworkAdapter::getVirtualSwitch).map(HmdServerVirtualSwitch::getSwitchId)
                .map(switchId -> this.serverVirtualSwitchRepository().getBySwitchId(server.get().getId(), switchId));
            vSwitch.map(HmdServerVirtualSwitch::getId).ifPresent(srcT::setVirtualSwitchId);
            vSwitch.ifPresent(srcT::setVirtualSwitch);
        }

        this.copy(srcT, desT);
    }
}
