use crate::api::api_error;
use crate::api::authorize_request;
use crate::api::ok_json_with_trace;
use crate::api::parse_json_payload;
use crate::api::BearerToken;
use crate::core::behavior_bio::BehaviorInput;
use crate::core::cross_location::CrossValidationError;
use crate::core::cross_location::CrossValidationInput;
use crate::AppState;
use actix_web::http::StatusCode;
use actix_web::{post, web, HttpRequest, HttpResponse, Responder};
use serde::Deserialize;
use std::net::IpAddr;
#[derive(Deserialize)]
pub struct GeoResolveRequest {
pub ip_address: Option<IpAddr>, pub gps_data: Option<(f64, f64, u8, f64)>, pub os_info: String, pub device_details: String, pub environment_context: String, pub behavior_input: BehaviorInput, }
#[post("/geo/resolve")]
pub async fn resolve_geo(
app_data: web::Data<AppState>,
req: HttpRequest,
bearer: BearerToken,
payload_bytes: web::Bytes,
) -> impl Responder {
if let Err(resp) = authorize_request(&app_data, &req, &bearer, &payload_bytes).await {
return resp;
}
let payload: GeoResolveRequest = match parse_json_payload(&payload_bytes) {
Ok(v) => v,
Err(resp) => return resp,
};
let input = CrossValidationInput {
ip_address: payload.ip_address, gps_data: payload.gps_data, os_info: &payload.os_info, device_details: &payload.device_details, environment_context: &payload.environment_context, behavior_input: payload.behavior_input.clone(), };
let engine = &app_data.x_engine;
match engine.validate(input).await {
Ok(result) => ok_json_with_trace(&req, result), Err(CrossValidationError::GeoResolutionFailed(msg)) => {
let no_sources = msg.contains("لا توجد مصادر متاحة")
|| msg.to_lowercase().contains("no sources")
|| msg.to_lowercase().contains("location lookup failed");
if no_sources {
HttpResponse::UnprocessableEntity().json(serde_json::json!({
"code": "GEO_SOURCES_UNAVAILABLE",
"status": "degraded",
"message": msg,
"hint": "Provide a valid gps_data or ensure GeoIP source availability"
}))
} else {
HttpResponse::BadGateway().json(serde_json::json!({
"code": "GEO_RESOLUTION_FAILED",
"message": msg
}))
}
}
Err(_) => api_error(
StatusCode::INTERNAL_SERVER_ERROR,
"GEO_VALIDATION_INTERNAL_ERROR",
"Internal error while validating geolocation",
),
}
}