package cn.quantgroup.customer.service.http;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.http.*;
import org.springframework.stereotype.Component;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.HttpClientErrorException;
import org.springframework.web.client.RestTemplate;

import java.util.Map;
import java.util.Objects;

/**
 * 这是基于 RestTemplate 实现的 ,兼容之前的接口
 *
 * @author Jie.Feng
 * @date 2017/12/13
 */
@Slf4j
@Component
public class RestTemplateServiceImpl implements IHttpService {

    private static final String LEFT_BRACES = "{", RIGHT_BRACES = "}", Q_MARK = "?";

    @Autowired
    @Qualifier("commonRestTemplate")
    private RestTemplate restTemplate;


    @Override
    public RestTemplate restTemplate() {
        return restTemplate;
    }

    @Override
    public String get(String uri) {
        ResponseEntity<String> entity = restTemplate.getForEntity(uri, String.class);
        if (entity.getStatusCode().is2xxSuccessful()) {
            return entity.getBody();
        }
        throw new HttpClientErrorException(entity.getStatusCode());
    }

    @Override
    public <T> T get(String uri, Class<T> clazz) {
        ResponseEntity<T> entity = restTemplate.getForEntity(uri, clazz);
        if (entity.getStatusCode().is2xxSuccessful()) {
            return entity.getBody();
        }
        throw new HttpClientErrorException(entity.getStatusCode());
    }

    @Override
    public String get(String uri, Map<String, ?> parameters) {
        ResponseEntity<String> entity = restTemplate.getForEntity(buildUrl(uri, parameters), String.class, parameters);
        if (entity.getStatusCode().is2xxSuccessful()) {
            return entity.getBody();
        }
        throw new HttpClientErrorException(entity.getStatusCode());
    }

    private String buildUrl(String uri, Map<String, ?> parameters) {
        StringBuilder builder = new StringBuilder(uri);
        if (!parameters.isEmpty()) {
            if (uri.indexOf(LEFT_BRACES) > 0 && uri.indexOf(RIGHT_BRACES) > 0) {
                //存在匹配不进行处理
            } else {
                if (uri.indexOf(Q_MARK) == -1) {
                    builder.append(Q_MARK);
                } else if (!uri.endsWith(Q_MARK)) {
                    builder.append("&");
                }
                int i = 0, j = parameters.keySet().size();
                for (String s : parameters.keySet()) {
                    builder.append(s).append("=").append(LEFT_BRACES).append(s).append(RIGHT_BRACES);
                    i++;
                    if (j != i) {
                        builder.append("&");
                    }
                }
            }
        }
        return builder.toString();
    }

    @Override
    public byte[] getByte(String uri, Map<String, String> hs, Map<String, ?> parameters) {
        HttpHeaders headers = new HttpHeaders();
        hs.forEach((k, v) -> {
            headers.add(k, v);
        });
        HttpEntity<?> en = new HttpEntity<>(headers);
        ResponseEntity<byte[]> entity = restTemplate.exchange(buildUrl(uri, parameters), HttpMethod.GET, en, byte[].class, parameters);
        if (entity.getStatusCode().is2xxSuccessful()) {
            return entity.getBody();
        }
        throw new HttpClientErrorException(entity.getStatusCode());
    }

    @Override
    public String get(String uri, Map<String, String> hs, Map<String, ?> parameters) {
        HttpHeaders headers = new HttpHeaders();
        hs.forEach((k, v) -> {
            headers.add(k, v);
        });
        HttpEntity<?> en = new HttpEntity<>(headers);
        ResponseEntity<String> entity = restTemplate.exchange(buildUrl(uri, parameters), HttpMethod.GET, en, String.class, parameters);
        if (entity.getStatusCode().is2xxSuccessful()) {
            return entity.getBody();
        }
        throw new HttpClientErrorException(entity.getStatusCode());
    }

    @Override
    public String post(String uri) {
        ResponseEntity<String> entity = restTemplate.postForEntity(uri, null, String.class);
        if (entity.getStatusCode().is2xxSuccessful()) {
            return entity.getBody();
        }
        throw new HttpClientErrorException(entity.getStatusCode());
    }

    @Override
    public String post(String uri, Object parameters) {
        ResponseEntity<String> entity = restTemplate.postForEntity(uri, parameters, String.class);
        if (entity.getStatusCode().is2xxSuccessful()) {
            return entity.getBody();
        }
        throw new HttpClientErrorException(entity.getStatusCode());
    }

    @Override
    public String post(String uri, Map<String, ?> parameters) {
        log.info("method post uri:{},parameters:{}", uri, parameters);
        ResponseEntity<String> entity = restTemplate.exchange(uri, HttpMethod.POST, from(null, parameters), String.class);
        if (entity.getStatusCode().is2xxSuccessful()) {
            return entity.getBody();
        }
        throw new HttpClientErrorException(entity.getStatusCode());
    }


    /**
     * 表单提交封装
     *
     * @param parameters
     * @return
     */
    private HttpEntity<MultiValueMap<String, String>> from(Map<String, String> headers, Map<String, ?> parameters) {
        HttpHeaders hd = new HttpHeaders();
        if (headers != null) {
            headers.forEach((k, v) -> {
                hd.add(k, v);
            });
        }
//        hd.setContentType(MediaType.APPLICATION_FORM_URLENCODED); 表单头?
        MultiValueMap<String, String> params = new LinkedMultiValueMap<>();
        parameters.forEach((s, o) -> {
            params.add(s, Objects.toString(o, StringUtils.EMPTY));
        });
        HttpEntity<MultiValueMap<String, String>> requestEntity = new HttpEntity<>(params, hd);
        return requestEntity;
    }


    @Override
    public <T> T post(String uri, final Map<String, String> headers, Object parameters, Class<T> clazz) {
        log.info("method post uri:{},headers:{},parameters:{}", uri, headers, parameters);
        HttpHeaders hd = new HttpHeaders();
        if (headers != null) {
            headers.forEach((k, v) -> {
                hd.add(k, v);
            });
        }
        //模拟表单提交
        if (MediaType.APPLICATION_FORM_URLENCODED.equals(hd.getContentType())) {
            MultiValueMap<String, Object> params = new LinkedMultiValueMap<>();
            if (parameters instanceof Map) {
                Map<String, Object> param = (Map) parameters;
                params.setAll(param);
            } else {
                try {
                    Map<String, String> describe = BeanUtils.describe(parameters);
                    describe.forEach((k, v) -> {
                        params.add(k, v);
                    });
                } catch (Exception e) {
                    log.error("表单提交时,bean必须为可序列基础类型:", e);
                    throw new IllegalArgumentException("bean必须为可序列基础类型");
                }
            }
            parameters = params;
        }
        HttpEntity<Object> requestEntity = new HttpEntity<>(parameters, hd);
        ResponseEntity<T> entity = restTemplate.exchange(uri, HttpMethod.POST, requestEntity, clazz);
        if (entity.getStatusCode().is2xxSuccessful()) {
            return entity.getBody();
        }
        throw new HttpClientErrorException(entity.getStatusCode());
    }

    @Override
    public <T> T postWithParam(String uri, Map<String, String> parameters, Class<T> clazz) {
        ResponseEntity<T> entity = restTemplate.exchange(uri, HttpMethod.POST, from(null, parameters), clazz);
        if (entity.getStatusCode().is2xxSuccessful()) {
            return entity.getBody();
        }
        throw new HttpClientErrorException(entity.getStatusCode());
    }


    @Override
    public <T> T post(String uri, Map<String, String> headers, Map<String, String> parameters, Class<T> clazz) {
        ResponseEntity<T> entity = restTemplate.exchange(uri, HttpMethod.POST, from(headers, parameters), clazz);
        if (entity.getStatusCode().is2xxSuccessful()) {
            return entity.getBody();
        }
        throw new HttpClientErrorException(entity.getStatusCode());
    }

    @Override
    public String post(String uri, Map<String, String> headers, Object parameters) {
        return post(uri, headers, parameters, String.class);
    }


    @Override
    public <T> T put(String uri, final Map<String, String> headers, Object parameters, Class<T> clazz) {
        HttpHeaders hd = new HttpHeaders();
        if (headers != null) {
            headers.forEach((k, v) -> {
                hd.add(k, v);
            });
        }
        HttpEntity<Object> requestEntity = new HttpEntity<>(parameters, hd);
        ResponseEntity<T> entity = restTemplate.exchange(uri, HttpMethod.PUT, requestEntity, clazz);
        if (entity.getStatusCode().is2xxSuccessful()) {
            return entity.getBody();
        }
        throw new HttpClientErrorException(entity.getStatusCode());
    }

}
