package com.red.circle.framework.web.feign;

import com.red.circle.framework.core.request.RequestHeaderConstant;
import com.red.circle.framework.core.request.ServiceTraceId;
import feign.RequestInterceptor;
import feign.RequestTemplate;
import jakarta.servlet.http.HttpServletRequest;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.Set;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

/**
 * Forward only business headers to Feign requests.
 */
@Component
@Order(Ordered.LOWEST_PRECEDENCE)
public class FeignRequestInterceptor implements RequestInterceptor {

  private static final String INNER_SERVICE = "FEIGN";

  private static final List<String> FORWARD_HEADERS = List.of(
      RequestHeaderConstant.AUTHORIZATION,
      RequestHeaderConstant.REQ_SYS_ORIGIN,
      RequestHeaderConstant.REQ_CLIENT,
      RequestHeaderConstant.REQ_ZONE,
      RequestHeaderConstant.REQ_IMEI,
      RequestHeaderConstant.REQ_APP_INTEL,
      RequestHeaderConstant.REQ_VERSION,
      RequestHeaderConstant.REQ_LANG,
      RequestHeaderConstant.REQ_INNER_INTERNAL,
      RequestHeaderConstant.REQ_INNER_TRACE_ID
  );

  private static final Set<String> BLOCKED_HEADERS = Set.of(
      "host",
      "content-length",
      "transfer-encoding",
      "connection",
      "keep-alive",
      "upgrade",
      "proxy-authorization",
      "proxy-authenticate",
      "te",
      "trailer"
  );

  @Override
  public void apply(RequestTemplate requestTemplate) {
    removeBlockedHeaders(requestTemplate);

    if (RequestContextHolder.getRequestAttributes() instanceof ServletRequestAttributes attrs) {
      forwardHeaders(requestTemplate, attrs.getRequest());
    }

    if (!hasHeader(requestTemplate, RequestHeaderConstant.REQ_INNER_SERVICE)) {
      requestTemplate.header(RequestHeaderConstant.REQ_INNER_SERVICE, INNER_SERVICE);
    }
    if (!hasHeader(requestTemplate, RequestHeaderConstant.REQ_INNER_TRACE_ID)) {
      requestTemplate.header(
          RequestHeaderConstant.REQ_INNER_TRACE_ID,
          ServiceTraceId.genTraceId(ServiceTraceId.Origin.INNER_REQ));
    }

    removeBlockedHeaders(requestTemplate);
  }

  private void forwardHeaders(RequestTemplate requestTemplate, HttpServletRequest request) {
    for (String header : FORWARD_HEADERS) {
      String value = request.getHeader(header);
      if (hasHeader(requestTemplate, header) || !isUsableHeaderValue(value)) {
        continue;
      }
      requestTemplate.header(header, value);
    }
  }

  private void removeBlockedHeaders(RequestTemplate requestTemplate) {
    List<String> names = new ArrayList<>(requestTemplate.headers().keySet());
    for (String name : names) {
      if (isBlockedHeader(name)) {
        requestTemplate.removeHeader(name);
      }
    }
  }

  private boolean hasHeader(RequestTemplate requestTemplate, String header) {
    return requestTemplate.headers().keySet().stream()
        .anyMatch(name -> name.equalsIgnoreCase(header));
  }

  private boolean isBlockedHeader(String header) {
    if (header == null) {
      return true;
    }
    String normalized = header.toLowerCase(Locale.ROOT);
    return BLOCKED_HEADERS.contains(normalized) || normalized.startsWith("proxy-");
  }

  private boolean isUsableHeaderValue(String value) {
    if (value == null || value.isBlank()) {
      return false;
    }
    for (int i = 0; i < value.length(); i++) {
      char c = value.charAt(i);
      if (c < 32 || c == 127) {
        return false;
      }
    }
    return true;
  }
}
