package com.reyun.security.interceptor;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.reyun.model.Account;
import com.reyun.model.App;
import com.reyun.repository.AccountRepository;
import com.reyun.repository.AppRepository;
import com.reyun.security.RedisLoginStatusManager;
import com.reyun.security.TokenManager;
import com.reyun.service.AuthService;
import com.reyun.util.Constant;
import com.reyun.util.DateUtil;
import com.reyun.util.ResultModel;
import com.reyun.util.ResultStatus;
import com.reyun.util.StringUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import java.io.BufferedWriter;
import java.io.OutputStreamWriter;
import java.lang.reflect.Method;
import java.util.Date;

public class AuthorizationInterceptor extends HandlerInterceptorAdapter {
    private static final Logger logger = LoggerFactory.getLogger(AuthorizationInterceptor.class);

    /**
     * 存放登录用户模型Key的Request Key
     */
    public static final String REQUEST_CURRENT_KEY = "REQUEST_CURRENT_KEY";

    //管理身份验证操作的对象
    @Autowired
    private TokenManager manager;
    @Autowired
    private AccountRepository accountRepository;
    @Autowired
    private AuthService authService;
    @Autowired
    private RedisLoginStatusManager redisLoginStatusManager;
    @Autowired
    private AppRepository appRepository;

    //存放鉴权信息的Header名称，默认是Authorization
    public static String httpHeaderName = "Authorization";

    //鉴权信息的无用前缀，默认为空
    private String httpHeaderPrefix = "";

    public void setManager(TokenManager manager) {
        this.manager = manager;
    }

    public void setHttpHeaderName(String httpHeaderName) {
        this.httpHeaderName = httpHeaderName;
    }

    public void setHttpHeaderPrefix(String httpHeaderPrefix) {
        this.httpHeaderPrefix = httpHeaderPrefix;
    }

    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
    	try {
			//如果不是映射到方法直接通过
    		if (!(handler instanceof HandlerMethod)) {
    			return true;
    		}
    		//放开登录,第三方下载,注册,短信验证码
    		if (request.getRequestURL().indexOf("login/login") != -1
    				|| request.getRequestURL().indexOf("login/loginweb") != -1
    				|| request.getRequestURL().indexOf("login/getvalidcode") != -1
    				|| request.getRequestURL().indexOf("external/download") != -1
					|| request.getRequestURL().indexOf("openapi/toutiao") != -1
//					|| request.getRequestURL().indexOf("event/find") != -1
					|| request.getRequestURI().endsWith("event/find4tracking")
    				|| request.getRequestURI().startsWith("/api/reged")
    				|| request.getRequestURI().startsWith("/api/demo")
					|| request.getRequestURI().startsWith("/api/messagecode")
					|| request.getRequestURI().startsWith("/api/report/all/home")){
				System.out.println(request.getRequestURI());
				return true;
    		}

    		HandlerMethod handlerMethod = (HandlerMethod) handler;
    		Method method = handlerMethod.getMethod();

    		//从header中得到token
    		String token = request.getHeader(httpHeaderName);
            token = StringUtil.isEmpty(token) ? getCookieToken(request.getCookies(), "TOKEN") : token;

    		if (token != null && token.startsWith(httpHeaderPrefix) && token.length() > 0) {

    			token = token.substring(httpHeaderPrefix.length());
    			//验证token
    			String key = manager.getKeyFromToken(token);
                //登陆状态
                boolean loginStatus = redisLoginStatusManager.getLoginStatusByKey(token);

    			if (!StringUtil.isEmpty(key)) {

    				Account account = accountRepository.findOne(Long.parseLong(key));
                    //加上密码校验
                    if (account == null || !redisLoginStatusManager.validateLoginPassword(token, account.getPassword(), loginStatus)) {

    					BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(response.getOutputStream()));
    					response.setContentType(MediaType.APPLICATION_JSON_VALUE);
                        request.getSession().removeAttribute(Constant.CURRENT_ACCOUNT);
                        manager.delRelationshipByToken(token);
                        redisLoginStatusManager.deleteLoginStatus(token);
    					String json = new ObjectMapper().writeValueAsString(ResultModel.ERROR(ResultStatus.USERNAME_LOGIN_EXPIRE));
    					writer.write(json);
    					writer.close();
    					return false;
    				}
					if (account.getPricelevel() != 6) {
						boolean isVerify = true;
						//2. 帐户过期验证
						if (request.getRequestURL().indexOf("login/logout") == -1
								&& request.getRequestURL().indexOf("tip") == -1
								&& request.getRequestURL().indexOf("notice") == -1
								&& request.getRequestURL().indexOf("account/detail") == -1
								&& request.getRequestURL().indexOf("account/updatePwd") == -1
								&& request.getRequestURL().indexOf("account/updateBase") == -1) {

							Account verifyAct = account;
							if(!account.getIsSuperUser()){
								verifyAct = accountRepository.findOne(account.getParent());
							}
							if (verifyAct.getStatus() != 1
									|| (!StringUtil.isEmpty(verifyAct.getPastDate())
									&& DateUtil.compare_date(DateUtil.format(new Date(), DateUtil.C_DATE_PATTON_DEFAULT), verifyAct.getPastDate()) == 1))
								isVerify = false;

							if(!isVerify){
								BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(response.getOutputStream()));
								response.setContentType(MediaType.APPLICATION_JSON_VALUE);
								request.getSession().removeAttribute(Constant.CURRENT_ACCOUNT);
								manager.delRelationshipByToken(token);
								redisLoginStatusManager.deleteLoginStatus(token);
								String json = new ObjectMapper().writeValueAsString(ResultModel.ERROR(ResultStatus.ACCOUNT_BUSINESS_EXPIRE));
								writer.write(json);
								writer.close();
								return false;
							}
						}
					}


    				//3. 子帐号权限验证

    				//如果token验证成功，将token对应的用户id存在request中，便于之后注入
    				//TODO 暂时用于解决下载时前端无法传递token的问题
    				Account sessionAct = (Account) request.getSession().getAttribute(Constant.CURRENT_ACCOUNT);
    				if (sessionAct == null || !account.getId().equals(sessionAct.getId())) {
                        Account sessionAccount =  authService.getSubAccountAuthById(account.getId());
                        sessionAccount.setIsMasterLogin(loginStatus);
                        request.getSession().setAttribute(Constant.CURRENT_ACCOUNT,sessionAccount);
                    }
    				//校验母账号删除app，子账号还能看的问题
    				if (needAppDelFilter(request.getRequestURL().toString())) {
    					String lastApp = getCookieToken(request.getCookies(), "ryioLastApp");
    					if (!StringUtil.isEmpty(lastApp)) {
    						App app = appRepository.findOne(Long.parseLong(lastApp));
    						if (app==null || (app!=null && app.getDelFlag())) {
    							Cookie cookie = new Cookie("ryioLastApp",null);
    				            cookie.setPath("/");
    				            cookie.setMaxAge(0);
    				            response.addCookie(cookie);
    							BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(response.getOutputStream()));
    							response.setContentType(MediaType.APPLICATION_JSON_VALUE);
    							String json = new ObjectMapper().writeValueAsString(ResultModel.ERROR(ResultStatus.APP_DEL));
    							writer.write(json);
    							writer.close();
    							return false;
    						}

							/**
							 *此处限制了渠道帐号，但是应该只限制此渠道帐号下的一个app即可
							 */
							/* else if (account.getIsChannelPerson() && authService.isOriginAccountPast(app.getAccount())) {
    							BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(response.getOutputStream()));
    							response.setContentType(MediaType.APPLICATION_JSON_VALUE);
    							String json = new ObjectMapper().writeValueAsString(ResultModel.ERROR(ResultStatus.AUTH_ACCOUNT_BUSINESS_EXPIRE));
    							writer.write(json);
    							writer.close();
    							return false;
    						}*/
    					}
    				}
                    //延长cookie
                    Cookie cookie = new Cookie("TOKEN",token);
					cookie.setDomain("trackingio.com");
                    cookie.setMaxAge(3600*24*7);
                    cookie.setPath("/");
                    response.addCookie(cookie);
    				return true;
    			}
    		}

    		//如果验证token失败，并且方法注明了Authorization，返回401错误
    		response.setStatus(HttpStatus.UNAUTHORIZED.value());
    		BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(response.getOutputStream()));
    		response.setContentType(MediaType.APPLICATION_JSON_VALUE);
    		String json = new ObjectMapper().writeValueAsString(ResultModel.ERROR(ResultStatus.USERNAME_LOGIN_EXPIRE));
    		writer.write(json);
    		writer.close();
    		return false;

        } catch (Exception e) {
    		e.printStackTrace();
    	}
    	return false;
    }
    
    private boolean needAuthFilter(String url) {
    	if (url.indexOf("login") != -1
        		|| url.indexOf("logout") != -1
                || url.indexOf("external/download") != -1
                || url.startsWith("/api/reged")
                || url.startsWith("/api/demo")
                || url.indexOf("tip") != -1
				|| url.indexOf("notice") != -1) {
            return false;
        }
    	return true;
    }
    
    private boolean needAppDelFilter(String url) {
    	if (url.indexOf("login") != -1
        		|| url.indexOf("logout") != -1
                || url.indexOf("external/download") != -1
                || url.startsWith("/api/reged")
                || url.startsWith("/api/demo")
                || url.startsWith("api/app")
                || url.startsWith("api/mng/auth")
                || url.startsWith("api/mng/channel")
                || url.indexOf("tip") != -1
				|| url.indexOf("notice") != -1) {
            return false;
        }
    	return true;
    }

    private String getCookieToken(Cookie[] cookies, String name){

        String token = null;

        if (null != cookies) {
            for (Cookie cookie : cookies) {
                if (cookie.getName().equals(name)) {
                    token = cookie.getValue();
                }
            }
        }

        return token;
    }
}