package ru.yandex.qe.dispenser.domain.dao.bot.remainder;

import com.google.common.collect.ImmutableMap;
import ru.yandex.qe.dispenser.domain.Segment;
import ru.yandex.qe.dispenser.domain.Service;
import ru.yandex.qe.dispenser.domain.dao.SqlDaoBase;
import ru.yandex.qe.dispenser.domain.dao.bot.ServersRemainder;
import ru.yandex.qe.dispenser.domain.hierarchy.Hierarchy;
import ru.yandex.qe.dispenser.domain.util.CollectionUtils;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

public class SqlServersRemainderDao extends SqlDaoBase implements ServersRemainderDao {
    private static final String GET_ALL_QUERY = "SELECT * FROM servers_remainder";
    private static final String GET_BY_CAMPAIGN_GROUP_ID = GET_ALL_QUERY + " WHERE bot_campaign_group_id = :botCampaignGroupId";
    private static final String REMOVE_BY_CAMPAIGN_GROUP_ID_AND_SERVICES = "DELETE FROM servers_remainder WHERE bot_campaign_group_id = :botCampaignGroupId and service_id IN (:services)";
    private static final String CREATE_ALL_QUERY = "INSERT INTO servers_remainder(service_id, segment_id, group_key, bot_campaign_group_id, server_id, storage_id, server_count, storage_count, price, upgrade) " +
            "VALUES (:serviceId, :segmentId, :groupKey, :botCampaignGroupId, :serverId, :storageId, :serverCount, :storageCount, :price, :upgrade)";
    private static final String CLEAR_QUERY = "TRUNCATE servers_remainder CASCADE";


    @Override
    public Set<ServersRemainder> getAll() {
        return jdbcTemplate.queryForSet(GET_ALL_QUERY, SqlServersRemainderDao::toRemainder);
    }

    @Override
    public Set<ServersRemainder> getByCampaignGroup(long campaignGroupId) {
        return jdbcTemplate.queryForSet(GET_BY_CAMPAIGN_GROUP_ID,
                ImmutableMap.of("botCampaignGroupId", campaignGroupId), SqlServersRemainderDao::toRemainder);
    }

    @Override
    public void removeByCampaignGroupAndServices(final long campaignGroupId, final Set<Service> services) {
        if (services.isEmpty()) {
            return;
        }
        jdbcTemplate.update(REMOVE_BY_CAMPAIGN_GROUP_ID_AND_SERVICES, ImmutableMap.of("botCampaignGroupId", campaignGroupId,
                "services", CollectionUtils.ids(services)));
    }

    @Override
    public void createAll(Collection<ServersRemainder> serversRemainders) {
        if (serversRemainders.isEmpty()) {
            return;
        }
        final List<Map<String, ?>> params = serversRemainders.stream()
                .map(SqlServersRemainderDao::toParams)
                .collect(Collectors.toList());
        jdbcTemplate.batchUpdate(CREATE_ALL_QUERY, params);
    }

    @Override
    public boolean clear() {
        return jdbcTemplate.update(CLEAR_QUERY) > 0;
    }

    private static Map<String, ?> toParams(final ServersRemainder serversRemainder) {
        final Map<String, Object> params = new HashMap<>();
        params.put("serviceId", serversRemainder.getService().getId());
        params.put("segmentId", serversRemainder.getSegment().getId());
        params.put("groupKey", serversRemainder.getGroupKey());
        params.put("botCampaignGroupId", serversRemainder.getBotCampaignGroupId());
        params.put("serverId", serversRemainder.getServerId());
        params.put("storageId", serversRemainder.getStorageId());
        params.put("serverCount", serversRemainder.getServerCount());
        params.put("storageCount", serversRemainder.getStorageCount());
        params.put("price", serversRemainder.getPrice());
        params.put("upgrade", serversRemainder.isUpgrade());
        return params;
    }

    private static ServersRemainder toRemainder(final ResultSet rs, final int i) throws SQLException {
        final Hierarchy hierarchy = Hierarchy.get();
        final Service service = hierarchy.getServiceReader().read(rs.getLong("service_id"));
        final Segment segment = hierarchy.getSegmentReader().read(rs.getLong("segment_id"));
        final String groupKey = rs.getString("group_key");
        final Long serverId = getLong(rs, "server_id");
        final Long storageId = getLong(rs, "storage_id");
        final double serverCount = rs.getDouble("server_count");
        final double storageCount = rs.getDouble("storage_count");
        final double price = rs.getDouble("price");
        final long botCampaignGroupId = rs.getLong("bot_campaign_group_id");
        final boolean upgrade = rs.getBoolean("upgrade");

        return new ServersRemainder(service, segment, groupKey, serverId, storageId, serverCount, storageCount, price, botCampaignGroupId, upgrade);
    }
}
