package com.ustadmobile.core.db.dao

import androidx.lifecycle.LiveData
import androidx.room.Dao
import androidx.room.Insert
import androidx.room.Query
import com.ustadmobile.lib.db.entities.ContentJobItem
import com.ustadmobile.lib.db.entities.ContentJobItemAndContentJob
import com.ustadmobile.lib.db.entities.ContentJobItemProgress
import kotlin.Boolean
import kotlin.Int
import kotlin.Long
import kotlin.String
import kotlin.Unit
import kotlin.collections.List

@Dao
public actual abstract class ContentJobItemDao {
  @Query(`value` =
      "\n        WITH ConnectivityStateCte(state) AS \n             (SELECT COALESCE(\n                     (SELECT connectivityState \n                        FROM ConnectivityStatus \n                       LIMIT 1), 0))\n                       \n        SELECT ContentJobItem.*, ContentJob.*\n          FROM ContentJobItem\n               JOIN ContentJob\n               ON ContentJobItem.cjiJobUid = ContentJob.cjUid\n         WHERE ContentJobItem.cjiJobUid = :contentJobUid\n           AND (ContentJobItem.cjiStatus = 4 OR \n                ContentJobItem.cjiStatus = 5)\n           AND (\n                NOT cjiConnectivityNeeded \n                OR ((SELECT state FROM ConnectivityStateCte) = 4) \n                OR (cjIsMeteredAllowed \n                    AND (SELECT state FROM ConnectivityStateCte) = 3)\n                )\n         LIMIT :limit\n    ")
  public actual abstract suspend fun findNextItemsInQueue(contentJobUid: Long, limit: Int):
      List<ContentJobItemAndContentJob>

  @Query(`value` =
      "\n        SELECT cjiRecursiveProgress AS progress, \n               cjiRecursiveTotal AS total, \n               cjNotificationTitle as progressTitle,\n               ContentJobItem.cjiUid\n          FROM ContentJobItem\n          JOIN ContentJob\n            ON ContentJob.cjUid = ContentJobItem.cjiJobUid\n         WHERE cjiContentEntryUid = :contentEntryUid\n           AND cjiRecursiveStatus >= 4\n           AND cjiRecursiveStatus <= 20\n      ORDER BY cjiStartTime DESC\n    ")
  public actual abstract suspend fun findActiveContentJobItems(contentEntryUid: Long):
      List<ContentJobItemProgress>

  @Insert(onConflict = 3)
  public actual abstract suspend fun insertJobItem(jobItem: ContentJobItem): Long

  @Insert(onConflict = 3)
  public actual abstract suspend fun insertJobItems(jobItems: List<ContentJobItem>): Unit

  @Query(`value` =
      "\n        UPDATE ContentJobItem \n           SET cjiStatus = :status\n         WHERE cjiUid= :cjiUid  \n    ")
  public actual abstract suspend fun updateItemStatus(cjiUid: Long, status: Int): Unit

  @Query(`value` =
      "\n        SELECT NOT EXISTS(\n               SELECT cjiUid \n                 FROM ContentJobItem\n                WHERE cjiJobUid = :jobUid\n                  AND cjiStatus < 21) \n    ")
  public actual abstract suspend fun isJobDone(jobUid: Long): Boolean

  @Query(`value` =
      "\n        SELECT * \n          FROM ContentJobItem\n         WHERE cjiJobUid = :jobUid \n           AND cjiParentCjiUid = 0 \n         LIMIT 1\n    ")
  public actual abstract fun findRootJobItemByJobId(jobUid: Long): ContentJobItem?

  @Query(`value` =
      "\n        UPDATE ContentJobItem\n           SET cjiItemProgress = :cjiProgress,\n               cjiItemTotal = :cjiTotal\n         WHERE cjiUid = :cjiUid     \n    ")
  public actual abstract suspend fun updateItemProgress(
    cjiUid: Long,
    cjiProgress: Long,
    cjiTotal: Long,
  ): Unit

  @Query(`value` =
      "\n        UPDATE ContentJobItem\n           SET cjiConnectivityNeeded = :connectivityNeeded\n         WHERE cjiUid = :contentJobItemId     \n    ")
  public actual abstract suspend fun updateConnectivityNeeded(contentJobItemId: Long,
      connectivityNeeded: Boolean): Unit

  @Query(`value` =
      "\n        UPDATE ContentJobItem\n           SET cjiContainerProcessed = :cjiContainerProcessed\n         WHERE cjiUid = :contentJobItemId   \n    ")
  public actual abstract suspend fun updateContainerProcessed(contentJobItemId: Long,
      cjiContainerProcessed: Boolean): Unit

  @Query(`value` =
      "\n        UPDATE ContentJobItem\n           SET cjiStatus = :status,\n               cjiAttemptCount = :attemptCount\n         WHERE cjiUid = :cjiUid      \n    ")
  public actual abstract suspend fun updateJobItemAttemptCountAndStatus(
    cjiUid: Long,
    attemptCount: Int,
    status: Int,
  ): Unit

  @Query(`value` =
      "\n        UPDATE ContentJobItem\n           SET cjiStartTime = :startTime\n         WHERE cjiUid = :cjiUid      \n    ")
  public actual abstract suspend fun updateStartTimeForJob(cjiUid: Long, startTime: Long): Unit

  @Query(`value` =
      "\n        UPDATE ContentJobItem\n           SET cjiFinishTime = :finishTime\n         WHERE cjiUid = :cjiUid      \n    ")
  public actual abstract suspend fun updateFinishTimeForJob(cjiUid: Long, finishTime: Long): Unit

  @Query(`value` =
      "\n        UPDATE ContentJobITem\n           SET cjiContentEntryUid = :contentEntryUid\n         WHERE cjiUid = :cjiUid  \n    ")
  public actual abstract suspend fun updateContentEntryUid(cjiUid: Long, contentEntryUid: Long):
      Unit

  @Query(`value` =
      "\n        UPDATE ContentJobItem\n           SET cjiContainerUid = :containerUid\n         WHERE cjiUid = :cjiUid  \n    ")
  public actual abstract suspend fun updateContentJobItemContainer(cjiUid: Long,
      containerUid: Long): Unit

  @Query(`value` = "\n        SELECT * \n          FROM ContentJobItem\n    ")
  public actual abstract suspend fun findAll(): List<ContentJobItem>

  @Query(`value` =
      "\n        SELECT ContentJobItem.*\n          FROM ContentJobItem\n         WHERE cjiUid = :cjiUid \n    ")
  public actual abstract suspend fun findByUidAsync(cjiUid: Long): ContentJobItem?

  @Query(`value` =
      "\n        SELECT COALESCE(\n               (SELECT ContentJobItem.cjiJobUid\n                  FROM ContentJobItem\n                 WHERE cjiContentEntryUid = :contentEntryUid\n                   AND cjiStatus BETWEEN 4 AND 20\n              ORDER BY cjiFinishTime DESC), 0)\n    ")
  public actual abstract suspend fun getActiveContentJobIdByContentEntryUid(contentEntryUid: Long):
      Long

  @Query(`value` =
      "\n        UPDATE ContentJobItem\n           SET cjiUploadSessionUid = :uploadSessionUuid\n         WHERE cjiUid = :cjiUid  \n    ")
  public actual abstract suspend fun updateUploadSessionUuid(cjiUid: Long,
      uploadSessionUuid: String): Unit

  @Query(`value` =
      "\n        SELECT * \n          FROM ContentJobItem\n         WHERE cjiJobUid = :jobId \n    ")
  public actual abstract fun findAllByJobId(jobId: Long): List<ContentJobItem>

  @Query(`value` =
      "\n        SELECT *\n          FROM ContentJobItem\n         WHERE cjiUid = :uid   \n    ")
  public actual abstract fun getJobItemByUidLive(uid: Long): LiveData<ContentJobItem?>

  @Query(`value` =
      "\n        SELECT cjiContainerUid\n          FROM ContentJobItem\n         WHERE cjiUid = :uid \n    ")
  public actual abstract suspend fun getContainerUidByJobItemUid(uid: Long): Long

  @Query(`value` =
      "\n        UPDATE ContentJobItem\n           SET cjiStatus = :newStatus\n         WHERE cjiJobUid = :jobUid\n           AND cjiStatus != :newStatus\n    ")
  public actual abstract suspend fun updateAllStatusesByJobUid(jobUid: Long, newStatus: Int): Unit

  @Query(`value` =
      "\n        SELECT ContentJobItem.cjiContainerUid\n          FROM ContentJobItem\n         WHERE cjiJobUid = :jobUid \n    ")
  public actual abstract suspend fun findAllContainersByJobUid(jobUid: Long): List<Long>
}
