package cn.axzo.workflow.server.common.interceptor;

import cn.axzo.workflow.core.common.exception.WorkflowEngineException;
import cn.axzo.workflow.core.repository.entity.ExtAxProperty;
import cn.axzo.workflow.core.service.ExtAxPropertyService;
import lombok.extern.slf4j.Slf4j;
import org.apache.maven.artifact.versioning.DefaultArtifactVersion;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.servlet.HandlerInterceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Enumeration;
import java.util.Objects;

import static cn.axzo.workflow.client.config.WorkflowRequestInterceptor.HEADER_API_VERSION;
import static cn.axzo.workflow.client.config.WorkflowRequestInterceptor.HEADER_HTTP_CLIENT;
import static cn.axzo.workflow.client.config.WorkflowRequestInterceptor.HEADER_HTTP_CLIENT_VALUE;
import static cn.axzo.workflow.client.config.WorkflowRequestInterceptor.HEADER_SERVER_NAME;
import static cn.axzo.workflow.common.constant.BpmnConstants.FLOW_SERVER_VERSION_130;
import static cn.axzo.workflow.core.common.code.OtherRespCode.CLIENT_VERSION_SUPPORT;
import static cn.axzo.workflow.core.common.code.OtherRespCode.MICRO_SERVER_NEED_REBUILD;

/**
 * 客户端与服务端的版本比较
 *
 * @author wangli
 * @since 2024/2/4 15:48
 */
@Component
@Slf4j
public class RequestHeaderContextInterceptor implements HandlerInterceptor {
    @Autowired
    private String serviceVersion;
    @Autowired
    private ExtAxPropertyService extAxPropertyService;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        if (Objects.equals(HEADER_HTTP_CLIENT_VALUE, request.getHeader(HEADER_HTTP_CLIENT))) {
            String headerClientVersion = request.getHeader(HEADER_API_VERSION)
                    .replaceAll("-SNAPSHOT", "")
                    .replaceAll("-RELEASE", "");
            serviceVersion = serviceVersion
                    .replaceAll("-SNAPSHOT", "")
                    .replaceAll("-RELEASE", "");
            DefaultArtifactVersion minimumSupportedVersion = new DefaultArtifactVersion(FLOW_SERVER_VERSION_130);
            DefaultArtifactVersion clientVersion = new DefaultArtifactVersion(headerClientVersion);
            DefaultArtifactVersion serverVersion = new DefaultArtifactVersion(serviceVersion);
            if (clientVersion.compareTo(minimumSupportedVersion) >= 0 || clientVersion.compareTo(serverVersion) >= 0) {

                recordClientInfo(request, headerClientVersion, clientVersion);

                return true;
            } else {
                log.info("request uri 1 : {}", request.getRequestURI());
                printHeader(request);
                log.error(CLIENT_VERSION_SUPPORT.getMessage(), serviceVersion, headerClientVersion);
                throw new WorkflowEngineException(CLIENT_VERSION_SUPPORT, serviceVersion, headerClientVersion);
            }
        }
        // 仅 feignApi 才需要检查版本
        if (!request.getRequestURI().contains("/web/") && !request.getRequestURI().contains("checkDeath")
                && !StringUtils.hasText(request.getHeader(HEADER_HTTP_CLIENT))) {
            String serverName = request.getHeader(HEADER_SERVER_NAME);
            printHeader(request);
            log.error(MICRO_SERVER_NEED_REBUILD.getMessage(), serverName);
            throw new WorkflowEngineException(MICRO_SERVER_NEED_REBUILD, serverName);
        }
        return true;
    }

    private void recordClientInfo(HttpServletRequest request, String headerClientVersion,
                                  DefaultArtifactVersion clientVersion) {
        if (!StringUtils.hasText(request.getHeader(HEADER_SERVER_NAME))) {
            return;
        }
        ExtAxProperty property = extAxPropertyService.getByName(request.getHeader(HEADER_SERVER_NAME)).map(entity -> {
            entity.setCreated(!Objects.equals(entity.getValue(), serviceVersion));
            entity.setValue(headerClientVersion);
            return entity;
        }).orElseGet(() -> {
            ExtAxProperty extAxProperty = new ExtAxProperty();
            extAxProperty.setCreated(true);
            extAxProperty.setName(request.getHeader(HEADER_SERVER_NAME));
            extAxProperty.setValue(clientVersion.toString());
            return extAxProperty;
        });

        if (property.getCreated()) {
            if (Objects.isNull(property.getId())) {
                extAxPropertyService.add(property);
            } else {
                extAxPropertyService.update(property);
            }
        }
    }

    private void printHeader(HttpServletRequest request) {
        Enumeration<String> headerNames = request.getHeaderNames();
        log.info("parse header start, current uri: {}", request.getRequestURI());
        while (headerNames.hasMoreElements()) {
            String headerName = headerNames.nextElement();
            String headerValue = request.getHeader(headerName);
            log.info("headerName: {}, headerValue: {}", headerName, headerValue);
        }
        log.info("parse header end");
    }

}
