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

import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Collections;

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

import ru.yandex.qe.dispenser.domain.dao.DiJdbcTemplate;
import ru.yandex.qe.dispenser.domain.property.Property;

enum TypeAdapter {
    BOOLEAN(Property.Type.BOOLEAN, "property_boolean_value") {
        @Override
        public Property.Value<?> getValue(final ResultSet resultSet, final String label) throws SQLException {
            return new Property.Value<>(Property.Type.BOOLEAN, resultSet.getBoolean(label));
        }
    },
    STRING(Property.Type.STRING, "property_string_value") {
        @Override
        public Property.Value<?> getValue(final ResultSet resultSet, final String label) throws SQLException {
            return new Property.Value<>(Property.Type.STRING, resultSet.getString(label));
        }
    };

    private final Property.Type<?> type;

    private final String valueQueryPart;
    private final String insertQuery;
    private final String updateQuery;
    private final String deleteQuery;

    TypeAdapter(final Property.Type<?> type, final String tableName) {
        this.type = type;

        valueQueryPart = "JOIN " + tableName + " ON property.id = " + tableName + ".property_id";

        insertQuery = "INSERT INTO " + tableName + " (property_id, value) VALUES (:propertyId, :value)";
        updateQuery = "UPDATE " + tableName + " SET value = :value WHERE property_id = :propertyId";
        deleteQuery = "DELETE FROM " + tableName + " WHERE property_id = :propertyId";
    }

    public Property.Type<?> getType() {
        return type;
    }

    public String getValueQueryPart() {
        return valueQueryPart;
    }

    public boolean create(final DiJdbcTemplate jdbcTemplate, final long propertyId, final Object value) {
        return jdbcTemplate.update(insertQuery, getParams(propertyId, value)) > 0;
    }

    public boolean update(final DiJdbcTemplate jdbcTemplate, final long propertyId, final Object value) {
        return jdbcTemplate.update(updateQuery, getParams(propertyId, value)) > 0;
    }

    public boolean delete(final DiJdbcTemplate jdbcTemplate, final long propertyId) {
        return jdbcTemplate.update(deleteQuery, Collections.singletonMap("propertyId", propertyId)) > 0;
    }

    public abstract Property.Value<?> getValue(final ResultSet resultSet, final String label) throws SQLException;

    @NotNull
    private ImmutableMap<String, ?> getParams(final long propertyId, final Object value) {
        return ImmutableMap.of(
                "propertyId", propertyId,
                "value", value
        );
    }
}
