package ru.yandex.clickhouse.jdbcbridge.db.jdbc;

import lombok.extern.slf4j.Slf4j;
import org.eclipse.jetty.util.StringUtil;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.net.URISyntaxException;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;

/**
 * This class provides possibility for getting connections via
 * full DSN, or by alias (alias://localhost)
 * Created by krash on 25.09.18.
 */
@Slf4j
public class BridgeConnectionManager {

    private static final String ALIAS_SCHEMA = "datasource";
    private static final String ALIAS_CONFIG_PREFIX = "datasource.";
    private static final String CLIENT_NAME = "clickhouse-jdbc-bridge";

    private final Map<String, String> aliasMap = new HashMap<>();

    public void load(File aliasSpecificationFile) throws IOException {

        log.info("Loading aliases from file {}", aliasSpecificationFile);
        Properties properties = new Properties();
        try (InputStream stream = new FileInputStream(aliasSpecificationFile)) {
            properties.load(stream);
        }
        for (Map.Entry<Object, Object> entry : properties.entrySet()) {
            String key = entry.getKey().toString();
            String value = entry.getValue().toString();
            if (key.startsWith(ALIAS_CONFIG_PREFIX) && !value.isEmpty()) {
                key = key.substring(ALIAS_CONFIG_PREFIX.length());

                try {
                    // validate URI
                    URI uri = new URI(value);
                    // log only part
                    log.info("Registering datasource alias '{}' for {}://{}****", key, uri.getScheme(), uri.getHost());

                    aliasMap.put(key, value);
                } catch (URISyntaxException err) {
                    throw new IllegalArgumentException("Failed to validate DSN for alias '" + key + "' - " + value + ", error: " + err.getMessage());
                }
            }
        }
    }

    public Connection get(String uri) throws SQLException {
        if (StringUtil.isBlank(uri)) {
            throw new IllegalArgumentException("Empty connection string given");
        }
        URI uriObject = URI.create(uri);
        if (ALIAS_SCHEMA.equals(uriObject.getScheme())) {
            uri = aliasMap.get(uriObject.getHost());
            if (null == uri) {
                throw new SQLException("Unknown connection alias '" + uriObject.getHost() + "' given");
            }
        }

        if (!uri.startsWith("jdbc:")) {
            uri = "jdbc:" + uri;
        }

        Connection conn = DriverManager.getConnection(uri);

        try {
            // to avoid transactions
            conn.setAutoCommit(true);
        } catch (SQLException err) {
            log.error("Failed to set autocommit", err);
        }

        try {
            // to determine origin of the query
            conn.setClientInfo("ClientUser", CLIENT_NAME);
        } catch (SQLException err) {
            log.error("Failed to set client info", err);
        }


        return conn;
    }
}