package ru.yandex.qe.dispenser.domain.dao.resource;

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

import com.google.common.collect.ImmutableMap;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.TestOnly;

import ru.yandex.qe.dispenser.domain.Resource;
import ru.yandex.qe.dispenser.domain.ResourceMapping;
import ru.yandex.qe.dispenser.domain.dao.SqlDaoBase;
import ru.yandex.qe.dispenser.domain.hierarchy.Hierarchy;
import ru.yandex.qe.dispenser.domain.util.CollectionUtils;

public class SqlResourceMappingDao extends SqlDaoBase implements ResourceMappingDao {
    private static final String INSERT_ALL_QUERY = "INSERT INTO resource_mapping(request_resource_id, quota_resource_key, service_key) VALUES (:request_resource_id, :quota_resource_key, :service_key)";
    private static final String GET_ALL_QUERY = "SELECT * FROM resource_mapping";
    private static final String GET_BY_ID_QUERY = "SELECT * FROM resource_mapping WHERE request_resource_id = :id";
    private static final String GET_BY_IDS_QUERY = "SELECT * FROM resource_mapping WHERE request_resource_id IN (:ids)";
    private static final String CLEAR_QUERY = "TRUNCATE resource_mapping CASCADE";

    @Override
    @TestOnly
    public void create(final Collection<ResourceMapping> resourceMappings) {
        jdbcTemplate.batchUpdate(INSERT_ALL_QUERY, resourceMappings.stream().map(SqlResourceMappingDao::toParams).collect(Collectors.toList()));
    }

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

    @Override
    public Set<ResourceMapping> getAll() {
        return jdbcTemplate.queryForSet(GET_ALL_QUERY, SqlResourceMappingDao::toResourceMapping);
    }

    @Override
    public Optional<ResourceMapping> getMappingOptional(final Resource resource) {
        return getMappingOptional(resource.getId());
    }

    @Override
    public Optional<ResourceMapping> getMappingOptional(final long id) {
        return jdbcTemplate.queryForOptional(GET_BY_ID_QUERY, ImmutableMap.of("id", id), SqlResourceMappingDao::toResourceMapping);
    }

    @Override
    public Set<ResourceMapping> getMappingForResources(final Collection<Resource> resources) {
        return jdbcTemplate.queryForSet(GET_BY_IDS_QUERY, ImmutableMap.of("ids", CollectionUtils.ids(resources)), SqlResourceMappingDao::toResourceMapping);
    }

    private static ResourceMapping toResourceMapping(@NotNull final ResultSet rs, final int i) throws SQLException {
        final long resourceId = rs.getLong("request_resource_id");
        return new ResourceMapping(Hierarchy.get().getResourceReader().read(resourceId), rs.getString("quota_resource_key"),
                rs.getString("service_key"));
    }

    private static Map<String, Object> toParams(final ResourceMapping resourceMapping) {
        return ImmutableMap.of(
                "request_resource_id", resourceMapping.getResource().getId(),
                "quota_resource_key", resourceMapping.getForeignResourceKey(),
                "service_key", resourceMapping.getForeignServiceKey()
                );
    }
}
