package com.dmc.callcrm.sync import android.content.Context import android.util.Log import com.dmc.callcrm.data.Prefs import com.dmc.callcrm.data.RecordingScanner import com.dmc.callcrm.network.ApiClient import okhttp3.MediaType.Companion.toMediaTypeOrNull import okhttp3.MultipartBody import okhttp3.RequestBody import okhttp3.RequestBody.Companion.asRequestBody import okhttp3.RequestBody.Companion.toRequestBody /** Scans for new recordings and uploads each, tagged with the client number. */ object RecordingUploader { private const val TAG = "RecordingUploader" suspend fun run(ctx: Context): Boolean { val prefs = Prefs(ctx) if (!prefs.isRegistered) return false val scanner = RecordingScanner(ctx) val uploaded = prefs.uploadedRecordings val recs = scanner.scan(prefs.lastRecordingScan, uploaded) if (recs.isEmpty()) return true var newestSeen = prefs.lastRecordingScan var allOk = true for (r in recs) { try { val mime = when (r.file.extension.lowercase()) { "mp3" -> "audio/mpeg"; "amr" -> "audio/amr"; "wav" -> "audio/wav" "ogg" -> "audio/ogg"; "aac" -> "audio/aac"; "3gp" -> "audio/3gpp" else -> "audio/mp4" } val filePart = MultipartBody.Part.createFormData( "file", r.file.name, r.file.asRequestBody(mime.toMediaTypeOrNull()) ) fun text(v: String): RequestBody = v.toRequestBody("text/plain".toMediaTypeOrNull()) val resp = ApiClient.service.uploadRecording( bearer = prefs.bearer(), file = filePart, clientNumber = text(r.clientNumber), callDate = text(r.callDateMs.toString()), duration = text(r.durationSec.toString()), callType = text(r.callType), contactName = text(r.contactName ?: ""), deviceCallId = text(r.deviceCallId ?: "") ) if (resp.isSuccessful && resp.body()?.ok == true) { prefs.markUploaded(r.file.absolutePath) if (r.file.lastModified() > newestSeen) newestSeen = r.file.lastModified() Log.d(TAG, "uploaded ${r.file.name} for ${r.clientNumber}") } else { allOk = false Log.w(TAG, "upload failed ${resp.code()} for ${r.file.name}") } } catch (e: Exception) { allOk = false Log.e(TAG, "upload error for ${r.file.name}", e) } } // Advance the scan cursor only when everything in this pass succeeded, // so failures get retried next run. if (allOk) prefs.lastRecordingScan = newestSeen return allOk } }