/**
 * Copyright 2008-2009. Chongqing Communications Industry Services Co.,Ltd Information Technology Branch. All rights reserved. <a>http://www.crunii.com</a>
 */
package com.crunii.micro.common.utils;

import com.crunii.micro.common.constants.CommonConstants;
import com.crunii.micro.common.exception.MicroException;
import org.apache.http.NameValuePair;
import org.apache.http.client.utils.URLEncodedUtils;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.util.ObjectUtils;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.nio.charset.Charset;
import java.util.*;

/**
 * @author 田平 create 2020年1月16日下午3:00:31
 */
public class BusiLogUtil {

	private static final String DEFAULT_ENCODING = "UTF-8";

	private static final List<MediaType> VISIBLE_TYPES = Arrays.asList(
			MediaType.valueOf("text/*"),
			MediaType.valueOf("application/*+json"),
			MediaType.valueOf("application/*+xml"),
			MediaType.APPLICATION_FORM_URLENCODED,
			MediaType.APPLICATION_JSON,
			MediaType.APPLICATION_XML);

	public static boolean checkContentType(MediaType mediaType) {
		if (mediaType == null) {
			return true;
		} else {
			return VISIBLE_TYPES.stream().anyMatch(visibleType -> visibleType.includes(mediaType));
		}
	}

	public static boolean checkContentType(String contentType) {
		if (ObjectUtils.isEmpty(contentType)) {
			return true;
		} else {
			MediaType mediaType = MediaType.valueOf(contentType);
			return VISIBLE_TYPES.stream().anyMatch(visibleType -> visibleType.includes(mediaType));
		}
	}

	public static String getServerAddr(HttpServletRequest request, int port) {
		return request.getScheme() + "://" + IPUtil.getIP() + ":" + port + request.getRequestURI();
	}

	public static String getServerAddr(ServerHttpRequest request, int port) {
		return request.getURI().getScheme() + "://" + IPUtil.getIP() + ":" + port + request.getPath().pathWithinApplication();
	}

	public static String getEncoding(String origin) {
		if (origin == null) {
			return DEFAULT_ENCODING;
		} else {
			return origin;
		}
	}

	public static void setResponseBase(Map<String, Object> data, HttpServletResponse response) {
		int status = response.getStatus();
		HttpStatus hs = HttpStatus.valueOf(status);
		data.put("status", hs.toString());
		data.put("headers", getHeaders(response));
	}

	public static void setRequestBase(Map<String, Object> data, HttpServletRequest request) {
		Map<String, String> headers = getHeaders(request);
		String queryString = request.getQueryString();
		String encode = getEncoding(request.getCharacterEncoding());
		List<NameValuePair> nameValues = URLEncodedUtils.parse(queryString, Charset.forName(encode));
		data.put("headers", headers);
		data.put("queryParams", nameValues);
		data.put("method", request.getMethod());
		data.put("uri", request.getRequestURI());
	}

	public static Map<String, String> getHeaders(HttpServletRequest request) {
		Enumeration<String> headers = request.getHeaderNames();
		Map<String, String> m = new HashMap<>(16);
		while (headers.hasMoreElements()) {
			String h = headers.nextElement();
			m.put(h, request.getHeader(h));
		}
		return m;
	}

	public static Map<String, String> getHeaders(HttpServletResponse response) {
		Collection<String> headers = response.getHeaderNames();
		Map<String, String> m = new HashMap<>(headers.size());
		for (String header : headers) {
			m.put(header, response.getHeader(header));
		}
		m.put("Content-Type", response.getContentType());
		return m;
	}

	public static void setResponseBase(Map<String, Object> data, ServerHttpResponse response) {
		data.put("headers", response.getHeaders());
		data.put("status", response.getStatusCode().toString());
	}

	public static void setRequestBase(Map<String, Object> data, ServerHttpRequest request) {
		data.put("queryParams", request.getQueryParams());
		data.put("headers", request.getHeaders());
		data.put("method", request.getMethod());
		data.put("uri", request.getURI());
	}

	public static void setSendAndRecv(Map<String, Object> busiInfo, Map<String, Object> sendData, Map<String, Object> recvData) {
		busiInfo.put("sendData", JsonUtil.getJsonString(sendData));
		busiInfo.put("recvData", JsonUtil.getJsonString(recvData));
	}

	public static void setErrorMsg(Map<String, Object> busiInfo, Throwable e) {
		busiInfo.put("errorMsg", MicroException.getErrorMsg(e));
		busiInfo.put("callResult", CommonConstants.RESULT_FAILURE);
	}

	public static void setBusiData(Map<String, Object> busiInfo, Map<String, Object> busiData) {
		if (busiData != null) {
			busiInfo.putAll(busiData);
		}
	}

	public static void setCallResult(Map<String, Object> busiInfo, int status) {
		if (status >= 200 && status < 300) {
			busiInfo.put("callResult", CommonConstants.RESULT_SUCCESS);
		} else {
			busiInfo.put("callResult", CommonConstants.RESULT_FAILURE);
		}
	}

	public static void setUseTime(Map<String, Object> busiInfo) {
		if (busiInfo.get("useTime") == null) {
			Date callTime = (Date) busiInfo.computeIfAbsent("callTime", key -> new Date());
			busiInfo.put("useTime", System.currentTimeMillis() - callTime.getTime());
		}
	}

}
