package de.hftstuttgart.config;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;

import java.io.IOException;
import java.net.*;
import java.util.*;
import java.util.stream.Collectors;

@Configuration
/**
 * Configures Proxy once on startup
 */
public class ProxySetup extends ProxySelector
{
    private static final Logger LOG = LogManager.getLogger(ProxySetup.class);

    List<Proxy> noProxy;
    List<Proxy> setProxy;
    Set<String> noProxyHosts;

    public ProxySetup(Environment env) {

        String ignoredHostNames = env.getProperty("proxy.ignoredHostNames");
        if (Objects.isNull(ignoredHostNames)) {
            ignoredHostNames = "";
        }

        String proxy = env.getProperty("proxy");

        LOG.info("Configuring Proxy");
        noProxy = Collections.singletonList(Proxy.NO_PROXY);

        if (Objects.nonNull(proxy)) {
            String[] proxyValues = proxy.split(":");
            Proxy p = new Proxy(
                Proxy.Type.HTTP,
                new InetSocketAddress(proxyValues[0], Integer.parseInt(proxyValues[1])));
            setProxy = Collections.singletonList(p);

            LOG.info(String.format("set proxy: %s", p.address().toString()));
        }

        noProxyHosts = Arrays.stream(ignoredHostNames.split(","))
            .map(String::toLowerCase)
            .collect(Collectors.toCollection(HashSet::new));

        LOG.info(String.format("Hosts to be ignored: %s", noProxyHosts));

        ProxySelector.setDefault(this);
    }

    @Override
    public List<Proxy> select(URI uri) {

        LOG.debug(String.format("Proxy selection for URI: %s", uri.getHost()));

        // No proxy for given hosts
        if (noProxyHosts.contains(uri.getHost().toLowerCase())) {
            LOG.debug(String.format("Proxy disabled for host %s", uri.getHost()));
            return noProxy;
        }

        // no proxy if no proxy was set
        if (Objects.nonNull(setProxy)) {
            LOG.debug(String.format("Proxy used for host %s", uri.getHost()));
            return setProxy;
        }

        LOG.debug("No proxy configured to choose from");
        return noProxy;
    }

    @Override
    public void connectFailed(URI uri, SocketAddress socketAddress, IOException e) {
        LOG.error(String.format("connection to %s failed with %s", uri.getHost(), e.getMessage()));
    }
}
