/*
 * Copyright 2000-2013 JetBrains s.r.o.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package jetbrains.buildServer.buildTriggers.url;

import jetbrains.buildServer.serverSide.TeamCityProperties;
import jetbrains.buildServer.util.ssl.SSLContextUtil;
import jetbrains.buildServer.util.ssl.SSLTrustStoreProvider;
import jetbrains.buildServer.version.ServerVersionHolder;
import org.apache.http.Header;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.Credentials;
import org.apache.http.client.CredentialsProvider;
import org.apache.http.client.config.CookieSpecs;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.impl.client.BasicCredentialsProvider;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicHeader;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import javax.net.ssl.SSLContext;
import java.net.URI;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.List;

public class HttpClientProvider {

  @Nullable
  private final SSLTrustStoreProvider sslTrustStoreProvider;

  public HttpClientProvider(@Nullable SSLTrustStoreProvider sslTrustStoreProvider) {
    this.sslTrustStoreProvider = sslTrustStoreProvider;
  }

  @NotNull
  public CloseableHttpClient createClient(@NotNull URI uri, @Nullable Credentials credentials, @NotNull Integer connectionTimeout) throws NoSuchAlgorithmException {
    final RequestConfig requestConfig = RequestConfig
      .custom()
      .setConnectTimeout(connectionTimeout)
      .setConnectionRequestTimeout(connectionTimeout)
      .setSocketTimeout(connectionTimeout)
      .setCookieSpec(CookieSpecs.STANDARD)
      .build();

    final SSLContext sslContext = getSslContext();
    SSLConnectionSocketFactory sslConnectionFactory = new SSLConnectionSocketFactory(sslContext, SSLConnectionSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);

    final HttpClientBuilder builder = HttpClients.custom().setDefaultRequestConfig(requestConfig).setSSLSocketFactory(sslConnectionFactory);

    if (credentials != null) {
      if (!(credentials instanceof BearerTokenCredentials)) {
        final CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
        credentialsProvider.setCredentials(new AuthScope(getHostName(uri), uri.getPort()), credentials);

        builder.setDefaultCredentialsProvider(credentialsProvider);
      }
    }

    builder.setUserAgent("JetBrains TeamCity " + ServerVersionHolder.getVersion().getDisplayVersion() + " (URL build trigger)");

    final List<Header> resHeaders = new ArrayList<>();
    String additionalHeaders = TeamCityProperties.getPropertyOrNull("teamcity.urlTrigger.additionalHeaders");
    if (additionalHeaders != null) {
      for (String additionalHeader : additionalHeaders.split("\n")) {
        String[] split = additionalHeader.split(":");
        resHeaders.add(new BasicHeader(split[0], split.length > 1 ? split[1] : null));
      }
    }
    builder.setDefaultHeaders(resHeaders);

    return builder.build();
  }

  private SSLContext getSslContext() throws NoSuchAlgorithmException {
    SSLContext tryContext = SSLContextUtil.createUserSSLContext(sslTrustStoreProvider != null ? sslTrustStoreProvider.getTrustStore() : null);
    return tryContext != null ? tryContext : SSLContext.getDefault();
  }

  @NotNull
  private String getHostName(@NotNull URI uri) {
    final String host = uri.getHost();
    if (host.startsWith("http://")) return host.substring(7);
    if (host.startsWith("https://")) return host.substring(8);
    return host;
  }
}
