package com.boco.nbd.wios.manage.call;

import com.boco.nbd.cams.core.constant.CamsConstant;
import com.boco.nbd.wios.manage.contants.InterfaceAddrConstant;
import com.ihidea.component.api.json.MJSONResultEntity;
import com.ihidea.core.support.SpringContextLoader;
import com.ihidea.core.support.exception.ServiceException;
import com.ihidea.core.support.pageLimit.PageLimit;
import com.ihidea.core.support.pageLimit.PageLimitHolderFilter;
import com.ihidea.core.util.HttpClientUtils;
import com.ihidea.core.util.JSONUtilsEx;
import java.util.Collections;
import org.apache.commons.lang.StringUtils;
import org.apache.http.Header;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 内部系统api接口抽象类,父类定义执行流程(共性)并提供模板方法(差异)供子类实现
 *
 * @author lilin
 * @version [4.0.0, 2017年7月1日]
 */
public abstract class AbstractInnerApi implements InnerApi {

    private Logger logger = LoggerFactory.getLogger(getClass());

    private static final String HTML = "<html>";
    private static final String SERVICE = "Service";
    private static final String BAD = "Bad";
    private static final String OK = "200";


    /**
     * 网关代理方法,传入调用方法名和参数,获取调用后的结果
     *
     * @param url      接口名称或地址
     * @param paramMap 参数Map
     * @param headers  消息头
     * @return 接口返回值
     */
    @Override
    public Object gatewayAgent(String url, Map<String, String> paramMap, Header... headers) {
        // 取分页参数
        PageLimit pl = PageLimitHolderFilter.getContext();
        // 分页参数不为空、允许分页、未曾分页过
        if (pl != null && pl.limited() && !pl.isLimited()) {
            if (paramMap == null) {
                paramMap = new HashMap<>(8);
            }
            paramMap.put("page", String.valueOf(pl.getCurrentPageNo()));
            paramMap.put("pagecount", String.valueOf(pl.getPageLength()));
            // 设置已经分页,后续操作不用再次分页
            pl.setLimited(true);
        }
        return getResult(url, paramMap, headers);
    }

    /**
     * 网关代理方法,传入调用方法名和参数,获取调用后的结果(单对象)
     *
     * @param url      接口名称或地址
     * @param paramMap 参数Map
     * @param clazz    返回的class类型
     * @param headers  消息头
     * @param <T>      返回类型
     * @return 接口返回值
     */
    @Override
    public <T> T gatewayAgent(String url, Map<String, String> paramMap, Class<T> clazz, Header... headers) {
        Object resultData = gatewayAgent(url, paramMap, headers);
        if (resultData == null) {
            return null;
        }
        String jsonStr = JSONUtilsEx.serialize(resultData);
        return JSONUtilsEx.deserialize(jsonStr, clazz);
    }

    /**
     * 网关代理方法,传入调用方法名和参数,获取调用后的结果(对象数组)
     *
     * @param url      接口名称或地址
     * @param paramMap 参数Map
     * @param clazz    返回的class类型
     * @param headers  消息头
     * @param <T>      返回类型
     * @return 接口返回值
     */
    @Override
    public <T> List<T> gatewayAgentList(String url, Map<String, String> paramMap, Class<T> clazz, Header... headers) {
        Object resultData = gatewayAgent(url, paramMap, headers);
        if (resultData == null) {
            return Collections.emptyList();
        }
        String jsonStr = JSONUtilsEx.serialize(resultData);

        return JSONUtilsEx.deserializeList(jsonStr, clazz);
    }

    /**
     * 获取远程调用数据,定义默认方法(子类有不同可重写)
     *
     * @param url      接口名称或地址
     * @param paramMap 参数Map
     * @param headers  消息头
     * @return 接口返回值
     */
    protected Object getResult(String url, Map<String, String> paramMap, Header... headers) {
        Class<? extends AbstractInnerApi> clz = this.getClass();
        // 获取component注解
        Component component = clz.getAnnotation(Component.class);
        String cValue = component.value();
        // 获取bean
        InterfaceAddrConstant constant = SpringContextLoader.getBean(InterfaceAddrConstant.class);
        int systemType = Integer.parseInt(cValue.split("\\.")[1]);
        String interfaceUrl = constant.getArr(systemType);

        long startTime = System.currentTimeMillis();
        String jsonStr = HttpClientUtils.post(interfaceUrl + '/' + url, paramMap, CamsConstant.UTF_8);

        logger.info("请求第三方地址:{},接口:{},耗时:{},参数:{},消息头:{},返回数据:{}", interfaceUrl, url, (System.currentTimeMillis() - startTime) + "ms", paramMap, headers,
                (jsonStr.length() > 2000 ? jsonStr.substring(0, 2000) : jsonStr));
        if (StringUtils.isBlank(jsonStr) || jsonStr.contains(HTML) || jsonStr.startsWith(SERVICE) || jsonStr.startsWith(BAD)) {
            throw new ServiceException("服务器无法访问");
        }

        MJSONResultEntity result = MJSONResultEntity.deserialize(jsonStr);
        if (!OK.equals(result.getCode())) {
            throw new ServiceException(result.getCode(), result.getText());
        }
        return result.getData();
    }

}