package com.chinaweal.aiccs.aiccs.market.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.chinaweal.aiccs.aiccs.market.entity.AddressGeoLog;
import com.chinaweal.aiccs.aiccs.market.entity.dto.GeoCodes;
import com.chinaweal.aiccs.aiccs.market.mapper.AddressGeoLogMapper;
import com.chinaweal.aiccs.aiccs.market.service.AddressGeoLogService;
import com.chinaweal.aiccs.common.util.StringUtils;
import com.chinaweal.youfool.framework.springboot.exception.custom.BusinessException;
import com.chinaweal.youfool.framework.springboot.mybatis.plus.BaseServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.HttpHost;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.conn.ssl.NoopHostnameVerifier;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.ssl.SSLContextBuilder;
import org.apache.http.util.EntityUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLContext;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.security.KeyManagementException;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.util.List;

/**
 * <p>
 * 地址编码记录表 服务实现类
 * </p>
 *
 * @author <a href="https://blog.lroyia.top">lroyia</a>
 * @since 2021-11-27
 */
@Slf4j
@Service
public class AddressGeoLogServiceImpl extends BaseServiceImpl<AddressGeoLogMapper, AddressGeoLog> implements AddressGeoLogService {

    @Value("${geo.host}")
    private String geoHost;

    @Value("${geo.appKey}")
    private String geoKey;

    @Value("${proxy.host:}")
    private String proxyHost;

    @Value("${proxy.port:}")
    private String proxyPort;

    private final static String DEFAULT_CITY = "广州";

    private final static String LIMIT_ERROR_MSG = "USER_DAILY_QUERY_OVER_LIMIT";

    @Override
    public List<GeoCodes> getGeoCodesByGeo(String address, String city) throws BusinessException {
        if (StringUtils.isBlank(city)) city = DEFAULT_CITY;

        try {
            address = URLEncoder.encode(address.trim(), "UTF-8");
        } catch (UnsupportedEncodingException e) {
            log.error("地址URLEncoder出错", e);
            throw new BusinessException(e.getMessage());
        }
        SSLConnectionSocketFactory sslsf;
        try {
            // 信任所有
            SSLContext sslContext = new SSLContextBuilder().loadTrustMaterial(null, (chain, authType) -> true).build();
            HostnameVerifier hostnameVerifier = NoopHostnameVerifier.INSTANCE;
            sslsf = new SSLConnectionSocketFactory(sslContext, hostnameVerifier);
        } catch (NoSuchAlgorithmException | KeyManagementException | KeyStoreException e) {
            throw new RuntimeException(e);
        }
        CloseableHttpClient httpClient = HttpClients.custom().setSSLSocketFactory(sslsf).build();
        HttpGet get = new HttpGet(String.format("%sv3/geocode/geo?key=%s&address=%s&city=%s", geoHost, geoKey, address, city));
        // 代理
        if (StringUtils.isNotBlank(proxyPort)) {
            HttpHost proxy = new HttpHost(proxyHost, Integer.parseInt(proxyPort), "http");
            get.setConfig(RequestConfig.custom().setProxy(proxy).build());
        }
        try (CloseableHttpResponse execute = httpClient.execute(get)) {
            JSONObject json = JSON.parseObject(EntityUtils.toString(execute.getEntity(), StandardCharsets.UTF_8));
            if (json.getInteger("status") != 1) {
                String info = json.getString("info");
                if (LIMIT_ERROR_MSG.equals(info)) {
                    throw new BusinessException("配额不足");
                }
                log.error("高德地图地理编码接口请求失败，错误码：{}", info);
                return null;
            }
            return json.getJSONArray("geocodes").toJavaList(GeoCodes.class);
        } catch (IOException e) {
            log.error("请求高德地图地理编码接口失败", e);
        } finally {
            try {
                httpClient.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        return null;
    }
}
