package com.qmth.boot.api.interceptor.impl;

import com.qmth.boot.api.config.ApiConfig;
import com.qmth.boot.api.config.ApiConfigService;
import com.qmth.boot.api.config.ApiProperties;
import com.qmth.boot.api.constant.ApiConstant;
import com.qmth.boot.api.exception.DefaultExceptionEnum;
import com.qmth.boot.api.interceptor.AbstractInterceptor;
import com.qmth.boot.api.valve.IPFilterPolicy;
import com.qmth.boot.api.valve.IPFilterService;
import com.qmth.boot.core.enums.Platform;
import com.qmth.boot.core.logger.constant.LoggerConstant;
import com.qmth.boot.tools.uuid.FastUUID;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.MDC;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@Component
public class ValveInterceptor extends AbstractInterceptor implements ApiConstant {

    @Resource
    private ApiProperties apiProperties;

    @Resource
    private ApiConfigService apiConfigService;

    @Resource
    private IPFilterService ipFilterService;

    private IPFilterPolicy ipFilterPolicy;

    @Autowired(required = false)
    public void setIpFilterPolicy(IPFilterPolicy ipFilterPolicy) {
        this.ipFilterPolicy = ipFilterPolicy;
    }

    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
        ApiConfig config = getApiConfig(apiProperties, apiConfigService, request, handler);
        Platform platform = Platform.findByName(StringUtils.trimToNull(request.getHeader(HEADER_PLATFORM)));
        String deviceId = StringUtils.trimToNull(request.getHeader(HEADER_DEVICE_ID));
        if (config.isStrict()) {
            // 严格模式platform和deviceId必须存在
            if (platform == null) {
                throw DefaultExceptionEnum.HEADER_PLATFORM_INVALID.exception();
            }
            if (deviceId == null) {
                throw DefaultExceptionEnum.HEADER_DEVICEID_INVALID.exception();
            }
            // 匹配指定允许的platform
            validatePlatform(request, platform, config);
        }
        // 执行IP过滤判断
        validateIP(request, config);
        // 优先从header读取traceId，否则自动生成
        String traceId = StringUtils.trimToNull(request.getHeader(HEADER_TRACE_ID));
        if (traceId == null) {
            traceId = FastUUID.get();
        }
        request.setAttribute(ATTRIBUTE_TRACE_ID, traceId);
        MDC.put(LoggerConstant.MDC_TRACE_ID, traceId);
        return true;
    }

    private void validatePlatform(HttpServletRequest request, Platform platform, ApiConfig config) {
        if (ArrayUtils.isNotEmpty(config.getPlatform())) {
            boolean match = false;
            for (Platform p : config.getPlatform()) {
                if (p.equals(platform)) {
                    match = true;
                    break;
                }
            }
            if (!match) {
                log.warn("Platform not allowed: path={}, platform={}, allowed={}", request.getServletPath(),
                        platform.getName(), StringUtils.join(config.getPlatform(), ","));
                throw DefaultExceptionEnum.PLATFORM_FORBIDDEN.exception();
            }
        }
    }

    private void validateIP(HttpServletRequest request, ApiConfig config) {
        // 先从接口获取动态规则
        String[] ipAllow = ipFilterPolicy != null ? ipFilterPolicy.getAllowIP(request.getServletPath()) : null;
        String[] ipDeny = ipFilterPolicy != null ? ipFilterPolicy.getDenyIP(request.getServletPath()) : null;
        // 若没有动态规则，则从静态配置中获取
        if (ArrayUtils.isEmpty(ipAllow)) {
            ipAllow = config.getIpAllow();
        }
        if (ArrayUtils.isEmpty(ipDeny)) {
            ipDeny = config.getIpDeny();
        }
        ipFilterService.filter(request, ipAllow, ipDeny);
    }

}
