package org.jeecg.common.aspect.baiduAddress;

import lombok.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
import org.springframework.util.StreamUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.util.UriUtils;

import java.io.InputStream;
import java.net.URL;
import java.net.URLConnection;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;

@Slf4j
@Component
public class BaiduMapApiHelper {

    final AtomicInteger accessCount = new AtomicInteger(0);

    @Autowired
    private BaiDuMapConf conf;


    /**
     * 地理编码
     * https://lbsyun.baidu.com/faq/api?title=webapi/guide/webservice-geocoding-base
     *
     * @param address
     * @return
     */
    @SneakyThrows
    public GeoCode geocoding(String address) {
        log.info("geocoding : {}", address);
        final String uri = "/geocoding/v3?";
        final BaiDuMapConf.Key key = nextKey();
        LinkedHashMap<String, String> params = new LinkedHashMap<String, String>();
        params.put("address", address);
        params.put("output", "json");
        params.put("ak", key.getAk());
        final String sn = BaiduSnUtil.sn(uri, params, key.getSk());
        byte[] bin = requestGet(uri, params, sn);
        String ret = new String(bin, "UTF-8");
        GeoCode geoCode = JsonUtil.toObject(ret, GeoCode.class);
        //默认填充地址
        if (geoCode!=null){
            if (geoCode.getResult()!=null){
                if (!StringUtils.hasText(geoCode.getResult().getFormatted_address())) {
                    geoCode.getResult().setFormatted_address(address);
                }
            }
        }
        return geoCode;
    }


    /**
     * 逆地理编码
     * https://lbsyun.baidu.com/faq/api?title=webapi/guide/webservice-geocoding-abroad-base
     *
     * @param coordType
     * @param lng
     * @param lat
     * @return
     */
    @SneakyThrows
    public GeoCode reverse_geocoding(GeoCoordType coordType, Double lng, Double lat) {
        log.info("reverse_geocoding : {},{}", lng, lat);
        final String uri = "/reverse_geocoding/v3?";
        final BaiDuMapConf.Key key = nextKey();
        LinkedHashMap<String, String> params = new LinkedHashMap<String, String>();
        params.put("ak", key.getAk());
        params.put("output", "json");
        params.put("coordtype", coordType.name());
        params.put("extensions_poi", "0");
        params.put("location", lat + "," + lng);

        final String sn = BaiduSnUtil.sn(uri, params, key.getSk());
        byte[] bin = requestGet(uri, params, sn);
        String ret = new String(bin, "UTF-8");
        return JsonUtil.toObject(ret, GeoCode.class);
    }


    @SneakyThrows
    public RegionSearchModel api_region_search(String keyword, String sub_admin, String extensions_code, String boundary, String boundarycode) {
        log.info("api_region_search : {},{},{},{},{}", keyword, sub_admin, extensions_code, boundary, boundarycode);
        final String uri = "/api_region_search/v1/?";
        final BaiDuMapConf.Key key = nextKey();
        LinkedHashMap<String, String> params = new LinkedHashMap<String, String>();
        params.put("ak", key.getAk());
        params.put("keyword", keyword);

        if (StringUtils.hasText(sub_admin)) {
            params.put("sub_admin", sub_admin);
        }
        if (StringUtils.hasText(extensions_code)) {
            params.put("extensions_code", extensions_code);
        }
        if (StringUtils.hasText(boundary)) {
            params.put("boundary", boundary);
        }
        if (StringUtils.hasText(boundarycode)) {
            params.put("boundarycode", boundarycode);
        }


        final String sn = BaiduSnUtil.sn(uri, params, key.getSk());
        byte[] bin = requestGet(uri, params, sn);
        String ret = new String(bin, "UTF-8");
        return JsonUtil.toObject(ret, RegionSearchModel.class);
    }



    @SneakyThrows
    private byte[] requestGet(String strUrl, Map<String, String> param, String sn) {
        if (strUrl == null || strUrl.length() <= 0 || param == null || param.size() <= 0) {
            return null;
        }

        StringBuffer queryString = new StringBuffer();
        queryString.append(strUrl);
        for (Map.Entry<?, ?> pair : param.entrySet()) {
            queryString.append(pair.getKey() + "=");
            queryString.append(UriUtils.encode((String) pair.getValue(), "UTF-8") + "&");
        }

        if (queryString.length() > 0) {
            queryString.deleteCharAt(queryString.length() - 1);
        }

        URL url = new URL("https://api.map.baidu.com" + queryString.toString() + "&sn=" + sn);
        URLConnection httpConnection = url.openConnection();
        httpConnection.connect();

        @Cleanup InputStream inputStream = httpConnection.getInputStream();
        return StreamUtils.copyToByteArray(inputStream);
    }


    /**
     * 后去key
     *
     * @return
     */
    private synchronized BaiDuMapConf.Key nextKey() {
        final BaiDuMapConf.Key[] keys = conf.getKeys();
        if (keys == null || keys.length == 0) {
            return null;
        }
        return keys[accessCount.getAndIncrement() % keys.length];
    }


    @Data
    @Component
    @NoArgsConstructor
    @AllArgsConstructor
    @ConfigurationProperties("baidu.map")
    public static class BaiDuMapConf {

        // 密钥
        private Key[] keys;


        @Data
        @Component
        @NoArgsConstructor
        @AllArgsConstructor
        public static class Key {

            // 应用
            private String ak;

            // 密钥
            private String sk;
        }

    }


}
