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.RawQuery
import androidx.room.Update
import com.ustadmobile.door.DoorQuery
import com.ustadmobile.lib.db.entities.Report
import kotlin.Boolean
import kotlin.Int
import kotlin.Long
import kotlin.String
import kotlin.Unit
import kotlin.collections.List

@Dao
public actual abstract class ReportDao : BaseDao<Report> {
  @Query(`value` =
      "\n     REPLACE INTO ReportReplicate(reportPk, reportDestination)\n      SELECT DISTINCT Report.reportUid AS reportPk,\n             :newNodeId AS reportDestination\n        FROM Report\n             JOIN UserSession\n                  ON UserSession.usStatus = 1\n                     AND CAST(Report.isTemplate AS INTEGER) = 1\n       WHERE Report.reportLct != COALESCE(\n             (SELECT reportVersionId\n                FROM ReportReplicate\n               WHERE reportPk = Report.reportUid\n                 AND reportDestination = :newNodeId), 0) \n      /*psql ON CONFLICT(reportPk, reportDestination) DO UPDATE\n             SET reportPending = true\n      */       \n    ")
  public actual abstract suspend fun replicateOnNewNodeTemplates(newNodeId: Long): Unit

  @Query(`value` =
      "\n REPLACE INTO ReportReplicate(reportPk, reportDestination)\n  SELECT DISTINCT Report.reportUid AS reportUid,\n         UserSession.usClientNodeId AS reportDestination\n    FROM ChangeLog\n         JOIN Report\n              ON ChangeLog.chTableId = 101 \n                 AND ChangeLog.chEntityPk = Report.reportUid\n         JOIN UserSession\n              ON UserSession.usStatus = 1\n                 AND CAST(Report.isTemplate AS INTEGER) = 1\n   WHERE UserSession.usClientNodeId != (\n         SELECT nodeClientId \n           FROM SyncNode\n          LIMIT 1)\n     AND Report.reportLct != COALESCE(\n         (SELECT reportVersionId\n            FROM ReportReplicate\n           WHERE reportPk = Report.reportUid\n             AND reportDestination = UserSession.usClientNodeId), 0)\n /*psql ON CONFLICT(reportPk, reportDestination) DO UPDATE\n     SET reportPending = true\n  */               \n ")
  public actual abstract suspend fun replicateOnChangeTemplates(): Unit

  @RawQuery(observedEntities = arrayOf())
  public actual abstract fun getResults(query: DoorQuery): List<Report>

  @Query(`value` =
      "SELECT * FROM REPORT WHERE NOT reportInactive \n        AND reportOwnerUid = :personUid\n        AND isTemplate = :isTemplate\n        AND reportTitle LIKE :searchBit\n        ORDER BY priority, CASE(:sortOrder)\n            WHEN 1 THEN Report.reportTitle\n            ELSE ''\n        END ASC,\n        CASE(:sortOrder)\n            WHEN 2 THEN Report.reportTitle\n            ELSE ''\n        END DESC\n            ")
  public actual abstract fun findAllActiveReport(
    searchBit: String,
    personUid: Long,
    sortOrder: Int,
    isTemplate: Boolean,
  ): DataSource.Factory<Int, Report>

  @Query(`value` = "SELECT * FROM Report WHERE reportUid = :entityUid")
  public actual abstract suspend fun findByUid(entityUid: Long): Report?

  @Update(onConflict = 3)
  public actual abstract suspend fun updateAsync(entity: Report): Unit

  @Query(`value` = "SELECT * From Report WHERE  reportUid = :uid")
  public actual abstract fun findByUidLive(uid: Long): LiveData<Report?>

  @Query(`value` =
      "SELECT * FROM REPORT WHERE NOT reportInactive \n        AND isTemplate = :isTemplate\n        ORDER BY priority ASC\n            ")
  public actual abstract fun findAllActiveReportLive(isTemplate: Boolean): LiveData<List<Report>>

  @Query(`value` =
      "SELECT * FROM REPORT WHERE NOT reportInactive \n        AND isTemplate = :isTemplate\n        ORDER BY priority ASC\n            ")
  public actual abstract fun findAllActiveReportList(isTemplate: Boolean): List<Report>

  @Query(`value` = "SELECT reportUid FROM Report WHERE reportUid IN (:uidList)")
  public actual abstract fun findByUidList(uidList: List<Long>): List<Long>

  @Query(`value` =
      "\n        UPDATE Report \n           SET reportInactive = :toggleVisibility,\n               reportLct = :updateTime \n         WHERE reportUid IN (:selectedItem)\n    ")
  public actual abstract suspend fun toggleVisibilityReportItems(
    toggleVisibility: Boolean,
    selectedItem: List<Long>,
    updateTime: Long,
  ): Unit

  @Insert(onConflict = 1)
  public actual abstract fun replaceList(entityList: List<Report>): Unit
}
