package com.uas.platform.b2b.filter;

import java.io.IOException;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.mobile.device.Device;
import org.springframework.mobile.device.DeviceResolver;
import org.springframework.mobile.device.LiteDeviceResolver;
import org.springframework.mobile.device.site.SitePreference;
import org.springframework.security.access.SecurityMetadataSource;
import org.springframework.security.access.intercept.AbstractSecurityInterceptor;
import org.springframework.security.access.intercept.InterceptorStatusToken;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.RememberMeAuthenticationToken;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.web.FilterInvocation;
import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource;
import org.springframework.security.web.context.HttpSessionSecurityContextRepository;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import com.uas.platform.b2b.model.Enterprise;
import com.uas.platform.b2b.model.ResourceItem;
import com.uas.platform.b2b.model.Role;
import com.uas.platform.b2b.model.SigninLog;
import com.uas.platform.b2b.model.User;
import com.uas.platform.b2b.service.EnterpriseService;
import com.uas.platform.b2b.service.RoleService;
import com.uas.platform.b2b.service.SigninLogService;
import com.uas.platform.b2b.service.UserService;
import com.uas.platform.b2b.support.SecurityConstant;
import com.uas.platform.b2b.support.SystemSession;
import com.uas.platform.b2b.support.TrustedAuthenticationToken;
import com.uas.platform.b2b.support.UserCreater;
import com.uas.platform.core.model.Constant;
import com.uas.platform.core.util.AgentUtils;
import com.uas.platform.core.util.encry.Md5Utils;

/**
 * @date 2016年8月31日上午10:55:13
 *       <p>
 *       切换到单点登录
 *       </p>
 * @author yingp
 */
@Deprecated
public class SecurityInterceptor extends AbstractSecurityInterceptor implements Filter {

	private FilterInvocationSecurityMetadataSource securityMetadataSource;

	private final static String tokenParam = "access_token";
	private final static String typeParam = "client_type";

	@Autowired
	@Qualifier("org.springframework.security.authenticationManager")
	protected AuthenticationManager authenticationManager;

	@Autowired
	private UserService userService;

	@Autowired
	private SigninLogService signinLogService;

	@Autowired
	private EnterpriseService enterpriseService;

	@Autowired
	private RoleService roleService;

	private final DeviceResolver deviceResolver;

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

	public SecurityInterceptor() {
		this.deviceResolver = new LiteDeviceResolver();
	}

	/**
	 * @param request
	 * @param response
	 * @param chain
	 * @throws IOException
	 * @throws ServletException
	 */
	@Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
		HttpServletRequest httpRequest = (HttpServletRequest) request;
		HttpServletResponse httpResponse = (HttpServletResponse) response;
		clearSession();
		// 账号密码自动登录
		autoLogin(httpRequest);
		// access_token验证登录
		logSession(httpRequest);
		User user = SystemSession.getUser();
		// 判断session的用户信息是否与Authentication一致
		if (user == null) {// 未登录则要求登录
			if (!SecurityConstant.AUTHENTICATION_URL.equals(httpRequest.getServletPath())) {
				if (httpRequest.getHeader("Accept").contains("application/json")) {
                    httpResponse.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
                } else {
                    httpResponse.sendRedirect(httpRequest.getContextPath() + SecurityConstant.LOGIN_URL);
                }
			}
			return;
		}
		Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
		if (authentication != null && authentication.isAuthenticated()
				&& !authentication.getName().equals(String.valueOf(user.getUserUU()))) {// 用户信息与Authentication不一致
			logger.error(String.format("用户信息%s@%s与Authentication信息%s@%s不一致", user.getUserUU(), user.getIp(), authentication.getName(),
					AgentUtils.getIp(httpRequest)));
			clearSession();
			if (httpRequest.getContentType().contains("application/json")) {
                httpResponse.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
            } else {
                httpResponse.sendRedirect(httpRequest.getContextPath() + SecurityConstant.LOGIN_URL);
            }
			return;
		}
		if (user.isSys()) {// 超级用户无需验证权限
			chain.doFilter(request, response);
			clearSession();
			return;
		}
		invoke(new FilterInvocation(request, response, chain));
		clearSession();
	}

	public void invoke(FilterInvocation filter) throws IOException, ServletException {
		InterceptorStatusToken token = super.beforeInvocation(filter);
		try {
			filter.getChain().doFilter(filter.getRequest(), filter.getResponse());
		} finally {
			super.afterInvocation(token, null);
		}
	}

	/**  
     *   
     */
	@Override
    public void destroy() {
	}

	/**
	 * @return
	 */
	@Override
	public Class<? extends Object> getSecureObjectClass() {
		return FilterInvocation.class;
	}

	/**
	 * @return
	 */
	@Override
	public SecurityMetadataSource obtainSecurityMetadataSource() {
		return this.securityMetadataSource;
	}

	public void setSecurityMetadataSource(FilterInvocationSecurityMetadataSource securityMetadataSource) {
		this.securityMetadataSource = securityMetadataSource;
	}

	@Override
    public void init(FilterConfig filterConfig) throws ServletException {

	}

	/**
	 * 将user信息放在当前线程里面
	 * 
	 * @param request
	 */
	private void logSession(HttpServletRequest request) {
		Object user = request.getSession().getAttribute("user");
		if (user != null) {
            SystemSession.setUser((User) user);
        } else {// login by remember-me
				// spring remember-me通过客户端的SPRING_SECURITY_REMEMBER_ME_COOKIE和数据库的PERSISTENT_LOGINS匹配
			Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
			if (authentication != null && authentication.isAuthenticated()
					&& RememberMeAuthenticationToken.class.isAssignableFrom(authentication.getClass())) {
				User authedUser = loginByRememberMe(request, authentication);
				request.getSession().setAttribute("user", authedUser);
				SystemSession.setUser(authedUser);
			}
		}
	}

	/**
	 * spring remember-me验证通过之后的登录处理
	 * 
	 * @param request
	 * @param authentication
	 * @return
	 */
	private User loginByRememberMe(HttpServletRequest request, Authentication authentication) {
		User authedUser = userService.findUserByUserUU(Long.parseLong(authentication.getName()));
		if (authedUser.getEnterprises().size() > 1) {
			SigninLog log = signinLogService.findLast(authedUser.getUserUU());
			authedUser.setCurrentEnterprise(log.getEnUU());
		} else {
            authedUser.setCurrentEnterprise();
        }
		Set<Role> roles = authedUser.getRoles();
		if (!authedUser.isSys() && !CollectionUtils.isEmpty(roles)) {
			for (Role role : roles) {
				if (role.isSys()) {// 超级账号
					authedUser.setIssys(Constant.YES);
					break;
				}
			}
		}
		authedUser.setIp(AgentUtils.getIp(request));
		// 记录登录日志
		SitePreference preference = getDefaultSitePreferenceForDevice(this.deviceResolver.resolveDevice(request));
		signinLogService.save(new SigninLog(authedUser, preference, true));
		return authedUser;
	}

	private SitePreference getDefaultSitePreferenceForDevice(Device device) {
		if (device == null) {
			return null;
		}
		if (device.isMobile()) {
			return SitePreference.MOBILE;
		}
		if (device.isTablet()) {
			return SitePreference.TABLET;
		}
		return SitePreference.NORMAL;
	}

	/**
	 * 线程池策略下，不会频繁删除线程，置于线程内的对象须手动删除
	 */
	private void clearSession() {
		SystemSession.clear();
	}

	static final String TEL_REGEXP = "^((\\(\\d{3}\\))|(\\d{3}\\-))?(13|15|18)\\d{9}$";

	static final String UU_REGEXP = "^\\d{4,}$";

	static final String ROLE_USER = "ROLE_USER";

	/**
	 * 自动登录
	 */
	private void autoLogin(HttpServletRequest request) {
		String enUU = request.getParameter("b_enuu");
		String username = request.getParameter("b_username");
		String password = request.getParameter("b_password");
		if (StringUtils.hasText(username) && StringUtils.hasText(password)) {
			User user = null;
			if (username.contains("@")) { // 邮箱登录
				user = userService.findUserByUserEmail(username);
			} else if (username.matches(TEL_REGEXP)) {// 手机号登录
				user = userService.findUserByUserTel(username);
			} else if (username.matches(UU_REGEXP)) {
				user = userService.findUserByUserUU(Long.parseLong(username));
			}
			if (user != null && user.getUserPwd().equals(Md5Utils.encode(password, user.getUserUU()))) {
				Collection<GrantedAuthority> array = getGrantedAuthorities(user);
				UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(user.getUserUU(), password, array);
				Authentication authenticatedUser = authenticationManager.authenticate(token);
				SecurityContextHolder.getContext().setAuthentication(authenticatedUser);
				request.getSession().setAttribute(HttpSessionSecurityContextRepository.SPRING_SECURITY_CONTEXT_KEY,
						SecurityContextHolder.getContext());
				if (enUU != null) {
                    checkEnterprise(user, enUU);
                } else {
                    user.setCurrentEnterprise();
                }
				user.setIp(AgentUtils.getIp(request));
				request.getSession().setAttribute("user", user);
			} else {
                throw new UsernameNotFoundException(username + " 账号或密码错误");
            }
		}
	}

	private void checkEnterprise(User user, String enUU) {
		boolean choosed = false;
		for (Enterprise enterprise : user.getEnterprises()) {
			if (enterprise.getUu().toString().equals(enUU)) {
				user.setEnterprise(enterprise);
				choosed = true;
				break;
			}
		}
		if (!choosed) {
            throw new UsernameNotFoundException("企业与用户不匹配");
        }
	}

	private Set<GrantedAuthority> getGrantedAuthorities(User user) {
		Set<GrantedAuthority> authSet = new HashSet<GrantedAuthority>();
		Set<Role> roles = user.getRoles();
		if (!CollectionUtils.isEmpty(roles)) {
			for (Role role : roles) {
				if (role.isSys()) {// 超级账号
					user.setIssys(Constant.YES);
					break;
				}
				Set<ResourceItem> resourceItems = role.getResourceItems();
				if (!CollectionUtils.isEmpty(resourceItems)) {
					for (ResourceItem res : resourceItems) {
						authSet.add(new SimpleGrantedAuthority(res.getName()));
					}
				}
			}
		}
		return authSet;
	}

}
