package com.e6yun.project.sdk.api.core;

import com.e6yun.project.sdk.api.constant.CodeConstant;
import com.e6yun.project.sdk.api.exception.ApiException;
import com.e6yun.project.sdk.api.pojo.base.ApiResponse;
import com.e6yun.project.sdk.api.pojo.base.ResultApiResponse;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonSyntaxException;

import java.io.IOException;
import java.net.URISyntaxException;
import java.util.Date;
import java.util.Map;
import java.util.Objects;

/**
 * @author xuexiang@e6yun.com
 */
public class E6SdkCore extends E6SdkHttp {

    /**
     * 构造函数
     *
     * @param address
     * @param appKey
     * @param secretKey
     * @throws IllegalArgumentException
     */
    public E6SdkCore(String address, String appKey, String secretKey) throws IllegalArgumentException {
        super(address, appKey, secretKey);
    }

    /**
     * 校验返回结果是否成功
     * @param resultApiResponse
     * @throws ApiException
     */
    private void checkResultApiResponse(ResultApiResponse<?> resultApiResponse) throws ApiException {
        ApiResponse<?> apiResponse = resultApiResponse.getResult();
        if(Objects.isNull(apiResponse)){
            throw new ApiException(CodeConstant.SYSTEM_ERROR, "结果中缺少result字段");
        }
        Integer code = apiResponse.getCode();
        if(!Objects.equals(code, CodeConstant.SUCCESS)){
            throw new ApiException(apiResponse.getCode(), apiResponse.getMessage());
        }
    }

    /**
     * 校验返回结果是否成功
     * @param apiResponse
     * @throws ApiException
     */
    private void checkApiResponse(ApiResponse<?> apiResponse) throws ApiException {
        Integer code = apiResponse.getCode();
        if(!Objects.equals(code, CodeConstant.SUCCESS)){
            throw new ApiException(apiResponse.getCode(), apiResponse.getMessage());
        }
    }

    private <T extends ResultApiResponse> T callResult(String path, Map<String, String> param, Class<T> clazz, ApiRequest apiRequest) throws ApiException {
        try {
            String result = apiRequest.apply(path, param);
            Gson gson = new GsonBuilder().registerTypeAdapter(Date.class, new DateGson()).create();
            T object = gson.fromJson(result, clazz);
            checkResultApiResponse(object);
            return object;
        } catch (IOException | URISyntaxException | JsonSyntaxException e) {
            throw new ApiException(CodeConstant.SYSTEM_ERROR, "接口调用失败", e);
        }
    }

    protected <T extends ResultApiResponse> T callPostResult(String path, Map<String, String> param, Class<T> clazz) throws ApiException {
        return this.callResult(path, param, clazz, ((path1, param1) -> {
            return this.postFormBody(path1, param1);
        }));
    }

    protected <T extends ResultApiResponse> T callGetResult(String path, Map<String, String> param, Class<T> clazz) throws ApiException {
        return this.callResult(path, param, clazz, ((path1, param1) -> {
            return this.get(path1, param1);
        }));
    }

    private <T extends ApiResponse> T call(String path, Map<String, String> param, Class<T> clazz, ApiRequest apiRequest) throws ApiException {
        try {
            String result = apiRequest.apply(path, param);
            Gson gson = new GsonBuilder().registerTypeAdapter(Date.class, new DateGson()).create();
            T object = gson.fromJson(result, clazz);
            checkApiResponse(object);
            return object;
        } catch (IOException | URISyntaxException | JsonSyntaxException e) {
            throw new ApiException(CodeConstant.SYSTEM_ERROR, "接口调用失败", e);
        }
    }

    protected <T extends ApiResponse> T callPost(String path, Map<String, String> param, Class<T> clazz) throws ApiException {
        return this.call(path, param, clazz, ((path1, param1) -> {
            return this.postFormBody(path1, param1);
        }));
    }

    protected <T extends ApiResponse> T callGet(String path, Map<String, String> param, Class<T> clazz) throws ApiException {
        return this.call(path, param, clazz, ((path1, param1) -> {
            return this.get(path1, param1);
        }));
    }

    private <T extends ApiResponse> T callJson(String path, Object paramRequestBody, Map<String, String> paramQueryString, Class<T> clazz, ApiRequestJson apiRequestJson) throws ApiException {
        try {
            String result = apiRequestJson.apply(path, paramRequestBody, paramQueryString);
            Gson gson = new GsonBuilder().registerTypeAdapter(Date.class, new DateGson()).create();
            T object = gson.fromJson(result, clazz);
            checkApiResponse(object);
            return object;
        } catch (IOException | URISyntaxException | JsonSyntaxException e) {
            throw new ApiException(CodeConstant.SYSTEM_ERROR, "接口调用失败", e);
        }
    }
    
    protected <T extends ApiResponse> T callPostJson(String path, Object paramRequestBody, Map<String, String> paramQueryString, Class<T> clazz) throws ApiException {
        return this.callJson(path, paramRequestBody, paramQueryString, clazz, ((path1, paramRequestBody1, paramQueryString1) -> {
            return this.postJsonBody(path1, paramRequestBody1, paramQueryString1);
        }));
    }

}
