package com.hipograf.companion.sync

import android.content.Context
import android.util.Log
import androidx.work.CoroutineWorker
import androidx.work.WorkerParameters
import com.hipograf.companion.api.HipografApi
import com.hipograf.companion.health.HealthReader
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext

/**
 * Background worker that runs every 15 minutes via WorkManager.
 * Reads new Samsung Health data and POSTs it to the Hipograf backend.
 */
class SyncWorker(
    context: Context,
    params: WorkerParameters
) : CoroutineWorker(context, params) {

    companion object {
        private const val TAG = "HipografSync"
        private const val PREF_LAST_SYNC = "last_sync_timestamp"

        // Always re-read the trailing 30-day window on every sync rather than
        // "since last sync". Two reasons:
        //  1. Samsung Health backfills data to Health Connect lazily — a day
        //     synced as "0 steps" today might have real data appear tomorrow,
        //     and a since-last-sync read would never pick it up.
        //  2. The backend upsert is keyed on {userId, provider, metric, date}
        //     so re-uploading is idempotent and cheap.
        private const val SYNC_WINDOW_DAYS = 30L
    }

    override suspend fun doWork(): Result = withContext(Dispatchers.IO) {
        val prefs = applicationContext.getSharedPreferences("hipograf", Context.MODE_PRIVATE)
        val token = prefs.getString("token", null)

        if (token.isNullOrEmpty()) {
            Log.w(TAG, "No auth token — skipping sync")
            return@withContext Result.success()
        }

        val windowStart = System.currentTimeMillis() - SYNC_WINDOW_DAYS * 24 * 60 * 60 * 1000L

        try {
            // 1. Read the last 30 days of health data (idempotent — backend upserts)
            val readings = HealthReader.readSince(applicationContext, windowStart)
            if (readings.isEmpty()) {
                Log.d(TAG, "No new readings to sync")
                return@withContext Result.success()
            }

            // 2. Convert to API format
            val apiReadings = readings.map { r ->
                mapOf<String, Any>(
                    "metric" to r.metric,
                    "value" to r.value,
                    "unit" to r.unit,
                    "date" to r.date,
                    "metricType" to r.metricType,
                    "quality" to r.quality
                )
            }

            // 3. POST to backend
            val deviceInfo = HealthReader.getDeviceInfo()
            val result = HipografApi.syncReadings(token, apiReadings, deviceInfo)

            result.fold(
                onSuccess = { syncResp ->
                    Log.i(TAG, "Synced ${syncResp.accepted} readings at ${syncResp.serverTime}")

                    // 4. Update last sync timestamp
                    prefs.edit()
                        .putLong(PREF_LAST_SYNC, System.currentTimeMillis())
                        .apply()

                    return@withContext Result.success()
                },
                onFailure = { error ->
                    Log.e(TAG, "Sync failed: ${error.message}")
                    // Retry on next schedule
                    return@withContext Result.retry()
                }
            )
        } catch (e: Exception) {
            Log.e(TAG, "Sync error", e)
            return@withContext Result.retry()
        }

        Result.success()
    }
}
