package com.bcxin.ins.aspect;

import com.bcxin.ins.rest.UserSupportUtil;
import com.bcxin.ins.spring.annotation.LoginRequired;
import com.bcxin.ins.spring.cache.CacheUtils;
import com.bcxin.ins.spring.util.JedisUtils;
import com.bcxin.ins.util.Constant;
import com.bcxin.ins.util.DSUtil;
import com.bcxin.ins.vo.ClientUserVo;
import com.bcxin.ins.vo.ConstProp;
import com.bcxin.mybatisplus.toolkit.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

/**
 * 登录验证切面拦截
 * @author hzp
 * @date 2018/06/08
 */
@Aspect
@Component
public class LoginRequiredAspect {

    private static final Logger logger = LoggerFactory.getLogger(LoginRequiredAspect.class);

    public LoginRequiredAspect() {
        System.out.println("初始化登录拦截切面 LoginRequiredAspect=======================");
    }

    /**
     * Controller层切点
     */
    @Pointcut("@annotation(com.bcxin.ins.spring.annotation.LoginRequired)")
    public void controllerAspect() {
    }


    /**
     * 环绕通知
     * @param point
     * @return
     */
    @Around("controllerAspect()")
    public Object doAroundController(ProceedingJoinPoint point) {
        Object result = null;
        try {
            ClientUserVo userDetail = UserSupportUtil.getSessionUser();
            if (userDetail != null) {
                return point.proceed();
            }
            //获取request
            HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
            Map<String, Object> map = new HashMap<String, Object>();
            Map<String, Object> kv = new HashMap<String, Object>();
            String targetName = point.getTarget().getClass().getName();
            String methodName = point.getSignature().getName();
            Object[] arguments = point.getArgs();
            Class targetClass = Class.forName(targetName);
            Method[] methods = targetClass.getMethods();
            for (Method method : methods) {
                if (!method.getName().equals(methodName)) {
                    continue;
                }
                Class[] clazz = method.getParameterTypes();
                if (clazz.length != arguments.length) {
                    continue;
                }
                map.put("isRedirect", method.getAnnotation(LoginRequired.class).isRedirect());
                map.put("redirectUrl", method.getAnnotation(LoginRequired.class).redirectUrl());

                //需要从方法体获取参数值
                String [] methodParamKey=method.getAnnotation(LoginRequired.class).methodParamKey();
                for(String k : methodParamKey){
                    String keyIndex=k.split(ConstProp.POUND_SIGN)[0];
                    String key=k.split(ConstProp.POUND_SIGN)[1];
                    Object ats = arguments[Integer.parseInt(keyIndex)];
                    if(ats != null){
                        String keyValue=arguments[Integer.parseInt(keyIndex)].toString();
                        kv.put(key,keyValue);
                    }
                }

                //需要从request获取参数值
                String [] requestParamKey=method.getAnnotation(LoginRequired.class).requestParamKey();
                for(String k : requestParamKey){
                    String keyValue=request.getParameter(k)!=null ? request.getParameter(k).toString() : ConstProp.BLANK_CHAR;
                    kv.put(k,keyValue);
                }
                break;
            }
            String url=this.getRedirectUrl(map,kv);
            return new ModelAndView(url);
        } catch (Exception e) {
            e.printStackTrace();
            logger.error(e.toString());
        } catch (Throwable throwable) {
            throwable.printStackTrace();
            logger.error(throwable.toString());
        }
        return result;
    }

    /**
     * 验证是否是微信浏览器
     * @return
     */
    private boolean checkWeiXin() {
        //获取request
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        String userAgent = request.getHeader("user-agent").toLowerCase();
        //微信客户端
        if (userAgent.indexOf("micromessenger") > -1) {
            return true;
        } else {
            return false;
        }
    }

    /**
     * 获取需要转发的url
     * @param map
     * @param kv 需要被替换的kv值
     * @return
     */
    private String getRedirectUrl(Map<String, Object> map,Map<String, Object> kv) {
        if (!map.containsKey("isRedirect") || !"true".equals(map.get("isRedirect").toString().toLowerCase())) {
            return "";
        }
        String url = map.containsKey("redirectUrl") ? map.get("redirectUrl").toString() : "";
        //如果是第三方平台，特殊处理情况
        String token = getToken();
        if(StringUtils.isNotEmpty(token)) {
            String platformFlag = JedisUtils.get(CacheUtils.THIRD_PLATFORM_FLAG+token);
            logger.info("第三方平台标识{}",new Object[]{platformFlag});
            if (StringUtils.isNotEmpty(platformFlag) && !"BLB".equalsIgnoreCase(platformFlag)) {
                //第三方平台
                return "forward:/synopsis/loseView";
            }
        }

        if(StringUtils.isEmpty(url)){
            return Constant.LOGIN_URL_COM;
        }

        //包含redirect: forward: 直接做跳转，不需要增加Constant.LOGIN_URL
        if (!(url.contains("redirect:") || url.contains("forward:"))) {
            if(checkWeiXin()) {
                //TODO 暂时不用处理
            }else{
//                url = Constant.LOGIN_URL + url;
                url = DSUtil.operation() + url;
            }
        }
        //url替换对应的key
        for(String key : kv.keySet()){
            url=url.replace("{"+key+"}",kv.get(key).toString());
        }
        return url;
    }

    /**
     * 获取cookies
     * @param name
     * @return
     */
    public static Cookie getCookieByName(String name) {
        //获取request
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        Map<String, Cookie> cookieMap = ReadCookieMap(request);
        if (cookieMap.containsKey(name)) {
            Cookie cookie = (Cookie) cookieMap.get(name);
            return cookie;
        } else {
            return null;
        }
    }

    public static String getToken() {
        //获取request
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        String access_token = request.getParameter("ACCESS_TOKEN");
        if(StringUtils.isEmpty(access_token)){
            String referer_url = request.getHeader("Referer");
            if(StringUtils.isNotEmpty(referer_url)&&referer_url.contains("ACCESS_TOKEN=")&&!referer_url.endsWith("ACCESS_TOKEN=")){
                String x_at = referer_url.split("ACCESS_TOKEN=")[1];
                if(x_at.length()==32){
                    access_token = x_at;
                }else if(x_at.length()>32){
                    access_token = x_at.substring(0,32);
                }
            }
        }
        return access_token;
    }

    /**
     * 将cookie封装到Map里面
     *
     * @param request
     * @return
     */
    private static Map<String, Cookie> ReadCookieMap(HttpServletRequest request) {
        Map<String, Cookie> cookieMap = new HashMap<String, Cookie>();
        Cookie[] cookies = request.getCookies();
        if (null != cookies) {
            for (Cookie cookie : cookies) {
                cookieMap.put(cookie.getName(), cookie);
            }
        }
        return cookieMap;
    }
}
