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

import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.fasterxml.jackson.core.type.TypeReference;
import org.jetbrains.annotations.NotNull;
import org.postgresql.util.PGobject;
import org.springframework.dao.EmptyResultDataAccessException;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import ru.yandex.qe.dispenser.domain.CampaignServiceResourcesPreset;
import ru.yandex.qe.dispenser.domain.dao.SqlDaoBase;
import ru.yandex.qe.dispenser.domain.dao.SqlUtils;
import ru.yandex.qe.dispenser.domain.dictionaries.model.CampaignProvidersSettingsDictionary;

public class SqlCampaignServiceResourcesPresetDao extends SqlDaoBase implements CampaignServiceResourcesPresetDao {

    public static final TypeReference<List<CampaignProvidersSettingsDictionary.ResourcePreset>> PRESET_TYPE = new TypeReference<List<CampaignProvidersSettingsDictionary.ResourcePreset>>() {
    };

    private static final String INSERT_QUERY = "INSERT INTO campaign_service_resource_preset (campaign_id, service_id, preset) VALUES (:campaignId, :serviceId, :preset)";

    private static final String SELECT_BY_PK_QUERY = "SELECT * FROM campaign_service_resource_preset WHERE campaign_id = :campaignId AND service_id = :serviceId";
    private static final String SELECT_BY_CAMPAIGN_ID_QUERY = "SELECT * FROM campaign_service_resource_preset WHERE campaign_id = :campaignId";

    private static final String UPDATE_QUERY = "UPDATE campaign_service_resource_preset SET preset = :preset WHERE campaign_id = :campaignId AND service_id = :serviceId";

    private static final String DELETE_QUERY = "DELETE FROM campaign_service_resource_preset WHERE campaign_id = :campaignId AND service_id = :serviceId";

    private static final String CLEAR_QUERY = "TRUNCATE campaign_service_resource_preset";


    @NotNull
    @Override
    @Transactional(propagation = Propagation.REQUIRED)
    public CampaignServiceResourcesPreset create(@NotNull final CampaignServiceResourcesPreset preset) {
        jdbcTemplate.update(INSERT_QUERY, toParams(preset));
        return preset;
    }

    @NotNull
    @Override
    public CampaignServiceResourcesPreset read(@NotNull final CampaignServiceResourcesPreset.Key key) throws EmptyResultDataAccessException {
        return jdbcTemplate.queryForObject(SELECT_BY_PK_QUERY, toParams(key), this::toPreset);
    }

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

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

    @Override
    @Transactional(propagation = Propagation.REQUIRED)
    public boolean clear() {
        return jdbcTemplate.update(CLEAR_QUERY) > 0;
    }

    @Override
    public List<CampaignServiceResourcesPreset> getPresetsByCampaignId(final long campaignId) {
        return jdbcTemplate.query(SELECT_BY_CAMPAIGN_ID_QUERY, Collections.singletonMap("campaignId", campaignId), this::toPreset);
    }

    private Map<String, Object> toParams(final CampaignServiceResourcesPreset preset) {
        final Map<String, Object> params = toParams(preset.getKey());
        params.put("preset", SqlUtils.toJsonb(preset.getResourcePresets()));
        return params;
    }

    private Map<String, Object> toParams(final CampaignServiceResourcesPreset.Key key) {
        final HashMap<String, Object> params = new HashMap<>();
        params.put("campaignId", key.getCampaignId());
        params.put("serviceId", key.getServiceId());
        return params;
    }

    private CampaignServiceResourcesPreset toPreset(final ResultSet rs, final int ignored) throws SQLException {
        return new CampaignServiceResourcesPreset(new CampaignServiceResourcesPreset.Key(
                rs.getLong("campaign_id"),
                rs.getLong("service_id")
        ), SqlUtils.fromJsonb((PGobject) rs.getObject("preset"), PRESET_TYPE));
    }

}
