/** 
 * Copyright 2018-2028 Akaxin Group
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License. 
 */
package com.windchat.im.business.impl.tai;

import java.util.Base64;
import java.util.List;
import java.util.Map;

//import org.apache.commons.codec.binary.Base64;
import com.windchat.im.business.dao.SitePluginDao;
import com.windchat.im.business.impl.AbstractRequest;
import com.windchat.im.business.impl.site.SiteConfig;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.windchat.common.command.Command;
import com.windchat.common.command.CommandResponse;
import com.windchat.common.constant.CharsetCoding;
import com.windchat.common.constant.CommandConst;
import com.windchat.common.constant.ErrorCode2;
import com.windchat.common.constant.IErrorCode;
import com.windchat.common.crypto.AESCrypto;
import com.windchat.common.exceptions.ZalyException2;
import com.windchat.common.http.ZalyHttpClient;
import com.windchat.common.logs.LogUtils;
import com.akaxin.proto.core.CoreProto;
import com.akaxin.proto.core.PluginProto;
import com.akaxin.proto.site.ApiPluginListProto;
import com.akaxin.proto.site.ApiPluginPageProto;
import com.akaxin.proto.site.ApiPluginProxyProto;
import com.windchat.im.business.dao.SitePluginDao;
import com.windchat.im.business.impl.AbstractRequest;
import com.windchat.im.business.impl.site.SiteConfig;
import com.windchat.im.storage.bean.PluginBean;
import com.google.protobuf.ByteString;

/**
 * 处理客户端与服务点扩展之间功能
 * 
 * @author Sam{@link an.guoyue254@gmail.com}
 * @since 2017-12-11 14:46:28
 */
public class ApiPluginService extends AbstractRequest {
	private static Logger logger = LoggerFactory.getLogger(ApiPluginService.class);
	private static final String HTTP_PREFFIX = "http://";
	private static final String HTTPS_PREFFIX = "https://";

	/**
	 * 分页获取扩展列表
	 * 
	 * @param command
	 * @return
	 */
	public CommandResponse list(Command command) {
		CommandResponse commandResponse = new CommandResponse().setAction(CommandConst.ACTION_RES);
		IErrorCode errCode = ErrorCode2.ERROR;
		try {
			ApiPluginListProto.ApiPluginListRequest request = ApiPluginListProto.ApiPluginListRequest
					.parseFrom(command.getParams());
			String siteUserId = command.getSiteUserId();
			String sessionId = command.getHeader().get(CoreProto.HeaderKey.CLIENT_SOCKET_SITE_SESSION_ID_VALUE);
			int pageNumber = request.getPageNumber();
			int pageSize = request.getPageSize();
			PluginProto.PluginPosition position = request.getPosition();
			LogUtils.requestDebugLog(logger, command, request.toString());

			pageNumber = Math.max(pageNumber, 1);// 从第一页开始

			// 支持首页以及消息聊天界面扩展
			if (PluginProto.PluginPosition.HOME_PAGE != position && PluginProto.PluginPosition.MSG_PAGE != position) {
				throw new ZalyException2(ErrorCode2.ERROR2_PLUGIN_STATUS);
			}

			List<PluginBean> pluginList = null;
			if (StringUtils.isNotBlank(siteUserId) && SiteConfig.isSiteManager(siteUserId)) {
				pluginList = SitePluginDao.getInstance().getAdminPluginPageList(pageNumber, pageSize,
						position.getNumber());
			} else {
				pluginList = SitePluginDao.getInstance().getOrdinaryPluginPageList(pageNumber, pageSize,
						position.getNumber());
			}

			if (pluginList != null) {
				ApiPluginListProto.ApiPluginListResponse.Builder responseBuilder = ApiPluginListProto.ApiPluginListResponse
						.newBuilder();
				for (PluginBean bean : pluginList) {
					PluginProto.Plugin.Builder pluginBuilder = getPluginProtoBuilder(bean);

					String authKey = bean.getAuthKey();
					if (StringUtils.isNotEmpty(authKey)) {
						byte[] tsk = bean.getAuthKey().getBytes(CharsetCoding.ISO_8859_1);
						byte[] encryptedSessionId = AESCrypto.encrypt(tsk,
								sessionId.getBytes(CharsetCoding.ISO_8859_1));
						String base64UrlSafeSessionId = Base64.getUrlEncoder().encodeToString(encryptedSessionId);
						pluginBuilder.setEncryptedSessionIdBase64(base64UrlSafeSessionId);
					}
					responseBuilder.addPlugin(pluginBuilder.build());
				}
				commandResponse.setParams(responseBuilder.build().toByteArray());
				errCode = ErrorCode2.SUCCESS;
			}

		} catch (Exception e) {
			errCode = ErrorCode2.ERROR_SYSTEMERROR;
			LogUtils.requestErrorLog(logger, command, e);
		} catch (ZalyException2 e) {
			errCode = e.getErrCode();
			LogUtils.requestErrorLog(logger, command, e);
		}
		return commandResponse.setErrCode(errCode);
	}

	/**
	 * <pre>
	 * 获取插件扩展的展示页面,支持两种方式
	 * 	1.非加密方式，此时扩展authkey不存在
	 *  2.加密方式，此时扩展authkey存在
	 * </pre>
	 * 
	 * @param command
	 * @return
	 */
	public CommandResponse page(Command command) {
		CommandResponse commandResponse = new CommandResponse().setAction(CommandConst.ACTION_RES);
		ErrorCode2 errCode = ErrorCode2.ERROR;
		try {
			ApiPluginPageProto.ApiPluginPageRequest request = ApiPluginPageProto.ApiPluginPageRequest
					.parseFrom(command.getParams());
			String siteUserId = command.getSiteUserId();
			String pluginId = request.getPluginId();
			String requestPage = request.getPage();// /index || index.php || index.html
			String requestParams = request.getParams();
			LogUtils.requestDebugLog(logger, command, request.toString());

			Map<Integer, String> header = command.getHeader();
			String siteSessionId = header.get(CoreProto.HeaderKey.CLIENT_SOCKET_SITE_SESSION_ID_VALUE);
			String pluginRefere = header.get(CoreProto.HeaderKey.PLUGIN_CLIENT_REFERER_VALUE);
			if (StringUtils.isNoneEmpty(siteUserId, pluginId)) {
				PluginBean bean = SitePluginDao.getInstance().getPluginProfile(Integer.valueOf(pluginId));
				if (bean != null && bean.getApiUrl() != null) {
					String pageUrl = buildUrl(bean.getApiUrl(), requestPage, bean.getUrlPage());
					logger.debug("http request uri={}", pageUrl);

					PluginProto.ProxyPluginPackage.Builder packageBuilder = PluginProto.ProxyPluginPackage.newBuilder();
					packageBuilder.putPluginHeader(PluginProto.PluginHeaderKey.CLIENT_SITE_USER_ID_VALUE, siteUserId);
					packageBuilder.putPluginHeader(PluginProto.PluginHeaderKey.CLIENT_SITE_SESSION_ID_VALUE,
							siteSessionId);
					packageBuilder.putPluginHeader(PluginProto.PluginHeaderKey.PLUGIN_ID_VALUE, pluginId);
					packageBuilder.putPluginHeader(PluginProto.PluginHeaderKey.PLUGIN_TIMESTAMP_VALUE,
							String.valueOf(System.currentTimeMillis()));
					if (StringUtils.isNotEmpty(pluginRefere)) {
						packageBuilder.putPluginHeader(PluginProto.PluginHeaderKey.PLUGIN_REFERER_VALUE, pluginRefere);
					}
					if (StringUtils.isNotEmpty(requestParams)) {
						packageBuilder.setData(requestParams);
					}

					byte[] httpContent = packageBuilder.build().toByteArray();
					String authKey = bean.getAuthKey();
					if (StringUtils.isNotEmpty(authKey)) {
						// AES 加密整个proto，通过http传输给plugin
						byte[] tsk = bean.getAuthKey().getBytes(CharsetCoding.ISO_8859_1);
						byte[] enPostContent = AESCrypto.encrypt(tsk, httpContent);
						httpContent = enPostContent;
					}

					byte[] httpResponse = ZalyHttpClient.getInstance().postBytes(pageUrl, httpContent);
					if (httpResponse != null) {
						ApiPluginProxyProto.ApiPluginProxyResponse response = ApiPluginProxyProto.ApiPluginProxyResponse
								.newBuilder().setData(ByteString.copyFrom(httpResponse)).build();

						commandResponse.setParams(response.toByteArray());
						errCode = ErrorCode2.SUCCESS;
					} else {
						logger.error("http request uri={} response={}", pageUrl, httpResponse);
					}
				}
			} else {
				errCode = ErrorCode2.ERROR_PARAMETER;
			}
		} catch (Exception e) {
			errCode = ErrorCode2.ERROR_SYSTEMERROR;
			LogUtils.requestErrorLog(logger, command, e);
		}
		return commandResponse.setErrCode2(errCode);
	}

	/**
	 * <pre>
	 * 	代理前台客户端中扩展的请求
	 * 		1.界面请求后台一般使用http请求
	 * 		2.使用tcp代理，代替http请求
	 * </pre>
	 * 
	 * @param command
	 * @return
	 */
	public CommandResponse proxy(Command command) {
		CommandResponse commandResponse = new CommandResponse().setAction(CommandConst.ACTION_RES);
		ErrorCode2 errCode = ErrorCode2.ERROR;
		try {
			ApiPluginProxyProto.ApiPluginProxyRequest request = ApiPluginProxyProto.ApiPluginProxyRequest
					.parseFrom(command.getParams());
			String siteUserId = command.getSiteUserId();
			String pluginId = request.getPluginId();
			String requestApi = request.getApi();
			String requestParams = request.getParams();
			LogUtils.requestDebugLog(logger, command, request.toString());

			Map<Integer, String> header = command.getHeader();
			String siteSessionId = header.get(CoreProto.HeaderKey.CLIENT_SOCKET_SITE_SESSION_ID_VALUE);
			String pluginRefere = header.get(CoreProto.HeaderKey.PLUGIN_CLIENT_REFERER_VALUE);

			if (!StringUtils.isAnyBlank(siteUserId, pluginId, requestApi)) {
				PluginBean bean = SitePluginDao.getInstance().getPluginProfile(Integer.valueOf(pluginId));
				if (bean != null && bean.getApiUrl() != null) {
					String pluginUrl = this.buildUrl(bean.getApiUrl(), requestApi, null);
					logger.debug("action={} pluginId={} api={} url={} params={}", command.getAction(), pluginId,
							requestApi, pluginUrl, requestParams);

					PluginProto.ProxyPluginPackage.Builder packageBuilder = PluginProto.ProxyPluginPackage.newBuilder();
					packageBuilder.putPluginHeader(PluginProto.PluginHeaderKey.CLIENT_SITE_USER_ID_VALUE, siteUserId);
					packageBuilder.putPluginHeader(PluginProto.PluginHeaderKey.CLIENT_SITE_SESSION_ID_VALUE,
							siteSessionId);
					packageBuilder.putPluginHeader(PluginProto.PluginHeaderKey.PLUGIN_ID_VALUE, pluginId);
					packageBuilder.putPluginHeader(PluginProto.PluginHeaderKey.PLUGIN_TIMESTAMP_VALUE,
							String.valueOf(System.currentTimeMillis()));
					if (StringUtils.isNotEmpty(pluginRefere)) {
						packageBuilder.putPluginHeader(PluginProto.PluginHeaderKey.PLUGIN_REFERER_VALUE, pluginRefere);
					}
					if (StringUtils.isNotEmpty(requestParams)) {
						packageBuilder.setData(requestParams);
					}

					byte[] httpContent = packageBuilder.build().toByteArray();
					String authKey = bean.getAuthKey();
					if (StringUtils.isNotEmpty(authKey)) {
						// AES 加密整个proto，通过http传输给plugin
						// byte[] tsk = AESCrypto.generateTSKey(bean.getAuthKey());
						byte[] tsk = bean.getAuthKey().getBytes(CharsetCoding.ISO_8859_1);
						byte[] enPostContent = AESCrypto.encrypt(tsk, httpContent);
						httpContent = enPostContent;
					}

					byte[] httpResponse = ZalyHttpClient.getInstance().postBytes(pluginUrl, httpContent);
					if (httpResponse != null) {
						ApiPluginProxyProto.ApiPluginProxyResponse response = ApiPluginProxyProto.ApiPluginProxyResponse
								.newBuilder().setData(ByteString.copyFrom(httpResponse)).build();
						commandResponse.setParams(response.toByteArray());// httpResposne,callback方法的回调方法参数
					}
					errCode = ErrorCode2.SUCCESS;
				}
			} else {
				errCode = ErrorCode2.ERROR_PARAMETER;
			}
		} catch (Exception e) {
			errCode = ErrorCode2.ERROR_SYSTEMERROR;
			LogUtils.requestErrorLog(logger, command, e);
		}
		return commandResponse.setErrCode2(errCode);
	}

	private PluginProto.Plugin.Builder getPluginProtoBuilder(PluginBean bean) {
		PluginProto.Plugin.Builder pluginBuilder = PluginProto.Plugin.newBuilder();
		pluginBuilder.setId(String.valueOf(bean.getId()));
		if (StringUtils.isNotBlank(bean.getName())) {
			pluginBuilder.setName(bean.getName());
		}
		if (StringUtils.isNotBlank(bean.getIcon())) {
			pluginBuilder.setIcon(bean.getIcon());
		}
		if (StringUtils.isNotBlank(bean.getUrlPage())) {
			pluginBuilder.setUrlPage(bean.getUrlPage());
		}
		if (StringUtils.isNotBlank(bean.getApiUrl())) {
			pluginBuilder.setApiUrl(bean.getApiUrl());
		}
		if (StringUtils.isNotBlank(bean.getAuthKey())) {
			pluginBuilder.setAuthKey(bean.getAuthKey());
		}
		if (StringUtils.isNotBlank(bean.getAllowedIp())) {
			pluginBuilder.setAllowedIp(bean.getAllowedIp());
		}
		pluginBuilder.setOrder(bean.getSort());
		pluginBuilder.setPositionValue(bean.getPosition());
		pluginBuilder.setPermissionStatusValue(bean.getPermissionStatus());
		pluginBuilder.setDisplayModeValue(bean.getDisplayMode());
		// pluginBuilder.setEncryptedSessionIdBase64(value)
		return pluginBuilder;
	}

	private String buildUrl(String apiUrl, String apiName, String defaultPage) {
		String pageUrl = HTTP_PREFFIX;
		if (apiUrl.startsWith(HTTP_PREFFIX) || apiUrl.startsWith(HTTPS_PREFFIX)) {
			pageUrl = apiUrl;
		} else {
			pageUrl += apiUrl;
		}
		if (StringUtils.isNotEmpty(apiName)) {
			if (apiName.startsWith("/")) {
				pageUrl += apiName;
			} else {
				pageUrl += "/" + apiName;
			}
		} else {
			if (StringUtils.isNotEmpty(defaultPage)) {
				if (defaultPage.startsWith("/")) {
					pageUrl += defaultPage;
				} else {
					pageUrl += "/" + defaultPage;
				}
			}
		}
		return pageUrl;
	}

}
