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

import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Collections;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

import javax.annotation.ParametersAreNonnullByDefault;

import com.google.common.collect.ImmutableMap;
import org.jetbrains.annotations.NotNull;
import org.springframework.dao.EmptyResultDataAccessException;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import ru.yandex.qe.dispenser.domain.Segmentation;
import ru.yandex.qe.dispenser.domain.dao.SqlDaoBase;

@ParametersAreNonnullByDefault
public class SqlSegmentationDao extends SqlDaoBase implements SegmentationDao {
    private static final String GET_ALL_QUERY = "SELECT * FROM segmentation";
    private static final String CREATE_QUERY = "INSERT INTO segmentation (key, name, description, priority) VALUES (:key, :name, :description, :priority)";
    private static final String READ_QUERY = "SELECT * FROM segmentation WHERE id = :id";
    private static final String UPDATE_QUERY = "UPDATE segmentation SET key = :key, name = :name, description = :description, priority = :priority WHERE id = :segmentationId";
    private static final String DELETE_QUERY = "DELETE FROM segmentation WHERE id = :segmentationId";

    @NotNull
    @Override
    @Transactional(propagation = Propagation.REQUIRED)
    public Set<Segmentation> getAll() {
        return new HashSet<>(jdbcTemplate.query(GET_ALL_QUERY, this::toSegmentation));
    }

    @NotNull
    @Override
    @Transactional(propagation = Propagation.REQUIRED)
    public Segmentation create(@NotNull final Segmentation segmentation) {
        jdbcTemplate.update(CREATE_QUERY, toParams(segmentation));
        return read(segmentation.getKey());
    }

    @NotNull
    @Override
    @Transactional(propagation = Propagation.REQUIRED)
    public Segmentation read(@NotNull final Long id) throws EmptyResultDataAccessException {
        return jdbcTemplate.queryForOptional(READ_QUERY, Collections.singletonMap("id", id), this::toSegmentation)
                .orElseThrow(() -> new EmptyResultDataAccessException("No segmentation with id " + id, 1));
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRED)
    public boolean update(@NotNull final Segmentation segmentation) {
        return jdbcTemplate.update(UPDATE_QUERY, toParams(segmentation)) > 0;
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRED)
    public boolean delete(@NotNull final Segmentation segmentation) {
        return jdbcTemplate.update(DELETE_QUERY, toParams(segmentation)) > 0;
    }

    @NotNull
    private Segmentation toSegmentation(final ResultSet rs, final int i) throws SQLException {
        final Segmentation segmentation = new Segmentation.Builder(rs.getString("key"))
                .name(rs.getString("name"))
                .description(rs.getString("description"))
                .priority(rs.getInt("priority"))
                .build();
        segmentation.setId(rs.getLong("id"));
        return segmentation;
    }

    @NotNull
    public static Map<String, Object> toParams(final Segmentation segmentation) {
        return ImmutableMap.<String, Object>builder()
                .put("segmentationId", segmentation.getId())
                .put("key", segmentation.getKey().getPublicKey())
                .put("name", segmentation.getName())
                .put("description", segmentation.getDescription())
                .put("priority", segmentation.getPriority())
                .build();
    }
}
