package com.github.ebnew.ki4so.core.service;

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

import org.apache.http.HttpEntity;
import org.apache.http.NameValuePair;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import org.apache.log4j.Logger;

import com.github.ebnew.ki4so.common.utils.StringUtils;
import com.github.ebnew.ki4so.core.app.App;
import com.github.ebnew.ki4so.core.app.AppService;
import com.github.ebnew.ki4so.core.authentication.status.UserLoggedStatus;
import com.github.ebnew.ki4so.core.authentication.status.UserLoggedStatusStore;
import com.github.ebnew.ki4so.web.utils.WebConstants;


/**
 * 统一登出服务
 * @author ywbrj042
 */
public class LogoutAppServiceImpl implements LogoutAppService {
	
	private static Logger logger = Logger.getLogger(LogoutAppServiceImpl.class);
	
	private static CloseableHttpClient httpClient = HttpClients.createDefault();  
	
	/**
	 * 默认请求失败重试次数。
	 */
	private static final int RETRY_TIMES = 3;
	
	private AppService appService;

	private UserLoggedStatusStore userLoggedStatusStore;
	
	public void setUserLoggedStatusStore(UserLoggedStatusStore userLoggedStatusStore) {
		this.userLoggedStatusStore = userLoggedStatusStore;
	}

	public void setAppService(AppService appService) {
		this.appService = appService;
	}
	
	/**
	 * 该方法主要是退出app
	 */
	@Override
	public void logoutApp(final String userId, final String service) {
		if(StringUtils.isEmpty(userId)){
			return;
		}
		
		//servie对应的app
		App app = null;
		//先查找service对应的应用登出地址。
		if(!StringUtils.isEmpty(service)){
			app = appService.findAppByHost(service);
			if(app!=null){
				String logoutUrl = app.getLogoutUrl();
				//登出service对应的应用。
				requestLogoutUrl(logoutUrl, userId);
			}
		}
		this.logoutAppsExcludeServiceApp(userId, app);
	}
	
	/**
	 * 请求登出URL地址。若登出失败则会自动重试
	 */
	protected void requestLogoutUrl(String url, String userId) {
		if(StringUtils.isEmpty(url)){
			return;
		}
		for(int i=0; i<RETRY_TIMES; i++){
			List<NameValuePair> nvps = new ArrayList<NameValuePair>();
			nvps.add(new BasicNameValuePair(WebConstants.USER_ID_PARAM_NAME, userId));
			try {
				String content = requestUrl(url, nvps);
				//当登出成功,则不再重试。
				if(!StringUtils.isEmpty(content)){
					logger.info("logout sucess ,the url is "+url);
					break;
				}
				logger.info(content);
			} catch (ClientProtocolException e) {
				logger.warn("request the url error", e);
			} catch (IOException e) {
				logger.warn("request the url error", e);
			}
		}
	}
	
	/**
	 * 请求某个URL,带着参数列表。
	 * @param url
	 * @param nameValuePairs
	 * @return
	 * @throws ClientProtocolException
	 * @throws IOException
	 */
	protected String requestUrl(String url, List<NameValuePair> nameValuePairs) throws ClientProtocolException, IOException {
		HttpPost httpPost = new HttpPost(url);
		if(nameValuePairs!=null && nameValuePairs.size()>0){
			httpPost.setEntity(new UrlEncodedFormEntity(nameValuePairs));
		}
		CloseableHttpResponse response = httpClient.execute(httpPost);  
		try {  
			if (response.getStatusLine().getStatusCode() == 200) {
				HttpEntity entity = response.getEntity();
				String content = EntityUtils.toString(entity);
				EntityUtils.consume(entity);
				return content;
			}
			else{
				logger.warn("request the url: "+url+" , but return the status code is "+response.getStatusLine().getStatusCode());
				return null;
			}
		}
		finally{
			response.close();
		}
	}
	
	/**
	 * 异步登出用户ID userId登录过的所有应用,排除app.
	 * @param userId 用户ID.
	 * @param serviceApp 要排除的app,该app已经登出过。
	 */
	protected void logoutAppsExcludeServiceApp(String userId, App serviceApp) {
		List<UserLoggedStatus> list = this.userLoggedStatusStore.findUserLoggedStatus(userId);
		//批量查询对应的应用信息。
		if(list!=null&& list.size()>0){
			for(UserLoggedStatus status:list){
				App app = appService.findAppById(status.getAppId());
				if(app!=null){
					//若该app已经登出过,则跳过。
					if(serviceApp!=null && serviceApp.getAppId().equals(app.getAppId())){
						continue;
					}
					String logoutUrl = app.getLogoutUrl();
					//登出service对应的应用。
					requestLogoutUrl(logoutUrl, userId);
				}
			}
		}
	}
}