package ru.ibs.socrates.confexporter.external.xmlparser.config;

import feign.Client;
import feign.Request;
import feign.RequestInterceptor;
import feign.Retryer;
import feign.codec.ErrorDecoder;
import java.util.concurrent.TimeUnit;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.hc.client5.http.ssl.NoopHostnameVerifier;
import org.apache.hc.client5.http.ssl.TrustAllStrategy;
import org.apache.hc.core5.ssl.SSLContexts;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.util.ResourceUtils;
import ru.ibs.socrates.confexporter.external.access.interceptor.AccessRequestInterceptor;
import ru.ibs.socrates.confexporter.external.access.service.AccessTokenAcquirer;
import ru.ibs.socrates.confexporter.service.content.utils.CustomErrorDecoder;
import ru.ibs.socrates.confexporter.service.content.utils.LimitInterceptor;

@Slf4j
public class XmlparserClientConfig {

  @Value("${integrations.xmlparser.ssl.key-store-enabled}")
  private Boolean keyStoreEnabled;

  @Value("${integrations.xmlparser.ssl.key-store-path}")
  private String keyStorePassword;

  @Value("${integrations.xmlparser.ssl.key-store-password}")
  private String keyStorePath;

  @Value("${integrations.xmlparser.ssl.trust-store-enabled}")
  private Boolean trustStoreEnabled;

  @Value("${integrations.xmlparser.ssl.trust-store-path}")
  private String trustStorePassword;

  @Value("${integrations.xmlparser.ssl.trust-store-password}")
  private String trustStorePath;

  @Bean
  @ConditionalOnExpression("'${integrations.sdt-llm-rag-gate-conf.access-type}'!='sdt-access'")
  public RequestInterceptor simpleRequestInterceptor() {
    log.info("xmlparser simple interceptior enabled");
    return new AccessRequestInterceptor();
  }

  @Bean
  @ConditionalOnProperty(name = "integrations.sdt-llm-rag-gate-conf.access-type",
      havingValue = "sdt-access")
  public RequestInterceptor accessTokenRequestInterceptor(
      AccessTokenAcquirer accessTokenAcquirer) {
    log.info("xmlparser sdt-access interceptior enabled");
    return new AccessRequestInterceptor(accessTokenAcquirer);
  }

  @Bean
  public Client client() {
    return new Client.Default(getSslSocketFactory(), new NoopHostnameVerifier(), false);
  }

  @SneakyThrows
  private SSLSocketFactory getSslSocketFactory() {
    final SSLContext sslContext;
    if (trustStoreEnabled) {
      if (keyStoreEnabled) {
        sslContext = SSLContexts.custom()
            .loadTrustMaterial(ResourceUtils.getFile(trustStorePath),
                trustStorePassword.toCharArray())
            .loadKeyMaterial(ResourceUtils.getFile(keyStorePath), keyStorePassword.toCharArray(),
                keyStorePassword.toCharArray())
            .build();
      } else {
        sslContext = SSLContexts.custom()
            .loadTrustMaterial(ResourceUtils.getFile(trustStorePath),
                trustStorePassword.toCharArray())
            .build();
      }
    } else {
      if (keyStoreEnabled) {
        sslContext = SSLContexts.custom()
            .loadTrustMaterial(null, new TrustAllStrategy())
            .loadKeyMaterial(ResourceUtils.getFile(keyStorePath), keyStorePassword.toCharArray(),
                keyStorePassword.toCharArray())
            .build();
      } else {
        sslContext = SSLContexts.custom()
            .loadTrustMaterial(null, new TrustAllStrategy())
            .build();
      }
    }
    return sslContext.getSocketFactory();
  }

  @Bean
  @ConditionalOnProperty(name = "integrations.xmlparser.limit.enabled")
  ErrorDecoder errorDecoder() {
    return new CustomErrorDecoder();
  }

  @Bean
  LimitInterceptor limitRequestInterceptor(
      @Value("${integrations.xmlparser.limit.per-second}") Long limit) {
    return new LimitInterceptor(limit);
  }

  @Bean
  @ConditionalOnProperty(name = "integrations.xmlparser.retry.enabled", matchIfMissing = false)
  Retryer retryer(
      @Value("${integrations.xmlparser.retry.period}") Long period,
      @Value("${integrations.xmlparser.retry.max-period}") Long maxPeriod,
      @Value("${integrations.xmlparser.retry.max-attempts}") Integer maxAttempts) {
    return new Retryer.Default(period, maxPeriod, maxAttempts);
  }

  @Bean
  Request.Options options(
      @Value("${integrations.xmlparser.connect-timeout}") long connectTimeout,
      @Value("${integrations.xmlparser.read-timeout}") long readTimeout) {
    return new Request.Options(connectTimeout, TimeUnit.MILLISECONDS, readTimeout,
        TimeUnit.MILLISECONDS, true);
  }
}
