package com.ustadmobile.libcache.db.dao

import androidx.room.Dao
import androidx.room.Delete
import androidx.room.Insert
import androidx.room.Query
import androidx.room.Update
import com.ustadmobile.libcache.db.entities.CacheEntry
import kotlin.Any
import kotlin.Int
import kotlin.Long
import kotlin.String
import kotlin.collections.List

@Dao
public actual abstract class CacheEntryDao {
  @Query(`value` =
      "\n        SELECT CacheEntry.*\n          FROM CacheEntry\n         WHERE CacheEntry.url = :url \n    ")
  public actual abstract suspend fun findByUrlAsync(url: String): CacheEntry?

  @Query(`value` =
      "\n        SELECT CacheEntry.*\n          FROM CacheEntry\n         WHERE CacheEntry.key = :key\n    ")
  public actual abstract fun findEntryAndBodyByKey(key: String): CacheEntry?

  @Insert(
    entity = Any::class,
    onConflict = 3,
  )
  public actual abstract suspend fun insertAsync(entry: CacheEntry): Long

  @Insert(
    entity = Any::class,
    onConflict = 3,
  )
  public actual abstract fun insertList(entry: List<CacheEntry>)

  @Update(
    entity = Any::class,
    onConflict = 3,
  )
  public actual abstract fun updateList(entry: List<CacheEntry>)

  @Insert(
    onConflict = 1,
    entity = Any::class,
  )
  public actual abstract fun upsertList(entry: List<CacheEntry>)

  @Query(`value` =
      "\n        SELECT CacheEntry.*\n          FROM CacheEntry\n         WHERE CacheEntry.key IN\n               (SELECT RequestedEntry.requestedKey\n                  FROM RequestedEntry\n                 WHERE RequestedEntry.batchId = :batchId)\n    ")
  public actual abstract fun findByRequestBatchId(batchId: Int): List<CacheEntry>

  @Query(`value` =
      "\n        SELECT RequestedEntry.requestedKey\n          FROM RequestedEntry\n         WHERE RequestedEntry.batchId = :batchId\n           AND EXISTS(\n               SELECT RetentionLock.lockId\n                 FROM RetentionLock\n                WHERE RetentionLock.lockKey = RequestedEntry.requestedKey)\n    ")
  public actual abstract fun findEntriesWithLock(batchId: Int): List<String>

  @Query(`value` =
      "\n        UPDATE CacheEntry\n           SET lastAccessed = :lastAccessTime\n         WHERE key = :key  \n    ")
  public actual abstract fun updateLastAccessedTime(key: String, lastAccessTime: Long)

  @Query(`value` =
      "\n        SELECT CacheEntry.*\n          FROM CacheEntry\n         WHERE NOT EXISTS(\n               SELECT RetentionLock.lockId\n                 FROM RetentionLock\n                WHERE RetentionLock.lockKey = CacheEntry.key) \n      ORDER BY lastAccessed ASC           \n         LIMIT :batchSize       \n      \n    ")
  public actual abstract fun findEvictableEntries(batchSize: Int): List<CacheEntry>

  @Query(`value` =
      "\n        SELECT SUM(CacheEntry.storageSize)\n          FROM CacheEntry\n         WHERE NOT EXISTS(\n               SELECT RetentionLock.lockId\n                 FROM RetentionLock\n                WHERE RetentionLock.lockKey = CacheEntry.key)  \n    ")
  public actual abstract fun totalEvictableSize(): Long

  @Delete(entity = Any::class)
  public actual abstract fun delete(entries: List<CacheEntry>)

  @Query(`value` =
      "\n        UPDATE CacheEntry\n           SET responseHeaders = :headers,\n               lastValidated = :lastValidated,\n               lastAccessed = :lastAccessed\n         WHERE key = :key      \n    ")
  public actual abstract fun updateValidation(
    key: String,
    headers: String,
    lastValidated: Long,
    lastAccessed: Long,
  )
}
