package gov.va.med.mpn.auth.web;

import gov.va.med.mpn.auth.controller.AuthorizationController;
import gov.va.med.mpn.auth.utils.AuthUtils;

import java.io.IOException;
import java.util.Enumeration;
import java.util.List;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import javax.ws.rs.core.HttpHeaders;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.filter.OncePerRequestFilter;

import com.agilex.healthcare.mobilehealthplatform.security.AppUser;

/**
 * The Class CustomOAuthClientFilter. THis filter wrappers each request 
 * extending Spring's OncePerRequestFilter and adds the logged in
 * user's access token to the Request Header (Authorization)
 * ex Authorization: Bearer "token"
 * <p>
 * <A HREF="http://www.hp.com"> Hewlett-Packard Enterprise Services</A>
 * </p>
 * 
 * @author <a href="mailto:david.aar.lucas@hp.com">Aaron Lucas</a> 
 * 
 * @see OncePerRequestFilter
 */
public class CustomOAuthClientFilter extends OncePerRequestFilter {

	/** The token prefix. */
	private final String TOKEN_PREFIX = "Bearer ";
	private final String DISPLAYNAME_HEADER = "mpn-displayname";
	private final String STATION_HEADER = "mpn-station";
	private final String MPN_ROLES = "mpn-roles";
	private final String MPN_USERNAME = "mpn-username";
	
	/** The logger. */
	private final Logger logger = LoggerFactory
			.getLogger(CustomOAuthClientFilter.class);

	/* (non-Javadoc)
	 * @see org.springframework.web.filter.OncePerRequestFilter#doFilterInternal(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse, javax.servlet.FilterChain)
	 */
	@Override
	protected void doFilterInternal(HttpServletRequest req,
			HttpServletResponse resp, FilterChain chain)
			throws ServletException, IOException {
		logger.debug("CustomOAuthClientFilter.doFilter() triggered.");
		CustomServletRequestWrapper request = new CustomServletRequestWrapper(
				(HttpServletRequest) req);
		HttpSession session = request.getSession();
		
		
		//log the cookies for debugging
		if(logger.isDebugEnabled()){
			logger.debug("cookies...");
			Cookie[] cookies = request.getCookies();
			if (cookies == null) {
				logger.info("Cookies not set.");
			} 
			
			//Commented out else clause to prevent Log Forging attack, because cookie values
			//are being written to the log.
//			else {
				// get cookie --COOKIE NAME--
//				for (int i = 0; i < cookies.length; i++) {
//					logger.debug(cookies[i].getName() + " : " + cookies[i].getValue());
//				}
//			}
		}
		//log the session attributes for debugging
		if(logger.isDebugEnabled()) {
			logger.debug("session attributes...");
			for (Enumeration e = session.getAttributeNames(); e.hasMoreElements(); ) {     
			    String attribName = (String) e.nextElement();
			    Object attribValue = session.getAttribute(attribName);
			    logger.debug("{}::{}",attribName,attribValue);
			}
		}
		
		String accessToken = 
			session.getAttribute(AuthorizationController.TOKEN_SESSION_ATTTRIBUTE) == null
			? null
			: session.getAttribute(AuthorizationController.TOKEN_SESSION_ATTTRIBUTE).toString();
		
		if (StringUtils.isNotEmpty(accessToken)) {
			logger.debug("Setting Headers...");				
			
			Authentication token = SecurityContextHolder.getContext().getAuthentication();
			
			if(token != null) {
				//OAuth Access token
				request.addHeader(HttpHeaders.AUTHORIZATION, TOKEN_PREFIX + accessToken);
				
				//add username
				request.addHeader(
						MPN_USERNAME, 
						AuthUtils.getUsername(
								(AppUser)token.getPrincipal()));	
				
				//add display name
				request.addHeader(
						DISPLAYNAME_HEADER, 
						AuthUtils.getUserDisplayName(
								(AppUser)token.getPrincipal()));	
				
				//add orbeon roles
				List<String> roles = AuthUtils.getAuthoritiesList(token);
				request.addHeader(
						MPN_ROLES, 
						StringUtils.join(roles,","));
				
				//add station
				request.addHeader(
						STATION_HEADER, 
						AuthUtils.getUserStation(
								(AppUser)token.getPrincipal()));
			}
			else {
				logger.debug("Token not set");
			}
		}
		
		logger.debug("AuthenticationFilter.doFilter() finished.");
		//request headers for debugging
		
		//Commented out to prevent Log Forging attack, because request header values
		//are being written to the log.
//		if(logger.isDebugEnabled())
//		{
//			Enumeration e = request.getHeaderNames();
//			while(e.hasMoreElements())
//			{
//				String name = e.nextElement().toString();
//				logger.debug("Request Header name: {}, request header value: {}",name, request.getHeader(name));
//			}
//		}
		
		chain.doFilter(request, resp);
	}
}
