package com.seven.ikar.kotlin.feature.transfer

import android.content.Context
import androidx.work.CoroutineWorker
import androidx.work.WorkerParameters
import com.seven.ikar.kotlin.app.IkarNativeApp
import com.seven.ikar.kotlin.core.local.TransferQueueStatus
import com.seven.ikar.kotlin.core.model.AttachmentDto
import com.seven.ikar.kotlin.core.model.AttachmentKind
import kotlinx.coroutines.runBlocking
import java.io.File

class AttachmentDownloadWorker(
    appContext: Context,
    params: WorkerParameters
) : CoroutineWorker(appContext, params) {
    override suspend fun doWork(): Result {
        val groupId = inputData.getString(KeyGroupId) ?: return Result.failure()
        val container = (applicationContext as IkarNativeApp).container
        val dao = container.localDatabase.transferQueueDao()
        val items = dao.getGroup(groupId)
        if (items.isEmpty()) {
            return Result.success()
        }

        val first = items.first()
        val attachmentId = first.attachmentId ?: return Result.failure()
        val chatId = first.chatId ?: return Result.failure()
        val now = System.currentTimeMillis()
        val totalBytes = first.fileSizeBytes.coerceAtLeast(0L)
        val showForeground = totalBytes >= TransferForegroundNotification.LargeTransferThresholdBytes
        if (showForeground) {
            setForeground(
                TransferForegroundNotification.createForegroundInfo(
                    context = applicationContext,
                    groupId = groupId,
                    title = "Загрузка вложения",
                    message = first.fileName,
                    progressPercent = null
                )
            )
        }
        dao.updateGroupStatus(groupId, TransferQueueStatus.Running, 5, null, now)
        var lastProgressPercent = 5
        var lastProgressAtMillis = now

        suspend fun publishProgress(bytesTransferred: Long, reportedTotalBytes: Long, force: Boolean = false) {
            val effectiveTotalBytes = reportedTotalBytes.takeIf { it > 0L } ?: totalBytes.takeIf { it > 0L } ?: return
            val progressPercent = ((bytesTransferred.coerceAtMost(effectiveTotalBytes) * 100L) / effectiveTotalBytes)
                .toInt()
                .coerceIn(5, 99)
            val currentTime = System.currentTimeMillis()
            val shouldPublish = force ||
                progressPercent != lastProgressPercent && currentTime - lastProgressAtMillis >= ProgressUpdateIntervalMillis ||
                progressPercent >= 99 && lastProgressPercent < 99
            if (!shouldPublish) {
                return
            }

            lastProgressPercent = progressPercent
            lastProgressAtMillis = currentTime
            dao.updateGroupStatus(groupId, TransferQueueStatus.Running, progressPercent, null, currentTime)
            if (showForeground) {
                setForeground(
                    TransferForegroundNotification.createForegroundInfo(
                        context = applicationContext,
                        groupId = groupId,
                        title = "Загрузка вложения",
                        message = first.fileName,
                        progressPercent = progressPercent
                    )
                )
            }
        }

        return runCatching {
            val attachment = AttachmentDto(
                id = attachmentId,
                fileName = first.fileName,
                contentType = first.contentType,
                fileSizeBytes = first.fileSizeBytes,
                downloadPath = "/api/chats/$chatId/attachments/$attachmentId/content",
                kind = AttachmentKind.File,
                sortOrder = first.sortOrder
            )
            val target = File(first.localPath).takeIf { it.path.isNotBlank() }
                ?: container.attachmentFileService.createAttachmentCacheFile(attachment.id, attachment.fileName)
            container.executeAuthorized { session ->
                val downloaded = container.apiClient.downloadAttachmentTo(
                    accessToken = session.accessToken,
                    attachment = attachment,
                    targetFile = target,
                    onProgress = { bytesRead, reportedTotalBytes ->
                        runBlocking {
                            publishProgress(bytesRead, reportedTotalBytes)
                        }
                    }
                )
                container.attachmentFileService.cacheDownloadedAttachment(downloaded)
            }
        }.fold(
            onSuccess = {
                dao.updateGroupStatus(groupId, TransferQueueStatus.Completed, 100, null, System.currentTimeMillis())
                Result.success()
            },
            onFailure = { error ->
                dao.updateGroupStatus(
                    groupId = groupId,
                    status = TransferQueueStatus.Failed,
                    progressPercent = 0,
                    errorMessage = error.message,
                    updatedAtMillis = System.currentTimeMillis()
                )
                if (runAttemptCount < 3) Result.retry() else Result.failure()
            }
        )
    }

    companion object {
        const val KeyGroupId = "group_id"
        private const val ProgressUpdateIntervalMillis = 500L
    }
}
