package com.imooc.utils;

import java.util.Map;
import java.util.Optional;
import java.util.function.Consumer;
import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import org.apache.commons.lang3.StringUtils;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Component;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;
import net.sf.json.JSONObject;
import static com.imooc.utils.CommonUtil.isEmpty;
import static com.imooc.utils.CommonUtil.getUrlParamStr;

/**
 * RestTemplate工具类
 * 
 * @version 1.0.0
 * @author Leon
 *
 */
@Component
public final class RestTemplateUtil {

	private static RestTemplate TEMPLATE;

	private static RestTemplate TEMPLATE_IGNORE_SSL;

	@Resource(name = "restTemplate")
	private RestTemplate restTemplate;

	@Resource(name = "restTemplateIgnoreSSL")
	private RestTemplate restTemplateIgnoreSSL;

	private RestTemplateUtil() {
	}

	@PostConstruct
	private void init() {
		TEMPLATE = this.restTemplate;
		TEMPLATE_IGNORE_SSL = this.restTemplateIgnoreSSL;
	}

	/**
	 * GET请求
	 * 
	 * @param <T>
	 * @param mediaType
	 * @param headerHandler
	 * @param headerData
	 * @param url
	 * @param param
	 * @param valueType
	 * @param responseHandler
	 */
	public static <T> void get(MediaType mediaType, Consumer<HttpHeaders> headerHandler, Map<String, String> headerData,
			String url, Map<String, String> param, Class<T> valueType, Consumer<ResponseEntity<T>> responseHandler) {
		HttpHeaders headers = new HttpHeaders();
		Optional.ofNullable(mediaType).ifPresent(t -> headers.setContentType(t));
		// 请求头信息
		buildHttpHeaders(headers, headerHandler, headerData);
		// 构建请求
		HttpEntity<T> entity = new HttpEntity<>(headers);
		ResponseEntity<T> responseEntity = buildRestTemplate(url).exchange(buildUrl(url, param), HttpMethod.GET, entity,
				valueType);
		// 处理响应
		responseHandler(responseEntity, responseHandler);
	}

	/**
	 * POST请求
	 * 
	 * @param <T>
	 * @param mediaType
	 * @param headerHandler
	 * @param headerData
	 * @param url
	 * @param param
	 * @param valueType
	 * @param responseHandler
	 */
	public static <T> void post(MediaType mediaType, Consumer<HttpHeaders> headerHandler,
			Map<String, String> headerData, String url, JSONObject param, Class<T> valueType,
			Consumer<ResponseEntity<T>> responseHandler) {
		HttpHeaders headers = new HttpHeaders();
		if (mediaType == null) {
			headers.setContentType(MediaType.APPLICATION_JSON);
		} else {
			headers.setContentType(mediaType);
		}
		// 请求头信息
		buildHttpHeaders(headers, headerHandler, headerData);
		// 构建请求
		HttpEntity<JSONObject> entity = new HttpEntity<>(param, headers);
		ResponseEntity<T> responseEntity = buildRestTemplate(url).exchange(url, HttpMethod.POST, entity, valueType);
		// 处理响应
		responseHandler(responseEntity, responseHandler);
	}

	/**
	 * POST请求
	 * 
	 * @param <T>
	 * @param mediaType
	 * @param headerHandler
	 * @param headerData
	 * @param url
	 * @param param
	 * @param valueType
	 * @param responseHandler
	 */
	public static <T> void post(MediaType mediaType, Consumer<HttpHeaders> headerHandler,
			Map<String, String> headerData, String url, MultiValueMap<String, Object> param, Class<T> valueType,
			Consumer<ResponseEntity<T>> responseHandler) {
		HttpHeaders headers = new HttpHeaders();
		if (mediaType == null) {
			headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
		} else {
			headers.setContentType(mediaType);
		}
		// 请求头信息
		buildHttpHeaders(headers, headerHandler, headerData);
		// 构建请求
		HttpEntity<MultiValueMap<String, Object>> entity = new HttpEntity<>(param, headers);
		ResponseEntity<T> responseEntity = buildRestTemplate(url).postForEntity(url, entity, valueType);
		// 处理响应
		responseHandler(responseEntity, responseHandler);
	}

	/**
	 * PUT请求
	 * 
	 * @param <T>
	 * @param headerHandler
	 * @param headerData
	 * @param url
	 * @param jsonBody
	 * @param valueType
	 * @param responseHandler
	 */
	public static <T> void put(Consumer<HttpHeaders> headerHandler, Map<String, String> headerData, String url,
			String jsonBody, Class<T> valueType, Consumer<ResponseEntity<T>> responseHandler) {
		HttpHeaders headers = new HttpHeaders();
		headers.setContentType(MediaType.APPLICATION_JSON);
		// 请求头信息
		buildHttpHeaders(headers, headerHandler, headerData);
		// 构建请求
		HttpEntity<String> entity = new HttpEntity<>(jsonBody, headers);
		ResponseEntity<T> responseEntity = buildRestTemplate(url).exchange(url, HttpMethod.PUT, entity, valueType);
		// 处理响应
		responseHandler(responseEntity, responseHandler);
	}

	/**
	 * 构建请求模板
	 * 
	 * @param ssl
	 * @return
	 */
	private static RestTemplate buildRestTemplate(String url) {
		boolean ssl = StringUtils.startsWithIgnoreCase(url, "https");
		return ssl ? TEMPLATE_IGNORE_SSL : TEMPLATE;
	}

	/**
	 * 构建请求头信息
	 * 
	 * @param headers
	 * @param headerHandler
	 * @param headerData
	 */
	private static void buildHttpHeaders(HttpHeaders headers, Consumer<HttpHeaders> headerHandler,
			Map<String, String> headerData) {
		Optional.ofNullable(headerHandler).ifPresent(t -> t.accept(headers));
		if (!isEmpty(headerData)) {
			headerData.forEach((k, v) -> headers.add(k, v));
		}
	}

	/**
	 * 构建请求url
	 * 
	 * @param url
	 * @param param
	 * @return
	 */
	private static String buildUrl(String url, Map<String, String> param) {
		if (isEmpty(param)) {
			return url;
		}
		String paramStr = getUrlParamStr(param);
		return url + "?" + paramStr;
	}

	/**
	 * 响应处理
	 * 
	 * @param <T>
	 * @param responseEntity
	 * @param responseHandler
	 */
	private static <T> void responseHandler(ResponseEntity<T> responseEntity,
			Consumer<ResponseEntity<T>> responseHandler) {
		Optional.ofNullable(responseHandler).ifPresent(t -> t.accept(responseEntity));
	}
}
