package com.ustadmobile.core.db.dao

import androidx.lifecycle.LiveData
import androidx.paging.DataSource
import androidx.room.Dao
import androidx.room.Insert
import androidx.room.Query
import androidx.room.Update
import com.ustadmobile.lib.db.entities.EntityRole
import com.ustadmobile.lib.db.entities.EntityRoleWithNameAndRole
import kotlin.Boolean
import kotlin.Int
import kotlin.Long
import kotlin.Unit
import kotlin.collections.List

@Dao
public actual abstract class EntityRoleDao {
  @Query(`value` =
      "\n        SELECT COALESCE((\n               SELECT admin \n                 FROM Person \n                WHERE personUid = :accountPersonUid), 0)\n            OR EXISTS(SELECT EntityRole.erUid FROM EntityRole \n               JOIN Role \n                    ON EntityRole.erRoleUid = Role.roleUid \n               JOIN PersonGroupMember \n                    ON EntityRole.erGroupUid = PersonGroupMember.groupMemberGroupUid\n         WHERE PersonGroupMember.groupMemberPersonUid = :accountPersonUid \n               AND (Role.rolePermissions & :permission) > 0) AS hasPermission")
  public actual abstract suspend fun userHasTableLevelPermission(accountPersonUid: Long,
      permission: Long): Boolean

  @Query(`value` =
      "SELECT * FROM EntityRole WHERE erTableId = :tableId  AND erEntityUid = :entityUid AND erGroupUid = :groupUid  AND erRoleUid = :roleUid ")
  public actual abstract suspend fun findByEntitiyAndPersonGroupAndRole(
    tableId: Int,
    entityUid: Long,
    groupUid: Long,
    roleUid: Long,
  ): List<EntityRole>

  @Query(`value` =
      "\n                    SELECT  \n                    (CASE \n                        WHEN EntityRole.erTableId = 6\tTHEN (SELECT Clazz.clazzName FROM Clazz WHERE Clazz.clazzUid = EntityRole.erEntityUid)\n                        WHEN EntityRole.erTableId = 9\tTHEN (SELECT Person.firstNames||' '||Person.lastName FROM Person WHERE Person.personUid = EntityRole.erEntityUid)\n                        WHEN EntityRole.erTableId = 164\tTHEN (SELECT School.schoolName FROM School WHERE School.schoolUid = EntityRole.erEntityUid)\n                        ELSE '' \n                    END) as entityRoleScopeName,\n                    Role.*, EntityRole.* FROM EntityRole\n                    LEFT JOIN Role ON EntityRole.erRoleUid = Role.roleUid \n                    WHERE EntityRole.erGroupUid = :personGroupUid\n                    AND CAST(EntityRole.erActive AS INTEGER) = 1 \n                ")
  public actual abstract fun filterByPersonWithExtra(personGroupUid: Long):
      DataSource.Factory<Int, EntityRoleWithNameAndRole>

  @Query(`value` =
      "\n                    SELECT  \n                    (CASE \n                        WHEN EntityRole.erTableId = 6\tTHEN (SELECT Clazz.clazzName FROM Clazz WHERE Clazz.clazzUid = EntityRole.erEntityUid)\n                        WHEN EntityRole.erTableId = 9\tTHEN (SELECT Person.firstNames||' '||Person.lastName FROM Person WHERE Person.personUid = EntityRole.erEntityUid)\n                        WHEN EntityRole.erTableId = 164\tTHEN (SELECT School.schoolName FROM School WHERE School.schoolUid = EntityRole.erEntityUid)\n                        ELSE '' \n                    END) as entityRoleScopeName,\n                    Role.*, EntityRole.* FROM EntityRole\n                    LEFT JOIN Role ON EntityRole.erRoleUid = Role.roleUid \n                    WHERE EntityRole.erGroupUid = :personGroupUid\n                    AND CAST(EntityRole.erActive AS INTEGER) = 1 \n                ")
  public actual abstract suspend fun filterByPersonWithExtraAsList(personGroupUid: Long):
      List<EntityRoleWithNameAndRole>

  @Query(`value` = "SELECT * FROM EntityRole WHERE erUid = :uid")
  public actual abstract suspend fun findByUidAsync(uid: Long): EntityRole?

  @Query(`value` = "SELECT * FROM EntityRole WHERE erUid = :uid")
  public actual abstract fun findByUidLive(uid: Long): LiveData<EntityRole?>

  @Update(onConflict = 3)
  public actual abstract suspend fun updateAsync(entity: EntityRole): Int

  @Insert(onConflict = 1)
  public actual abstract suspend fun insertOrReplace(entity: EntityRole): Unit
}
