package com.ustadmobile.core.db.dao

import androidx.room.Dao
import androidx.room.Insert
import androidx.room.Query
import androidx.room.Update
import com.ustadmobile.lib.db.composites.PersonAndClazzLogAttendanceRecord
import com.ustadmobile.lib.db.entities.ClazzLogAttendanceRecord
import com.ustadmobile.lib.db.entities.ClazzLogAttendanceRecordWithPerson
import kotlin.Any
import kotlin.Long
import kotlin.collections.List

@Dao
public actual abstract class ClazzLogAttendanceRecordDao : BaseDao<ClazzLogAttendanceRecord> {
  @Insert(
    entity = Any::class,
    onConflict = 3,
  )
  public actual abstract suspend fun insertListAsync(entities: List<ClazzLogAttendanceRecord>)

  @Query(`value` =
      "SELECT * from ClazzLogAttendanceRecord WHERE clazzLogAttendanceRecordUid = :uid")
  public actual abstract fun findByUid(uid: Long): ClazzLogAttendanceRecord?

  @Update(
    entity = Any::class,
    onConflict = 3,
  )
  public actual abstract suspend fun updateListAsync(entities: List<ClazzLogAttendanceRecord>)

  @Query(`value` =
      "SELECT ClazzLogAttendanceRecord.*, Person.*\n         FROM ClazzLogAttendanceRecord \n         LEFT JOIN Person ON ClazzLogAttendanceRecord.clazzLogAttendanceRecordPersonUid = Person.personUid\n         WHERE clazzLogAttendanceRecordClazzLogUid = :clazzLogUid")
  public actual abstract suspend fun findByClazzLogUid(clazzLogUid: Long):
      List<ClazzLogAttendanceRecordWithPerson>

  @Query(`value` =
      "\n        UPDATE ClazzLogAttendanceRecord\n           SET clazzLogAttendanceRecordClazzLogUid = :newClazzLogUid,\n               clazzLogAttendanceRecordLastChangedTime = :changedTime\n        WHERE clazzLogAttendanceRecordClazzLogUid = :oldClazzLogUid\n    ")
  public actual abstract fun updateRescheduledClazzLogUids(
    oldClazzLogUid: Long,
    newClazzLogUid: Long,
    changedTime: Long,
  )

  @Query(`value` =
      "\n        \n        WITH CurrentlyEnrolledPersonUids(enroledPersonUid) AS\n              (SELECT DISTINCT ClazzEnrolment.clazzEnrolmentPersonUid AS enroledPersonUid\n                 FROM ClazzEnrolment\n                WHERE ClazzEnrolment.clazzEnrolmentClazzUid = :clazzUid\n                  AND ClazzEnrolment.clazzEnrolmentRole = 1000\n                  AND :time BETWEEN ClazzEnrolment.clazzEnrolmentDateJoined AND ClazzEnrolment.clazzEnrolmentDateLeft)\n    \n                  \n        SELECT Person.*, ClazzLogAttendanceRecord.*, PersonPicture.*\n          FROM Person\n               LEFT JOIN ClazzLogAttendanceRecord \n                         ON ClazzLogAttendanceRecord.clazzLogAttendanceRecordUid = \n                            (SELECT ClazzLogAttendanceRecordInner.clazzLogAttendanceRecordUid  \n                               FROM ClazzLogAttendanceRecord ClazzLogAttendanceRecordInner\n                              WHERE ClazzLogAttendanceRecordInner.clazzLogAttendanceRecordClazzLogUid = :clazzLogUid\n                                AND ClazzLogAttendanceRecordInner.clazzLogAttendanceRecordPersonUid = Person.personUid\n                           ORDER BY ClazzLogAttendanceRecordInner.clazzLogAttendanceRecordLastChangedTime DESC     \n                              LIMIT 1  \n                            )\n               LEFT JOIN PersonPicture\n                         ON PersonPicture.personPictureUid = Person.personUid\n         WHERE Person.personUid IN \n               (SELECT CurrentlyEnrolledPersonUids.enroledPersonUid\n                  FROM CurrentlyEnrolledPersonUids)                \n    ")
  public actual abstract suspend fun findByClazzAndTime(
    clazzUid: Long,
    clazzLogUid: Long,
    time: Long,
  ): List<PersonAndClazzLogAttendanceRecord>

  @Insert(
    onConflict = 1,
    entity = Any::class,
  )
  public actual abstract suspend fun upsertListAsync(entityList: List<ClazzLogAttendanceRecord>)
}
