package com.ruoyi.app.flashdelivery.route;

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.ruoyi.common.core.domain.entity.SysDictData;
import com.ruoyi.common.utils.DictUtils;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.springframework.stereotype.Component;

import java.math.BigDecimal;
import java.nio.charset.StandardCharsets;
import java.util.List;

/** Google Routes API 的服务端实现，密钥只从后端专用字典读取。 */
@Component
public class GoogleRoutesDistanceProvider implements RouteDistanceProvider {
    private static final String ENDPOINT = "https://routes.googleapis.com/directions/v2:computeRoutes";
    private static final RequestConfig TIMEOUTS = RequestConfig.custom()
            .setConnectTimeout(2500).setConnectionRequestTimeout(2500).setSocketTimeout(3500).build();

    @Override
    public RouteDistance route(BigDecimal originLatitude, BigDecimal originLongitude,
                               BigDecimal destinationLatitude, BigDecimal destinationLongitude) {
        // 不复用可能被浏览器端读取的 sys_googlemap_key，防止服务端 API 权限泄露。
        List<SysDictData> keys = DictUtils.getDictCache("sys_google_routes_key");
        if (keys == null || keys.isEmpty() || keys.get(0).getDictValue() == null
                || keys.get(0).getDictValue().isBlank()) {
            throw new IllegalStateException("google routes key unavailable");
        }
        JSONObject body = new JSONObject();
        body.put("origin", waypoint(originLatitude, originLongitude));
        body.put("destination", waypoint(destinationLatitude, destinationLongitude));
        body.put("travelMode", "DRIVE");
        body.put("routingPreference", "TRAFFIC_AWARE");
        body.put("computeAlternativeRoutes", false);
        body.put("units", "METRIC");
        HttpPost request = new HttpPost(ENDPOINT);
        request.setConfig(TIMEOUTS);
        request.setHeader("X-Goog-Api-Key", keys.get(0).getDictValue());
        // 只请求计价需要的字段，减少响应体及不必要的数据暴露。
        request.setHeader("X-Goog-FieldMask", "routes.distanceMeters,routes.duration");
        request.setEntity(new StringEntity(body.toJSONString(), ContentType.APPLICATION_JSON));
        try (CloseableHttpClient client = HttpClients.custom().disableAutomaticRetries().build();
             CloseableHttpResponse response = client.execute(request)) {
            if (response.getStatusLine().getStatusCode() < 200 || response.getStatusLine().getStatusCode() >= 300) {
                throw new IllegalStateException("google routes non-success response");
            }
            JSONObject json = JSON.parseObject(EntityUtils.toString(response.getEntity(), StandardCharsets.UTF_8));
            JSONArray routes = json.getJSONArray("routes");
            if (routes == null || routes.isEmpty()) {
                throw new IllegalStateException("google routes empty response");
            }
            JSONObject first = routes.getJSONObject(0);
            int meters = first.getIntValue("distanceMeters");
            if (meters <= 0) {
                throw new IllegalStateException("google routes invalid distance");
            }
            return new RouteDistance(meters, parseDuration(first.getString("duration")), "ROUTE");
        } catch (Exception exception) {
            throw new IllegalStateException("google routes request failed", exception);
        }
    }

    private JSONObject waypoint(BigDecimal latitude, BigDecimal longitude) {
        JSONObject latLng = new JSONObject();
        latLng.put("latitude", latitude);
        latLng.put("longitude", longitude);
        JSONObject location = new JSONObject();
        location.put("latLng", latLng);
        JSONObject waypoint = new JSONObject();
        waypoint.put("location", location);
        return waypoint;
    }

    private Integer parseDuration(String value) {
        if (value == null || !value.endsWith("s")) return null;
        try {
            return new BigDecimal(value.substring(0, value.length() - 1)).intValue();
        } catch (NumberFormatException exception) {
            return null;
        }
    }
}
