package com.ustadmobile.core.db.dao

import androidx.room.Dao
import androidx.room.Insert
import androidx.room.Query
import com.ustadmobile.lib.db.composites.TransferJobAndTotals
import com.ustadmobile.lib.db.entities.TransferJob
import kotlin.Any
import kotlin.Int
import kotlin.Long
import kotlin.collections.List
import kotlinx.coroutines.flow.Flow

@Dao
public actual abstract class TransferJobDao {
  @Insert(
    entity = Any::class,
    onConflict = 3,
  )
  public actual abstract suspend fun insert(job: TransferJob): Long

  @Query(`value` =
      "\n        SELECT TransferJob.*\n          FROM TransferJob\n         WHERE TransferJob.tjUid = :jobUid\n    ")
  public actual abstract suspend fun findByUid(jobUid: Int): TransferJob?

  @Query(`value` =
      "\n        SELECT TransferJob.*\n          FROM TransferJob\n         WHERE TransferJob.tjUid = :jobUid\n    ")
  public actual abstract fun findByUidAsFlow(jobUid: Int): Flow<TransferJob?>

  @Query(`value` =
      "\n        UPDATE TransferJob\n           SET tjStatus = :status\n         WHERE tjUid = :jobUid  \n    ")
  public actual abstract suspend fun updateStatus(jobUid: Int, status: Int)

  @Query(`value` =
      "\n        SELECT COALESCE(\n            (SELECT TransferJob.tjStatus\n               FROM TransferJob\n              WHERE tjUid = :jobUid), 0)\n    ")
  public actual abstract suspend fun getJobStatus(jobUid: Int): Int

  @Query(`value` =
      "\n        UPDATE TransferJob\n           SET tjStatus = 21\n         WHERE tjUid = :jobUid\n          AND NOT EXISTS(\n              SELECT TransferJobItem.tjiUid\n                FROM TransferJobItem\n               WHERE TransferJobItem.tjiTjUid = :jobUid\n                 AND TransferJobItem.tjiStatus != 21) \n    ")
  public actual abstract suspend fun updateStatusIfComplete(jobUid: Int): Int

  @Query(`value` =
      "\n        SELECT TransferJob.*\n          FROM TransferJob\n         WHERE EXISTS(\n               SELECT TransferJobItem.tjiUid\n                 FROM TransferJobItem\n                WHERE TransferJobItem.tjiTjUid = TransferJob.tjUid\n                  AND TransferJobItem.tjiTableId = :tableId\n                  AND TransferJobItem.tjiEntityUid = :entityUid) \n    ")
  public actual abstract suspend fun findJobByEntityAndTableUid(tableId: Int, entityUid: Long):
      List<TransferJob>

  @Query(`value` =
      "\n        SELECT TransferJob.*,\n               \n        (SELECT SUM(TransferJobItem.tjTotalSize)\n                   FROM TransferJobItem\n                  WHERE TransferJobItem.tjiTjUid =  TransferJob.tjUid) AS totalSize,\n                (SELECT SUM(TransferJobItem.tjTransferred)\n                   FROM TransferJobItem\n                  WHERE TransferJobItem.tjiTjUid =  TransferJob.tjUid) AS transferred \n    ,\n               TransferJobError.tjeErrorStr AS latestErrorStr\n          FROM TransferJob\n               LEFT JOIN TransferJobError\n                         ON TransferJobError.tjeId = \n                            (SELECT TransferJobError.tjeId\n                               FROM TransferJobError\n                              WHERE TransferJob.tjStatus = 22\n                                AND TransferJobError.tjeTjUid = TransferJob.tjUid\n                           ORDER BY TransferJobError.tjeDismissed DESC \n                              LIMIT 1)\n         WHERE TransferJob.tjTableId = 738\n           AND TransferJob.tjEntityUid IN \n               \n        (SELECT ContentEntryVersion.cevUid\n                         FROM ContentEntryVersion\n                        WHERE ContentEntryVersion.cevContentEntryUid = :contentEntryUid)\n     \n           AND (   TransferJob.tjStatus < 21\n                OR (TransferJobError.tjeErrorStr IS NOT NULL AND NOT TransferJobError.tjeDismissed))\n           AND TransferJob.tjType = :jobType   \n    ")
  public actual abstract fun findByContentEntryUidWithTotalsAsFlow(contentEntryUid: Long,
      jobType: Int): Flow<List<TransferJobAndTotals>>

  @Query(`value` =
      "\n        SELECT COALESCE(\n               (SELECT TransferJob.tjOiUid\n                  FROM TransferJob\n                 WHERE TransferJob.tjUid = :jobUid), 0)\n    ")
  public actual abstract suspend fun findOfflineItemUidForTransferJobUid(jobUid: Int): Long
}
