package ru.ibs.socrates.confexporter.external.access.interceptor;

import feign.RequestInterceptor;
import feign.RequestTemplate;
import java.util.Objects;
import java.util.UUID;
import java.util.function.Supplier;
import lombok.AllArgsConstructor;
import lombok.NoArgsConstructor;
import ru.ibs.socrates.confexporter.external.access.service.AccessTokenAcquirer;

/**
 * Интерцептор для проброса заголовков при вызове сервисов.
 */
public class AccessRequestInterceptor implements RequestInterceptor {

  private static final String AUTHORIZATION_HEADER = "Authorization";
  private static final String X_CALL_ID_HEADER = "X-Call-ID";

  private final ApplyHeader applyAuthorization;
  private final ApplyHeader applyCallId;

  /**
   * AccessRequestInterceptor.
   */
  public AccessRequestInterceptor() {
    this(null);
  }

  /**
   * AccessRequestInterceptor.
   * @param tokenAcquirer
   */
  public AccessRequestInterceptor(AccessTokenAcquirer tokenAcquirer) {
    applyCallId =
        new DefaultApplyHeader(X_CALL_ID_HEADER, () -> UUID.randomUUID().toString());

    if (Objects.nonNull(tokenAcquirer)) {
      applyAuthorization =
          new DefaultApplyHeader(AUTHORIZATION_HEADER, () -> tokenAcquirer.acquire());
    } else {
      applyAuthorization = new NoApplyHeader();
    }
  }

  /**
   * Получить хидеры для интерцептора.
   */
  @Override
  public void apply(RequestTemplate requestTemplate) {
    applyCallId.apply(requestTemplate);
    applyAuthorization.apply(requestTemplate);
  }

  /**
   * Получить хидеры для интерцептора.
   */
  protected interface ApplyHeader {
    void apply(RequestTemplate requestTemplate);
  }

  /**
   * Получить хидеры для интерцептора.
   */
  @AllArgsConstructor
  protected class DefaultApplyHeader implements ApplyHeader {

    private final String header;
    private final Supplier<String> value;

    @Override
    public void apply(RequestTemplate requestTemplate) {
      requestTemplate.removeHeader(header);
      requestTemplate.header(header, value.get());
    }

  }

  /**
   * Получить хидеры для интерцептора, без логики задания заголовка.
   */
  @NoArgsConstructor
  protected class NoApplyHeader implements ApplyHeader {

    @Override
    public void apply(RequestTemplate requestTemplate) {

    }
  }

}
