package com.clickdelivery.nativebridge import android.Manifest import android.app.* import android.content.* import android.content.pm.PackageManager import android.location.* import android.os.* import org.json.JSONObject import java.net.HttpURLConnection import java.net.URL import java.util.UUID class DriverLocationService:Service(),LocationListener{ private lateinit var lm:LocationManager;private var interval=8000L override fun onBind(i:Intent?)=null override fun onCreate(){super.onCreate();lm=getSystemService(Context.LOCATION_SERVICE) as LocationManager;startForeground(7707,notification())} private fun notification():Notification{val mgr=getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager;val id="clickdelivery_tracking";if(Build.VERSION.SDK_INT>=26)mgr.createNotificationChannel(NotificationChannel(id,"Tracking de reparto",NotificationManager.IMPORTANCE_LOW));val b=if(Build.VERSION.SDK_INT>=26)Notification.Builder(this,id) else Notification.Builder(this);return b.setSmallIcon(applicationInfo.icon).setContentTitle("ClickDelivery Repartidor").setContentText("Ubicación activa durante la entrega").setOngoing(true).build()} override fun onStartCommand(intent:Intent?,flags:Int,startId:Int):Int{interval=intent?.getLongExtra("interval_ms",8000L)?.coerceAtLeast(3000)?:8000;if(checkSelfPermission(Manifest.permission.ACCESS_FINE_LOCATION)==PackageManager.PERMISSION_GRANTED){runCatching{lm.requestLocationUpdates(LocationManager.GPS_PROVIDER,interval,5f,this)};runCatching{lm.requestLocationUpdates(LocationManager.NETWORK_PROVIDER,interval,5f,this)}};return START_STICKY} override fun onDestroy(){runCatching{lm.removeUpdates(this)};super.onDestroy()} override fun onLocationChanged(l:Location){Thread{send(l,false)}.start()} private fun baseUrl():String{val ai=packageManager.getApplicationInfo(packageName,PackageManager.GET_META_DATA);return ai.metaData.getString("CLICKDELIVERY_API_BASE_URL")!!.trimEnd('/')} private fun request(path:String,token:String,body:String):Pair{val c=(URL(baseUrl()+path).openConnection() as HttpURLConnection);c.requestMethod="POST";c.connectTimeout=10000;c.readTimeout=10000;c.doOutput=true;c.setRequestProperty("Content-Type","application/json");c.setRequestProperty("Authorization","Bearer $token");c.outputStream.use{it.write(body.toByteArray())};val code=c.responseCode;val stream=if(code<400)c.inputStream else c.errorStream;val text=stream?.bufferedReader()?.use{it.readText()}.orEmpty();c.disconnect();return code to text} private fun refresh():String?{val rt=SecureStore.get(this,"refresh_token")?:return null;val device=getSharedPreferences("clickdelivery_install",0).getString("id",null);val body=JSONObject().put("refresh_token",rt).put("device_id",device).toString();val c=(URL(baseUrl()+"/api/v1/auth/refresh").openConnection() as HttpURLConnection);c.requestMethod="POST";c.connectTimeout=10000;c.readTimeout=10000;c.doOutput=true;c.setRequestProperty("Content-Type","application/json");c.outputStream.use{it.write(body.toByteArray())};if(c.responseCode>=400){c.disconnect();return null};val obj=JSONObject(c.inputStream.bufferedReader().use{it.readText()});c.disconnect();obj.optString("token").takeIf{it.isNotBlank()}?.let{SecureStore.set(this,"access_token",it)};obj.optString("refresh_token").takeIf{it.isNotBlank()}?.let{SecureStore.set(this,"refresh_token",it)};return obj.optString("token").takeIf{it.isNotBlank()}} private fun send(l:Location,retry:Boolean){var token=SecureStore.get(this,"access_token")?:return;val body=JSONObject().put("client_point_id","bg_${UUID.randomUUID()}").put("lat",l.latitude).put("lng",l.longitude).put("accuracy_m",l.accuracy.toDouble()).put("speed_kmh",l.speed.toDouble()*3.6).put("heading",l.bearing.toDouble()).put("captured_at",java.text.SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'",java.util.Locale.US).apply{timeZone=java.util.TimeZone.getTimeZone("UTC")}.format(java.util.Date(l.time))).toString();val (code,_)=request("/api/v1/driver/location",token,body);if(code==401&&!retry){token=refresh()?:return;request("/api/v1/driver/location",token,body)}} }