package cy.hexor.furumi.data.local

import android.app.job.JobInfo
import android.app.job.JobScheduler
import android.content.ComponentName
import android.content.Context
import android.os.Build
import cy.hexor.furumi.domain.model.AuthException
import cy.hexor.furumi.offline.OfflineDownloadJobService
import dagger.hilt.android.qualifiers.ApplicationContext
import javax.inject.Inject
import javax.inject.Singleton

@Singleton
class OfflineDownloadJobScheduler @Inject constructor(
    @param:ApplicationContext private val context: Context
) {
    private val jobScheduler = context.getSystemService(JobScheduler::class.java)

    fun schedule(estimatedDownloadBytes: Long) {
        if (jobScheduler.allPendingJobs.any { it.id == OFFLINE_DOWNLOAD_JOB_ID }) return

        val result = jobScheduler.schedule(buildJobInfo(userInitiated = true, estimatedDownloadBytes))
        if (result == JobScheduler.RESULT_SUCCESS) return

        val fallbackResult = jobScheduler.schedule(buildJobInfo(userInitiated = false, estimatedDownloadBytes))
        if (fallbackResult != JobScheduler.RESULT_SUCCESS) {
            throw AuthException("Unable to schedule offline download")
        }
    }

    private fun buildJobInfo(userInitiated: Boolean, estimatedDownloadBytes: Long): JobInfo {
        val builder = JobInfo.Builder(
            OFFLINE_DOWNLOAD_JOB_ID,
            ComponentName(context, OfflineDownloadJobService::class.java)
        )
            .setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY)
            .setRequiresStorageNotLow(true)

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P && estimatedDownloadBytes > 0L) {
            builder.setEstimatedNetworkBytes(estimatedDownloadBytes, 0L)
        }
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE &&
            userInitiated &&
            jobScheduler.canRunUserInitiatedJobs()
        ) {
            builder.setUserInitiated(true)
        }
        return builder.build()
    }

    companion object {
        const val OFFLINE_DOWNLOAD_JOB_ID = 0x4675_0D1
    }
}
