package com.tofly.getway.filter;

import com.tofly.common.core.constant.SecurityConstants;
import com.tofly.common.core.util.HttpURL;
import com.tofly.common.core.util.StringUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.stereotype.Component;
import org.springframework.web.util.UriComponentsBuilder;

import java.io.UnsupportedEncodingException;
import java.net.URI;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * @author Administrator
 * @date 2019/10/9  11:52
 * 登陆接口默认添加clientid
 * 需要在网关进行配置对哪一个服务进行过滤
 */
@Component
@Slf4j
public class LoginParamFilter extends AbstractGatewayFilterFactory {

    @Autowired
    private ValueOperations<String,String> valueOperations;

    @Autowired
    private RedisTemplate redisTemplate;

    @Value("${tofly.client_Id:tofly}")
    private String client_Id;
    @Value("${tofly.client_secret:tofly}")
    private String client_secret;
    @Value("${tofly.grant_type:password}")
    private String grant_type;
    @Override
    public GatewayFilter apply(Object config) {
        return (exchange, chain) -> {
            ServerHttpRequest request = exchange.getRequest();
            // 不是登录请求，直接向下执行
//            if (!StringUtil.containsAnyIgnoreCase(request.getURI().getPath(), SecurityConstants.OAUTH_TOKEN_URL)) {
//                return chain.filter(exchange);
//            }
            //修改为oauth/login
            if (!StringUtil.containsAnyIgnoreCase(request.getURI().getPath(), SecurityConstants.OAUTH_LOGIN_URL)
                && !StringUtil.containsAnyIgnoreCase(request.getURI().getPath(), SecurityConstants.OAUTH_TOKEN_URL) ) {
                return chain.filter(exchange);
            }

            URI uri = exchange.getRequest().getURI();
            String queryParam = uri.getRawQuery();

            Map paramMap= getParameterMap(queryParam);
            if(StringUtil.isEmpty((String)paramMap.get("grant_type"))){
                paramMap.put("grant_type",grant_type);
            }
            if(StringUtil.isEmpty((String)paramMap.get("client_id"))){
                paramMap.put("client_id",client_Id);
            }
            if(StringUtil.isEmpty((String)paramMap.get("client_secret"))){
                paramMap.put("client_secret",client_secret);
            }

            String project = (String)paramMap.get("project");
            if(!StringUtil.isEmpty(project)){
                //valueOperations.set(SecurityConstants.REDIS_LOGIN_LOCK,project);
                tryLock(SecurityConstants.REDIS_LOGIN_LOCK, project);
                //redisTemplate.opsForValue().set(SecurityConstants.REDIS_LOGIN_LOCK,project);
//                Boolean success = redisTemplate.opsForValue().setIfAbsent(SecurityConstants.REDIS_LOGIN_LOCK, project,
//                        SecurityConstants.REDIS_LOCK_TIME, TimeUnit.MILLISECONDS);
//                while (!success){
//                    try {
//                        Thread.sleep(2000);
//                    } catch (InterruptedException e) {
//                        e.printStackTrace();
//                    }
//                    success = redisTemplate.opsForValue().setIfAbsent(SecurityConstants.REDIS_LOGIN_LOCK, project,
//                            SecurityConstants.REDIS_LOCK_TIME, TimeUnit.MILLISECONDS);
//                }
            }

            log.info("------------string paramMap:{}",HttpURL.asUrlParams(paramMap));
            URI newUri = UriComponentsBuilder.fromUri(uri)
                    .replacePath(SecurityConstants.OAUTH_TOKEN_URL)
                    .replaceQuery(HttpURL.asUrlParams(paramMap))
                    .build(true)
                    .toUri();

            ServerHttpRequest newRequest = exchange.getRequest().mutate().uri(newUri).build();
            return chain.filter(exchange.mutate().request(newRequest).build());
        };
    }

    public Boolean tryLock(String key, String value) {
        Long start = System.currentTimeMillis();
        try{
            Boolean ret=valueOperations.setIfAbsent(key, value, SecurityConstants.REDIS_LOCK_TIME, TimeUnit.MILLISECONDS);
            while (!ret){
                try {
                    Thread.sleep(1000);
                }catch (InterruptedException e) {
                        e.printStackTrace();
                }
                ret = valueOperations.setIfAbsent(key, value, SecurityConstants.REDIS_LOCK_TIME, TimeUnit.MILLISECONDS);
            }
            return true;

        }finally {
            valueOperations.setIfAbsent(key, value);
        }

    }


    private Map getParameterMap(String queryParam){
        Map<String, Object> map = new HashMap<String, Object>(0);
        if (StringUtil.isEmpty(queryParam)) {
            return map;
        }
        String[] params = queryParam.split("&");
        for (int i = 0; i < params.length; i++) {
            String[] p = params[i].split("=");
            if (p.length == 2) {
                map.put(p[0], p[1]);
            }
        }
        return map;
    }


    private  Map getParameterMap(ServerHttpRequest request) throws UnsupportedEncodingException {
        // 参数Map
        Map properties = request.getQueryParams();
        // 返回值Map
        Map returnMap = new HashMap();
        Iterator entries = properties.entrySet().iterator();
        Map.Entry entry;
        String name = "";
        String value = "";
        while (entries.hasNext()) {
            entry = (Map.Entry) entries.next();
            name = (String) entry.getKey();
            Object valueObj = entry.getValue();
            if(null == valueObj){
                value = "";
            }else if(valueObj instanceof String[]){
                String[] values = (String[])valueObj;
                for(int i=0;i<values.length;i++){
                    value = values[i] + ",";
                }
                value = value.substring(0, value.length()-1);
            }else{
                value = new String(valueObj.toString().getBytes("iso-8859-1"), "utf-8");

            }
            returnMap.put(name, value);
        }
        return returnMap;
    }
}
