package com.ruoyi.framework.interceptor;

import cn.hutool.core.util.StrUtil;
import com.ruoyi.common.utils.XssUtil;
import com.ruoyi.framework.annotation.RyRateLimit;
import com.ruoyi.framework.config.XssConfig;
import org.noear.solon.annotation.Component;
import org.noear.solon.annotation.Inject;
import org.noear.solon.core.handle.Context;
import org.noear.solon.core.handle.Handler;
import org.noear.solon.core.handle.Result;
import org.noear.solon.core.route.RouterInterceptor;
import org.noear.solon.core.route.RouterInterceptorChain;

import java.util.Map;

/**
 * 全局路由拦截器
 * @author ruoyi
 */
@Component
public class GlobalRouterInterceptor implements RouterInterceptor {

    @Inject
    XssConfig xssConfig;

    // 以下前缀的路径不统一返回结果（监控、接口文档）
    private static final String[] ignorePaths = { "/solon-admin", "/swagger" };

//    @RyRateLimit()  // 全局限流
    @Override
    public void doIntercept(Context ctx, Handler mainHandler, RouterInterceptorChain chain) throws Throwable {
        handleIntercept(ctx, mainHandler, chain);
    }

    @Override
    public Object postResult(Context ctx, Object result) throws Throwable {
        return handlePostResult(ctx, result);
    }

    /**
     * 清除 XSS
     * @param ctx
     * @param mainHandler
     * @param chain
     * @throws Throwable
     */
    private void handleIntercept(Context ctx, Handler mainHandler, RouterInterceptorChain chain) throws Throwable {
        if (mainHandler != null && xssConfig.getEnabled() && !xssConfig.getExcludes().contains(ctx.pathAsLower())) {
            // 请求头
//            for (Map.Entry<String, String> kv : ctx.headerMap().toValueMap().entrySet()) {
//                kv.setValue(cleanXss(kv.getValue()));
//            }
            // 请求参数
            for (Map.Entry<String, String> kv : ctx.paramMap().toValueMap().entrySet()) {
                kv.setValue(cleanXss(kv.getValue()));
            }
            // 请求体
            if (ctx.contentType() != null && ctx.contentType().contains("json")) {
                ctx.bodyNew(cleanXss(ctx.body()));
            }
        }
        chain.doIntercept(ctx, mainHandler);
    }

    /**
     * 统一返回结果（将异常之外的返回结果统一为 Result，render执行前调用）
     * @param ctx
     * @param result
     * @return
     */
    private Object handlePostResult(Context ctx, Object result) {
        // 部分路径不统一返回结果
        if(StrUtil.startWithAny(ctx.pathAsLower(), ignorePaths)) {
            return result;
        }
        // 异常直接返回，由过滤器处理
        return result instanceof Result || result instanceof Throwable ? result : Result.succeed(result);
    }

    private String cleanXss(String input) {
        if (StrUtil.isBlankOrUndefined(input)) {
            return input;
        }
        input = XssUtil.removeEvent(input);
        input = XssUtil.removeScript(input);
        input = XssUtil.removeEval(input);
        input = XssUtil.swapJavascript(input);
        input = XssUtil.swapVbscript(input);
        input = XssUtil.swapLivescript(input);
        input = XssUtil.encode(input);
        return input;
    }

}
