package tech.easyflow.publicapi.interceptor;

import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.slf4j.MDC;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;
import tech.easyflow.common.web.error.RequestErrorProfile;
import tech.easyflow.common.web.error.RequestIdContext;
import tech.easyflow.publicapi.error.WorkflowRunAsyncErrorProfile;

import java.io.IOException;
import java.util.UUID;
import java.util.regex.Pattern;

/**
 * 在 Public API 进入 Spring MVC 前初始化请求关联标识和错误契约。
 */
@Component
@Order(Ordered.HIGHEST_PRECEDENCE + 20)
public class PublicApiRequestContextFilter
        extends OncePerRequestFilter {

    private static final Pattern VALID_REQUEST_ID = Pattern.compile(
            "[A-Za-z0-9][A-Za-z0-9._:-]{0,127}");
    private static final String WORKFLOW_API_PATH_PREFIX =
            "/public-api/workflow/";

    /**
     * {@inheritDoc}
     */
    @Override
    protected boolean shouldNotFilter(HttpServletRequest request) {
        String uri = request.getRequestURI();
        return uri == null || !uri.contains("/public-api/");
    }

    /**
     * {@inheritDoc}
     */
    @Override
    protected void doFilterInternal(
            HttpServletRequest request,
            HttpServletResponse response,
            FilterChain filterChain)
            throws ServletException, IOException {
        String requestId = resolveRequestId(
                request.getHeader(RequestIdContext.HEADER_NAME));
        request.setAttribute(
                RequestIdContext.ATTRIBUTE_NAME,
                requestId);
        response.setHeader(RequestIdContext.HEADER_NAME, requestId);
        if (isWorkflowApi(request)) {
            request.setAttribute(
                    RequestErrorProfile.ATTRIBUTE_NAME,
                    WorkflowRunAsyncErrorProfile.INSTANCE);
        }

        String previousRequestId = MDC.get(RequestIdContext.MDC_KEY);
        MDC.put(RequestIdContext.MDC_KEY, requestId);
        try {
            filterChain.doFilter(request, response);
        } finally {
            if (previousRequestId == null) {
                MDC.remove(RequestIdContext.MDC_KEY);
            } else {
                MDC.put(RequestIdContext.MDC_KEY, previousRequestId);
            }
        }
    }

    /**
     * 校验调用方请求 ID，非法时生成服务端 ID。
     *
     * @param supplied 调用方请求 ID
     * @return 可安全进入响应头和日志的请求 ID
     */
    private String resolveRequestId(String supplied) {
        if (supplied != null) {
            String trimmed = supplied.trim();
            if (VALID_REQUEST_ID.matcher(trimmed).matches()) {
                return trimmed;
            }
        }
        return UUID.randomUUID().toString().replace("-", "");
    }

    /**
     * 判断请求是否为工作流 Public API。
     *
     * @param request 当前请求
     * @return 是否匹配目标接口
     */
    private boolean isWorkflowApi(HttpServletRequest request) {
        String uri = request.getRequestURI();
        return uri != null && uri.contains(WORKFLOW_API_PATH_PREFIX);
    }
}
