package pl.firmatpp.kierowca.data.upload

import android.content.Context
import android.location.Location
import androidx.work.BackoffPolicy
import androidx.work.Constraints
import androidx.work.ExistingWorkPolicy
import androidx.work.NetworkType
import androidx.work.OneTimeWorkRequestBuilder
import androidx.work.WorkManager
import androidx.work.workDataOf
import java.util.UUID
import java.util.concurrent.TimeUnit

class RoutePointOutbox(
    private val context: Context,
    private val dao: RoutePointDao = DriverDatabase.get(context).routePointDao(),
    private val workManager: WorkManager = WorkManager.getInstance(context),
) {
    suspend fun enqueue(
        routeId: String,
        driverId: String,
        location: Location,
        battery: Int?,
        charging: Boolean,
        uploadDelaySeconds: Long,
    ) {
        dao.upsert(
            RoutePointEntity(
                clientPointId = UUID.randomUUID().toString(),
                routeId = routeId,
                driverId = driverId,
                lat = location.latitude,
                lon = location.longitude,
                accuracy = if (location.hasAccuracy()) location.accuracy.toDouble() else 0.0,
                speed = if (location.hasSpeed()) location.speed.toDouble() else null,
                bearing = if (location.hasBearing()) location.bearing.toDouble() else null,
                timestamp = ((location.time.takeIf { it > 0L } ?: System.currentTimeMillis()) / 1000L),
                battery = battery,
                charging = charging,
            ),
        )

        enqueueWorker(routeId, uploadDelaySeconds)
    }

    fun enqueueWorker(routeId: String, delaySeconds: Long = 20L) {
        val request = OneTimeWorkRequestBuilder<RoutePointWorker>()
            .setInputData(workDataOf(RoutePointWorker.KEY_ROUTE_ID to routeId))
            .setInitialDelay(delaySeconds.coerceAtLeast(0L), TimeUnit.SECONDS)
            .setConstraints(Constraints.Builder().setRequiredNetworkType(NetworkType.CONNECTED).build())
            .setBackoffCriteria(BackoffPolicy.EXPONENTIAL, 30, TimeUnit.SECONDS)
            .build()

        workManager.enqueueUniqueWork(
            RoutePointWorker.uniqueWorkName(routeId),
            ExistingWorkPolicy.KEEP,
            request,
        )
    }
}
