package shop.alien.store.config;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.stereotype.Component;
import shop.alien.entity.store.EssentialCityCode;
import shop.alien.mapper.EssentialCityCodeMapper;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLEncoder;
import java.util.HashMap;
import java.util.Map;

/**
 * 高德地图工具类
 *
 * @author ssk
 * @version 1.0.0
 * @discription 打死你个龟孙
 * @since 1937-7-7
 */
@Slf4j
@Component
@RefreshScope
@RequiredArgsConstructor
public class GaoDeMapUtil {

    @Value("${gaode.key}")
    private String key;

    @Value("${gaode.geoUrl}")
    private String geoUrl;

    @Value("${gaode.geoListUrl}")
    private String geoListUrl;

    @Value("${gaode.getDistrict}")
    private String getDistrict;

    @Value("${gaode.distanceUrl}")
    private String distanceUrl;

    @Value("${gaode.distanceTypeUrl}")
    private String distanceTypeUrl;

    @Value("${gaode.nearUrl}")
    private String nearUrl;

    @Value("${gaode.subwayUrl}")
    private String subwayUrl;

    @Value("${gaode.addressUrl}")
    private String addressUrl;

    private final EssentialCityCodeMapper essentialCityCodeMapper;

    /**
     * 地址转经纬度
     *
     * @param address 地址
     * @return 经纬度
     */
    public String getLonAndLatByAddress(String address) {
        String formattedUrl = String.format(geoUrl, address, key);
        JSONObject obj = getResponse(formattedUrl);
        if (null != obj && "1".equals(String.valueOf(obj.get("status")))) {
            JSONArray geocodesArray = obj.getJSONArray("geocodes");
            if (geocodesArray != null && !geocodesArray.isEmpty()) {
                JSONObject jobJSON = geocodesArray.getJSONObject(0);
                return jobJSON.getString("location");
            } else {
                log.error("AddressLocationUtil.getLonAndLatByAddress ERROR 未找到与地址匹配的经纬度信息");
                return "ERROR 未找到与地址匹配的经纬度信息";
            }
        } else {
            log.error("AddressLocationUtil.getLonAndLatByAddress ERROR 地址转换经纬度失败");
            return "ERROR 地址转换经纬度失败";
        }
    }

    /**
     * 地址转经纬度
     *
     * @param address 地址
     * @return 经纬度
     */
    public JSONObject getInputPrompt(String address, String city) {
        //如果按照城市查询
        String cityCode = "";
        if (StringUtils.isNotEmpty(city)) {
            EssentialCityCode essentialCityCode = essentialCityCodeMapper.selectOne(new LambdaQueryWrapper<EssentialCityCode>().eq(EssentialCityCode::getAreaName, city));
            if (null != essentialCityCode) {
                cityCode = essentialCityCode.getCityCode().toString();
            }
        }
        String formattedUrl = String.format(geoListUrl, address, key, cityCode);
        JSONObject obj = getResponse(formattedUrl);
        return obj;
    }

    /**
     * 地址转经纬度
     * cityCode：城市编码
     *
     * @return
     */
    public JSONObject getDistrict(String cityCode) {
        String formattedUrl = String.format(getDistrict, key, cityCode);
        JSONObject obj = getResponse(formattedUrl);
        return obj;
    }

    /**
     * 计算两个经纬度的距离
     *
     * @param longitudeOne 经度1
     * @param latitudeOne  纬度1
     * @param longitudeTwo 经度2
     * @param latitudeTwo  纬度2
     * @return distance
     */
    public Double getDistance(String longitudeOne, String latitudeOne, String longitudeTwo, String latitudeTwo) {
        try {
            String urlString = String.format(distanceUrl, key, longitudeOne, latitudeOne, longitudeTwo, latitudeTwo);
            JSONObject obj = getResponse(urlString);
            if (null != obj && "1".equals(String.valueOf(obj.get("status")))) {
                JSONArray resultsArray = obj.getJSONArray("results");
                if (resultsArray != null && !resultsArray.isEmpty()) {
                    JSONObject resultJSON = resultsArray.getJSONObject(0);
                    return Double.parseDouble(resultJSON.getString("distance"));
                } else {
                    log.error("AddressLocationUtil.getDistance ERROR 计算距离失败，结果为空");
                    return null;
                }
            } else {
                log.error("AddressLocationUtil.getDistance ERROR 计算距离失败");
                return null;
            }
        } catch (Exception e) {
            log.error("AddressLocationUtil.getDistance ERROR {}", e.getMessage());
            return null;
        }
    }

    /**
     * 计算两个经纬度的距离
     *
     * @param longitudeOne 经度1
     * @param latitudeOne  纬度1
     * @param longitudeTwo 经度2
     * @param latitudeTwo  纬度2
     * @return distance
     */
    public Double getDistanceStraightLine(String longitudeOne, String latitudeOne, String longitudeTwo, String latitudeTwo) {
        try {
            String urlString = String.format(distanceTypeUrl, key, longitudeOne, latitudeOne, longitudeTwo, latitudeTwo, 0);
            JSONObject obj = getResponse(urlString);
            if (null != obj && "1".equals(String.valueOf(obj.get("status")))) {
                JSONArray resultsArray = obj.getJSONArray("results");
                if (resultsArray != null && !resultsArray.isEmpty()) {
                    JSONObject resultJSON = resultsArray.getJSONObject(0);
                    return Double.parseDouble(resultJSON.getString("distance"));
                } else {
                    log.error("AddressLocationUtil.getDistance ERROR 计算距离失败，结果为空");
                    return null;
                }
            } else {
                log.error("AddressLocationUtil.getDistance ERROR 计算距离失败");
                return null;
            }
        } catch (Exception e) {
            log.error("AddressLocationUtil.getDistance ERROR {}", e.getMessage());
            return null;
        }
    }

    /**
     * 获取附近商家、建筑等信息
     *
     * @param longitude 经度
     * @param latitude  纬度
     * @return
     */
    public JSONArray getNear(String longitude, String latitude) {
        try {
            String urlString = String.format(nearUrl, longitude, latitude, key, 10000, 20, 1);
            JSONObject obj = getResponse(urlString);
            if (null != obj && "1".equals(String.valueOf(obj.get("status")))) {
                JSONArray resultsArray = obj.getJSONArray("pois");
                return resultsArray;
            }
        } catch (Exception e) {
            log.error("AddressLocationUtil.getNear ERROR {}", e.getMessage());
        }
        return new JSONArray();
    }

    /**
     * 获取10公里范围内的商场
     *
     * @param longitude 经度
     * @param latitude  纬度
     * @return 商场列表
     */
    public JSONArray getNearbyShoppingMalls(String longitude, String latitude) {
        try {
            // 使用高德地图POI搜索接口，搜索类型为商场(060100)
            String urlString = String.format(nearUrl, longitude, latitude, key, 10000, 20, 1) + "&types=060100";
            JSONObject obj = getResponse(urlString);
            if (null != obj && "1".equals(String.valueOf(obj.get("status")))) {
                JSONArray resultsArray = obj.getJSONArray("pois");
                return resultsArray;
            }
        } catch (Exception e) {
            log.error("GaoDeMapUtil.getNearbyShoppingMalls ERROR {}", e.getMessage());
        }
        return new JSONArray();
    }

    public JSONObject getNearbySubway(String longitude, String latitude) {
        try {
            // 使用高德地图POI搜索接口，搜索类型为地铁站(010100)
            String encodedKeywords = URLEncoder.encode("地铁站", "UTF-8");
            String urlString = String.format(
                    subwayUrl,
                    key, latitude, longitude, encodedKeywords, 1000, 150500);
            JSONObject obj = getResponse(urlString);
            if (null != obj && "1".equals(String.valueOf(obj.get("status")))) {
                JSONObject pois = obj.getJSONArray("pois").getJSONObject(0);
                return pois;
            }
        } catch (Exception e) {
            log.error("GaoDeMapUtil.getNearbySubway ERROR {}", e.getMessage());
        }
        return new JSONObject();
    }

    /**
     * 通过经纬度获取地址信息
     *
     * @param longitude
     * @param latitude
     * @param radius
     * @param extensions
     * @return
     */
    public Map<String, String> getAddressByLonAndLat(String longitude, String latitude, String radius, String extensions) {
        String formattedUrl = String.format(addressUrl, longitude, latitude, key, radius, extensions);
        JSONObject obj = getResponse(formattedUrl);
        try {
            if (null != obj && "1".equals(String.valueOf(obj.get("status")))) {
                Map<String, String> address = new HashMap<>();
                JSONObject regeocodeObject = obj.getJSONObject("regeocode");
                JSONObject addressComponent = regeocodeObject.getJSONObject("addressComponent");
                address.put("city", addressComponent.getString("city"));
                address.put("district", addressComponent.getString("district"));
                address.put("province", addressComponent.getString("province"));
                JSONObject streetNumber = addressComponent.getJSONObject("streetNumber");
                address.put("street", streetNumber.getString("street"));
                address.put("streetNumber", streetNumber.getString("number"));
                JSONObject pois = regeocodeObject.getJSONArray("pois").getJSONObject(0);
                address.put("poiName", pois.getString("name"));
                return address;
            }
        } catch (Exception e) {
            log.error("GaoDeMapUtil.getAddressByLonAndLat ERROR {}", e.getMessage());
        }
        return new HashMap<>();
    }

    /**
     * 创建请求
     *
     * @param serverUrl 请求地址
     * @return JSONObject
     */
    private JSONObject getResponse(String serverUrl) {
        StringBuilder result = new StringBuilder();
        try {
            URL url = new URL(serverUrl);
            URLConnection conn = url.openConnection();
            BufferedReader in = new BufferedReader(new InputStreamReader(conn.getInputStream()));
            String line;
            while ((line = in.readLine()) != null) {
                result.append(line);
            }
            in.close();
        } catch (Exception e) {
            log.error("AddressLocationUtil.getResponse ERROR {}", e.getMessage());
            return null;
        }
        return JSONObject.parseObject(result.toString());
    }
}
