package eu.brassepc.fitnessdroid.data import android.content.Context import androidx.health.connect.client.HealthConnectClient import androidx.health.connect.client.permission.HealthPermission import androidx.health.connect.client.records.StepsRecord import androidx.health.connect.client.request.AggregateRequest import androidx.health.connect.client.time.TimeRangeFilter import java.time.Instant import java.time.LocalDate import java.time.ZoneId /** * Steg via Health Connect: läser dagens + gårdagens stegsumma (som andra * appar/telefonen loggat) och synkar upp till gym-API:t (upsertDailySteps). * Servern räknar sedan in stegen i kcal-mätarens telefondel och stegmålen. */ class StepsSync( private val context: Context, private val gymApi: GymApi, ) { val stepsPermission: String = HealthPermission.getReadPermission(StepsRecord::class) private var lastSyncMs = 0L /** SDK_UNAVAILABLE / SDK_UNAVAILABLE_PROVIDER_UPDATE_REQUIRED / SDK_AVAILABLE */ fun sdkStatus(): Int = HealthConnectClient.getSdkStatus(context) fun isAvailable(): Boolean = sdkStatus() == HealthConnectClient.SDK_AVAILABLE suspend fun hasPermission(): Boolean { if (!isAvailable()) return false return runCatching { HealthConnectClient.getOrCreate(context) .permissionController.getGrantedPermissions() .contains(stepsPermission) }.getOrDefault(false) } /** * Läs och synka. Returnerar dagens steg, eller null om HC saknas / * behörighet inte getts. Fel sväljs (nästa synk försöker igen). */ suspend fun syncNow(): Int? { if (!hasPermission()) return null val client = HealthConnectClient.getOrCreate(context) val zone = ZoneId.systemDefault() val today = LocalDate.now() var todaySteps: Int? = null for (day in listOf(today.minusDays(1), today)) { val startInstant = day.atStartOfDay(zone).toInstant() val endInstant = if (day == today) Instant.now() else day.plusDays(1).atStartOfDay(zone).toInstant() val steps = runCatching { val result = client.aggregate( AggregateRequest( metrics = setOf(StepsRecord.COUNT_TOTAL), timeRangeFilter = TimeRangeFilter.between(startInstant, endInstant), ) ) (result[StepsRecord.COUNT_TOTAL] ?: 0L).toInt() }.getOrNull() ?: continue if (day == today) todaySteps = steps runCatching { gymApi.upsertDailySteps(startInstant.toString(), steps) } } lastSyncMs = System.currentTimeMillis() return todaySteps } /** Synka högst var 10:e minut — anropas t.ex. när hemskärmen visas. */ suspend fun syncThrottled() { if (System.currentTimeMillis() - lastSyncMs < 10 * 60_000) return syncNow() } }