package com.fdkankan.gateway.filter;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSON;
import com.fdkankan.common.constant.ErrorCode;
import com.fdkankan.common.constant.RedisKey;
import com.fdkankan.common.constant.ServerCode;
import com.fdkankan.common.exception.BusinessException;
import com.fdkankan.common.util.DataUtils;
import com.fdkankan.common.util.SHAUtils;
import com.fdkankan.gateway.dto.TmDeveloperDto;
import com.fdkankan.gateway.dto.User;
import lombok.extern.log4j.Log4j2;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.core.Ordered;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import org.springframework.util.MultiValueMap;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.util.HashMap;
import java.util.Map;

@Component
@Log4j2
public class AppAuthFilter implements GatewayFilter, Ordered {

    @Autowired
    private RedisTemplate<String, String> redisTemplate;

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {

        StringBuilder logBuilder = new StringBuilder();
        Map<String, String> params = parseRequest(exchange, logBuilder);
        if (!CollUtil.isEmpty(params)) {
            String token = params.get("token");
            String appId = params.get("appId");
            Long timeStamp = DataUtils.getLongReturnNullIfNotExit(params.get("timeStamp"));
            log.info("鉴权流程获取到的appid={}，请求路径:{}" , appId , exchange.getRequest().getURI());
            //先获取校验app id的合法性
            String developerJson = redisTemplate.opsForValue().get(String.format(RedisKey.TM_DEVELOPER, appId));
            if(StrUtil.isBlank(developerJson)){
                throw new BusinessException(ErrorCode.APP_ID_ILLEGAL);
            }
            //校验token的有效性
            TmDeveloperDto tmDeveloperDto = JSONUtil.toBean(developerJson, TmDeveloperDto.class);
            String tmpToken = tmDeveloperDto.getAppId() + tmDeveloperDto.getAppSecret() + timeStamp.toString();
            String enCodeToken = SHAUtils.getSHA256(tmpToken);
            if(!StrUtil.equals(enCodeToken , token)){
                throw new BusinessException(ErrorCode.TOKEN_ILLEGAL);
            }
            //校验数据是否已经被串改放到controller里面校验
            log.info("------网关基础校验通过-------");
        }else{
            throw new BusinessException(ErrorCode.PARAM_REQUIRED);
        }
        return chain.filter(exchange);
    }

    private Map<String, String> parseRequest(ServerWebExchange exchange, StringBuilder logBuilder) {
        ServerHttpRequest serverHttpRequest = exchange.getRequest();
        String method = serverHttpRequest.getMethodValue().toUpperCase();
        logBuilder.append(method).append(",").append(serverHttpRequest.getURI());
        MultiValueMap<String, String> query = serverHttpRequest.getQueryParams();
        Map<String, String> params = new HashMap<>();
        query.forEach((k, v) -> {
            params.put(k, v.get(0));
        });
        if ("POST".equals(method)) {
            String body = exchange.getAttributeOrDefault("cachedRequestBody", "");
            if (StrUtil.isNotBlank(body)) {
                logBuilder.append(",body=").append(body);
                String[] kvArray = body.split("&");
                for (String kv : kvArray) {
                    if (kv.indexOf("=") >= 0) {
                        String k = kv.split("=")[0];
                        String v = kv.split("=")[1];
                        if (!params.containsKey(k)) {
                            try {
                                params.put(k, URLDecoder.decode(v, "UTF-8"));
                            } catch (UnsupportedEncodingException e) {
                            }
                        }
                    }
                }
            }
        }
        return params;
    }

    @Override
    public int getOrder() {
        return -20;
    }
}
