package ru.yandex.webmaster.common.host.dao;

import java.sql.*;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import org.springframework.jdbc.core.PreparedStatementCreator;
import org.springframework.jdbc.core.simple.ParameterizedRowMapper;
import org.springframework.jdbc.support.GeneratedKeyHolder;

import ru.yandex.common.util.db.LongRowMapper;
import ru.yandex.wmconsole.data.info.BriefHostInfo;
import ru.yandex.wmconsole.data.info.HostDbHostInfo;
import ru.yandex.wmconsole.data.partition.WMCPartition;
import ru.yandex.wmtools.common.error.InternalException;
import ru.yandex.wmtools.common.service.AbstractDbService;
import ru.yandex.wmtools.common.util.SqlUtil;

/**
 * @author aherman
 */
public class TblHostsHostDao extends AbstractDbService {
    public HostDbHostInfo addHostInfoToHostDb(final String hostname) throws InternalException {
        final String q = "INSERT IGNORE INTO tbl_hosts (name) VALUES (?)";
        GeneratedKeyHolder keyHolder = new GeneratedKeyHolder();
        PreparedStatementCreator statementCreator = new PreparedStatementCreator() {
            @Override
            public PreparedStatement createPreparedStatement(Connection connection) throws SQLException {
                PreparedStatement statement = connection.prepareStatement(q, Statement.RETURN_GENERATED_KEYS);
                statement.setString(1, hostname);
                return statement;
            }
        };
        getJdbcTemplate(new WMCPartition(null, hostname, null)).getJdbcOperations().update(statementCreator, keyHolder);
        if (keyHolder.getKey() == null) {
            return null;
        }
        long hostId = keyHolder.getKey().longValue();
        return new HostDbHostInfo(hostId, hostname);
    }

    public HostDbHostInfo getHostDbHostIdByHostname(String hostname) throws InternalException {
        String q = "SELECT host_id FROM tbl_hosts WHERE name = ?";
        List<Long> result = getJdbcTemplate(new WMCPartition(null, hostname, null)).query(q, new LongRowMapper(), hostname);
        if ((result == null) || result.isEmpty()) {
            return null;
        }
        long hostId = result.get(0);
        return new HostDbHostInfo(hostId, hostname);
    }

    public HostDbHostInfo getHostDbHostInfoByHostId(int dbNum, long hostId) throws InternalException {
        String q = "SELECT host_id, name FROM tbl_hosts WHERE host_id = ?";
        List<HostDbHostInfo> results = getJdbcTemplate(new WMCPartition(dbNum, hostId)).query(q, MAPPER, hostId);
        return results.isEmpty() ? null : results.get(0);
    }

    public List<List<HostDbHostInfo>> listHostsForNames(List<BriefHostInfo> hostInfos) throws InternalException {
        List<List<String>> splittedHosts = new ArrayList<>(getDatabaseCount());
        for (int i = 0; i < getDatabaseCount(); i++) {
            splittedHosts.add(new ArrayList<String>());
        }
        for (BriefHostInfo hostInfo : hostInfos) {
            String hostName = hostInfo.getName();
            splittedHosts.get(getDBIndex(hostName)).add(hostName);
        }

        List<List<HostDbHostInfo>> result = new ArrayList<>(getDatabaseCount());
        for (int i = 0; i < getDatabaseCount(); i++) {
            List<String> hostsBatch = splittedHosts.get(i);
            if (hostsBatch.isEmpty()) {
                result.add(Collections.<HostDbHostInfo>emptyList());
            } else {
                result.add(getJdbcTemplate(new WMCPartition(i)).query(
                        "SELECT host_id, name FROM tbl_hosts WHERE name IN (" + SqlUtil.createQuestionMarks(hostsBatch.size()) + ")",
                        MAPPER,
                        hostsBatch.toArray()
                ));
            }
        }
        return result;
    }

    private int getDBIndex(String name) {
        return new WMCPartition(null, name, null).getDatabaseIndex(getDatabaseCount());
    }

    private static final ParameterizedRowMapper<HostDbHostInfo> MAPPER = new ParameterizedRowMapper<HostDbHostInfo>() {
        @Override
        public HostDbHostInfo mapRow(ResultSet rs, int rowNum) throws SQLException {
            return new HostDbHostInfo(rs.getLong("host_id"), rs.getString("name"));
        }
    };
}
