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.HmdProfile;
import com.bocloud.ims.entity.resource.hmc.HmdProfileHea;
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 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;

@Repository
public abstract class HmdProfileRepository extends HmdGenericDao<HmdProfile> {

    @Lookup protected abstract HmdPartitionRepository partitionRepository();
    @Lookup protected abstract HmdServerSharedProcessorPoolRepository serverSharedProcessorPoolRepository();
    @Lookup protected abstract HmdVirtualIoAdapterRepository virtualIoAdapterRepository();
    @Lookup protected abstract HmdVirtualNetworkAdapterRepository virtualNetworkAdapterRepository();
    @Lookup protected abstract HmdVirtualScsiAdapterRepository virtualScsiAdapterRepository();
    @Lookup protected abstract HmdVirtualFabricAdapterRepository virtualFabricAdapterRepository();
    @Lookup protected abstract HmdProfileHeaRepository profileHeaRepository();

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

    @Override
    public void extra(HmdProfile profile) {
        Optional.of(profile).map(HmdProfile::getId).map(this.virtualIoAdapterRepository()::listByProfileId).ifPresent(profile::setIoAdapters);
        Optional.of(profile).map(HmdProfile::getId).map(this.virtualNetworkAdapterRepository()::listByProfileId).ifPresent(profile::setNetworkAdapters);
        Optional.of(profile).map(HmdProfile::getId).map(this.virtualScsiAdapterRepository()::listByProfileId).ifPresent(profile::setScsiAdapters);
        Optional.of(profile).map(HmdProfile::getId).map(this.virtualFabricAdapterRepository()::listByProfileId).ifPresent(profile::setFabricAdapters);
        Optional.of(profile).map(HmdProfile::getId).map(this.profileHeaRepository()::listByProfileId).ifPresent(profile::setHeas);

        Optional.of(profile).map(HmdProfile::getPartitionId).map(this.partitionRepository()::getById).ifPresent(profile::setPartition);
        Optional.of(profile).map(HmdProfile::getSharedProPoolId).map(this.serverSharedProcessorPoolRepository()::getById).ifPresent(profile::setSharedProPool);
    }

    public List<HmdProfile> listByPartitionId(long partitionId) {
        return this.search(Collections.singletonMap("a.partition_id", partitionId));
    }

    public HmdProfile getByUuid(String uuid) {
        return this.search(Collections.singletonMap("a.uuid", uuid)).stream().findFirst().orElse(null);
    }

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

    public HmdProfile getCurrActiveProfileByPartitionId(long partitionId) {
        Map<String, Object> map = MapBuilder.init()
            .put("a.partition_id", partitionId)
            .put("a.is_active_profile", 1)
            .get();
        return this.search(map).stream().findFirst().orElse(null);
    }

    public HmdProfile getDefaultProfileByPartitionId(long partitionId) {
        Map<String, Object> map = MapBuilder.init()
            .put("a.partition_id", partitionId)
            .put("a.is_default_profile", 1)
            .get();
        return this.search(map).stream().findFirst().orElse(null);
    }

    public HmdProfile getLastActiveProfileByPartitionId(long partitionId) {
        Map<String, Object> map = MapBuilder.init()
            .put("a.partition_id", partitionId)
            .put("a.is_last_activated", 1)
            .get();
        return this.search(map).stream().findFirst().orElse(null);
    }

    @Override
    public void clear(long id) {
        this.virtualIoAdapterRepository().listByProfileId(id).stream().map(HmdVirtualIoAdapter::getId).forEach(this.virtualIoAdapterRepository()::clear);
        this.virtualNetworkAdapterRepository().listByProfileId(id).stream().map(HmdVirtualNetworkAdapter::getId).forEach(this.virtualNetworkAdapterRepository()::clear);
        this.virtualScsiAdapterRepository().listByProfileId(id).stream().map(HmdVirtualScsiAdapter::getId).forEach(this.virtualScsiAdapterRepository()::clear);
        this.virtualFabricAdapterRepository().listByProfileId(id).stream().map(HmdVirtualFabricAdapter::getId).forEach(this.virtualFabricAdapterRepository()::clear);
        this.profileHeaRepository().listByProfileId(id).stream().map(HmdProfileHea::getId).forEach(this.profileHeaRepository()::clear);

        this.delete(id);
    }

    @Override
    public void startAllPending(long id) {
        this.virtualIoAdapterRepository().listByProfileId(id).stream().map(HmdVirtualIoAdapter::getId).forEach(this.virtualIoAdapterRepository()::startAllPending);
        this.virtualNetworkAdapterRepository().listByProfileId(id).stream().map(HmdVirtualNetworkAdapter::getId).forEach(this.virtualNetworkAdapterRepository()::startAllPending);
        this.virtualScsiAdapterRepository().listByProfileId(id).stream().map(HmdVirtualScsiAdapter::getId).forEach(this.virtualScsiAdapterRepository()::startAllPending);
        this.virtualFabricAdapterRepository().listByProfileId(id).stream().map(HmdVirtualFabricAdapter::getId).forEach(this.virtualFabricAdapterRepository()::startAllPending);
        this.profileHeaRepository().listByProfileId(id).stream().map(HmdProfileHea::getId).forEach(this.profileHeaRepository()::startAllPending);

        this.startPending(id);
    }

    @Override
    public void stopAllPending(long id) {
        this.virtualIoAdapterRepository().listByProfileId(id).stream().map(HmdVirtualIoAdapter::getId).forEach(this.virtualIoAdapterRepository()::stopAllPending);
        this.virtualNetworkAdapterRepository().listByProfileId(id).stream().map(HmdVirtualNetworkAdapter::getId).forEach(this.virtualNetworkAdapterRepository()::stopAllPending);
        this.virtualScsiAdapterRepository().listByProfileId(id).stream().map(HmdVirtualScsiAdapter::getId).forEach(this.virtualScsiAdapterRepository()::stopAllPending);
        this.virtualFabricAdapterRepository().listByProfileId(id).stream().map(HmdVirtualFabricAdapter::getId).forEach(this.virtualFabricAdapterRepository()::stopAllPending);
        this.profileHeaRepository().listByProfileId(id).stream().map(HmdProfileHea::getId).forEach(this.profileHeaRepository()::stopAllPending);

        this.stopPending(id);
    }

    @Override
    public void syncInstance(HmdProfile newT, HmdProfile oldT, long userId) {
        super.syncInstance(newT, oldT, userId);
        Optional.of(newT).map(HmdProfile::getIoAdapters).ifPresent(newAdapters -> {
            newAdapters.forEach(adapter -> {
                adapter.setTargetId(newT.getId());
                adapter.setTargetType(VirtualAdapterTargetType.PROFILE.name());
                adapter.setProfile(newT);
            });
            List<HmdVirtualIoAdapter> oldAdapters = this.virtualIoAdapterRepository().listByProfileId(newT.getId());
            this.virtualIoAdapterRepository().syncList(newAdapters, oldAdapters, userId);
        });
        Optional.of(newT).map(HmdProfile::getNetworkAdapters).ifPresent(newAdapters -> {
            newAdapters.forEach(adapter -> {
                adapter.setTargetId(newT.getId());
                adapter.setTargetType(VirtualAdapterTargetType.PROFILE.name());
                adapter.setProfile(newT);
            });
            List<HmdVirtualNetworkAdapter> oldAdapters = this.virtualNetworkAdapterRepository().listByProfileId(newT.getId());
            this.virtualNetworkAdapterRepository().syncList(newAdapters, oldAdapters, userId);
        });
        Optional.of(newT).map(HmdProfile::getScsiAdapters).ifPresent(newAdapters -> {
            newAdapters.forEach(adapter -> {
                adapter.setTargetId(newT.getId());
                adapter.setTargetType(VirtualAdapterTargetType.PROFILE.name());
                adapter.setProfile(newT);
            });
            List<HmdVirtualScsiAdapter> oldAdapters = this.virtualScsiAdapterRepository().listByProfileId(newT.getId());
            this.virtualScsiAdapterRepository().syncList(newAdapters, oldAdapters, userId);
        });
        Optional.of(newT).map(HmdProfile::getFabricAdapters).ifPresent(newAdapters -> {
            newAdapters.forEach(adapter -> {
                adapter.setTargetId(newT.getId());
                adapter.setTargetType(VirtualAdapterTargetType.PROFILE.name());
                adapter.setProfile(newT);
            });
            List<HmdVirtualFabricAdapter> oldAdapters = this.virtualFabricAdapterRepository().listByProfileId(newT.getId());
            this.virtualFabricAdapterRepository().syncList(newAdapters, oldAdapters, userId);
        });
        Optional.of(newT).map(HmdProfile::getHeas).ifPresent(newHeas -> {
            newHeas.forEach(hea -> {
                hea.setProfileId(newT.getId());
                hea.setProfile(newT);
            });
            List<HmdProfileHea> oldHeas = this.profileHeaRepository().listByProfileId(newT.getId());
            this.profileHeaRepository().syncList(newHeas, oldHeas, userId);
        });
    }
}
