package com.hotent.base.util;

import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.util.Iterator;

import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.fluent.Request;
import org.apache.http.entity.ContentType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.Assert;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.hotent.base.jwt.JwtTokenHandler;

public class FluentUtil {
	private final static int CONNECT_TIMEOUT = 30000;
	private final static int SOCKET_TIMEOUT = 30000;
	
	private final static Logger logger = LoggerFactory.getLogger(FluentUtil.class);

	/**
	 * get请求
	 * 
	 * @param url
	 * @return
	 * @throws ClientProtocolException
	 * @throws IOException
	 */
	public static String get(String url, String headerStr) throws ClientProtocolException, IOException {
		return get(url, headerStr, 0, 0);
	}

	public static String get(String url, String headerStr, int connectTimeout, int socketTimeout)
			throws ClientProtocolException, IOException {
		connectTimeout = connectTimeout > 0 ? connectTimeout : CONNECT_TIMEOUT;
		socketTimeout = socketTimeout > 0 ? socketTimeout : SOCKET_TIMEOUT;
		Request request = Request.Get(url);
		request = setHeaders(request, headerStr);
		HttpResponse returnResponse = request.connectTimeout(connectTimeout).socketTimeout(socketTimeout).execute()
				.returnResponse();
		return handleResponse(returnResponse);
	}

	/**
	 * post请求
	 * 
	 * @param url
	 * @return
	 * @throws ClientProtocolException
	 * @throws IOException
	 */
	public static String post(String url, String headerStr, Object params) throws ClientProtocolException, IOException {
		return post(url, headerStr, params, 0, 0);
	}
	
	public static String post(String url, String headerStr, Object params, ContentType contentType) throws ClientProtocolException, IOException {
		return post(url, headerStr, params, 0, 0, contentType);
	}
	
	private static String post(String url, String headerStr, Object params, int connectTimeout, int socketTimeout)
			throws ClientProtocolException, IOException {
		return post(url, headerStr, params, connectTimeout, socketTimeout, ContentType.APPLICATION_JSON);
	}

	private static String post(String url, String headerStr, Object params, int connectTimeout, int socketTimeout, ContentType contentType)
			throws ClientProtocolException, IOException {
		logger.debug("[Fluent Request]:" + url);
		connectTimeout = connectTimeout > 0 ? connectTimeout : CONNECT_TIMEOUT;
		socketTimeout = socketTimeout > 0 ? socketTimeout : SOCKET_TIMEOUT;

		Request request = Request.Post(url);
		request = setHeaders(request, headerStr);
		String paramStr = "";
		if(BeanUtils.isNotEmpty(params)){
			paramStr = JsonUtil.toJson(params);
		}
		HttpResponse returnResponse = request.bodyString(paramStr, contentType)
				.connectTimeout(connectTimeout).socketTimeout(socketTimeout).execute().returnResponse();
		return handleResponse(returnResponse);
	}

	@SuppressWarnings("rawtypes")
	private static Request setHeaders(Request request, String headerStr) {
		if (StringUtil.isNotEmpty(headerStr)) {
			try {
				headerStr = Base64.getFromBase64(headerStr);
				ObjectNode obj = (ObjectNode) JsonUtil.toJsonNode(headerStr);
				Iterator it = obj.fieldNames();
				while (it.hasNext()) {
					String key = (String) it.next();
					request.setHeader(key, obj.get(key).asText());
				}
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		return request;
	}

	/**
	 * 处理结果，状态不等于200，则解析异常内容，
	 * @param returnResponse
	 * @return
	 * @throws IOException
	 */
	private static String handleResponse(HttpResponse returnResponse) throws IOException {
		int statusCode = returnResponse.getStatusLine().getStatusCode();
		InputStream content = returnResponse.getEntity().getContent();
		String res = StringUtil.InputStreamToString(content);
		logger.debug("[Fluent Response]:" + res);
		if (statusCode != 200) {
			logger.error("[Fluent Response Error]:{}", res);
			JsonNode jsonNode = JsonUtil.toJsonNode(res);
			throw new RuntimeException(JsonUtil.getString(jsonNode, "message", res));
		}
		return res;
	}
	
	
	/**
	 *  采用http方式调用当前服务的接口。以免多线程获取当前用户有问题
	 * @param url
	 * @param account
	 * @return
	 * @throws ClientProtocolException
	 * @throws IOException
	 */
	public static String getCurAppInterfaceWithHttp(String url, String account) throws ClientProtocolException, IOException {
		return get(handleUrl(url), getAuthHeaderStr(account), 0, 0);
	}

	/**
	 * 采用http方式调用当前服务的接口。以免多线程获取当前用户有问题
	 * @param url
	 * @param account
	 * @return
	 * @throws ClientProtocolException
	 * @throws IOException
	 */
	public static String postCurAppInterfaceWithHttp(String url, String account, Object params) throws ClientProtocolException, IOException {
		return post(handleUrl(url), getAuthHeaderStr(account), params, 0, 0);
	}

	/**
	 * 判断是否为完整的请求地址。如果不完整则拼上当前服务的端口
	 * @param url
	 * @return
	 * @throws ClientProtocolException
	 * @throws IOException
	 */
	private static String handleUrl(String url)  {
		if (isHttpUrl(url)) {
			return url;
		}
		url = "http://localhost:" + AppUtil.getServerPort() + url;
		return url;
	}
	
	public static boolean isHttpUrl(String url) {
		Assert.notNull(url, "请求url不能为空");
		url = url.toLowerCase();
		String regex = "^((https|http|ftp|rtsp|mms)?://)" // https、http、ftp、rtsp、mms
				+ "?(([0-9a-z_!~*‘().&=+$%-]+: )?[0-9a-z_!~*‘().&=+$%-]+@)?" // ftp的user@
				+ "(([0-9]{1,3}\\.){3}[0-9]{1,3}" // IP形式的URL- 例如：199.194.52.184
				+ "|" // 允许IP和DOMAIN（域名）
				+ "([0-9a-z_!~*‘()-]+\\.)*" // 域名- www.
				+ "([0-9a-z][0-9a-z-]{0,61})?[0-9a-z]\\." // 二级域名
				+ "[a-z]{2,6})" // first level domain- .com or .museum
				+ "(:[0-9]{1,5})?" // 端口号最大为65535,5位数
				+ "((/?)|" // a slash isn‘t required if there is no file name
				+ "(/[0-9a-z_!~*‘().;?:@&=+$,%#-\\{\\}]+)+/?)$";
		return url.matches(regex);
	}
	
	
	/**
	 * 根据账号生成该账号用户的token
	 * @param account
	 * @return
	 * @throws UnsupportedEncodingException 
	 * @throws ClientProtocolException
	 * @throws IOException
	 */
	private static String getAuthHeaderStr(String account) throws UnsupportedEncodingException, IOException {
		JwtTokenHandler jwtTokenHandler = AppUtil.getBean(JwtTokenHandler.class);
		String generateToken = jwtTokenHandler.generateToken(account);
		ObjectNode objectNode = JsonUtil.getMapper().createObjectNode();
		objectNode.put("Authorization", "Bearer " + generateToken);
		return Base64.getBase64(JsonUtil.toJson(objectNode));
	}
}
