package com.ustadmobile.core.db.dao

import androidx.paging.DataSource
import androidx.room.Dao
import androidx.room.Query
import com.ustadmobile.lib.db.entities.Comments
import com.ustadmobile.lib.db.entities.CommentsWithPerson
import kotlin.Boolean
import kotlin.Int
import kotlin.Long
import kotlin.Unit
import kotlin.collections.List

@Dao
public actual abstract class CommentsDao : BaseDao<Comments>, OneToManyJoinDao<Comments> {
  @Query(`value` =
      "\n     REPLACE INTO CommentsReplicate(commentsPk, commentsDestination)\n      SELECT DISTINCT Comments.commentsUid AS commentsPk,\n             :newNodeId AS commentsDestination\n        FROM Comments\n       WHERE Comments.commentsLct != COALESCE(\n             (SELECT commentsVersionId\n                FROM CommentsReplicate\n               WHERE commentsPk = Comments.commentsUid\n                 AND commentsDestination = :newNodeId), 0) \n      /*psql ON CONFLICT(commentsPk, commentsDestination) DO UPDATE\n             SET commentsPending = true\n      */       \n    ")
  public actual abstract suspend fun replicateOnNewNode(newNodeId: Long): Unit

  @Query(`value` =
      "\n     REPLACE INTO CommentsReplicate(commentsPk, commentsDestination)\n      SELECT DISTINCT Comments.commentsUid AS commentsPk,\n             UserSession.usClientNodeId AS commentsDestination\n        FROM ChangeLog\n             JOIN Comments\n                 ON ChangeLog.chTableId = 208\n                    AND ChangeLog.chEntityPk = Comments.commentsUid\n             JOIN UserSession \n                  ON UserSession.usStatus = 1\n       WHERE UserSession.usClientNodeId != (\n             SELECT nodeClientId \n               FROM SyncNode\n              LIMIT 1)\n         AND Comments.commentsLct != COALESCE(\n             (SELECT commentsVersionId\n                FROM CommentsReplicate\n               WHERE commentsPk = Comments.commentsUid\n                 AND commentsDestination = UserSession.usClientNodeId), 0)\n     /*psql ON CONFLICT(commentsPk, commentsDestination) DO UPDATE\n         SET commentsPending = true\n      */               \n    ")
  public actual abstract suspend fun replicateOnChange(): Unit

  @Query(`value` =
      "SELECT * FROM Comments WHERE commentsUid = :uid  AND CAST(commentsInActive AS INTEGER) = 0")
  public actual abstract fun findByUidAsync(uid: Long): Comments?

  @Query(`value` =
      "\n        SELECT Comments.*, Person.* \n          FROM Comments\n                LEFT JOIN Person \n                ON Person.personUid = Comments.commentsPersonUid \n         WHERE Comments.commentsEntityType = :entityType \n           AND Comments.commentsEntityUid = :entityUid\n           AND CAST(Comments.commentsFlagged AS INTEGER) = 0\n           AND CAST(Comments.commentsInActive AS INTEGER) = 0\n           AND CAST(Comments.commentsPublic AS INTEGER) = 1\n      ORDER BY Comments.commentsDateTimeAdded DESC \n    ")
  public actual abstract fun findPublicByEntityTypeAndUidLive(entityType: Int, entityUid: Long):
      DataSource.Factory<Int, CommentsWithPerson>

  @Query(`value` =
      "\n        SELECT Comments.*, Person.* FROM Comments\n        LEFT JOIN Person ON Person.personUid = Comments.commentsPersonUid \n        WHERE Comments.commentsEntityType = :entityType \n        AND Comments.commentsEntityUid = :entityUid\n        AND Comments.commentsPersonUid = :personUid OR Comments.commentsToPersonUid = :personUid \n        AND CAST(Comments.commentsFlagged AS INTEGER) = 0\n        AND CAST(Comments.commentsInActive AS INTEGER) = 0\n        AND CAST(Comments.commentsPublic AS INTEGER) = 0\n        AND Person.personUid = :personUid\n        ORDER BY Comments.commentsDateTimeAdded DESC \n    ")
  public actual abstract fun findPrivateByEntityTypeAndUidAndForPersonLive(
    entityType: Int,
    entityUid: Long,
    personUid: Long,
  ): DataSource.Factory<Int, CommentsWithPerson>

  @Query(`value` =
      "\n            SELECT Comments.*, \n                   Person.* \n              FROM Comments\n                   LEFT JOIN Person \n                   ON Person.personUid = Comments.commentsPersonUid\n             WHERE Comments.commentsEntityType = :entityType \n               AND Comments.commentsEntityUid = :entityUid\n               AND Comments.commentSubmitterUid = :submitterUid  \n               AND CAST(Comments.commentsFlagged AS INTEGER) = 0\n               AND CAST(Comments.commentsInActive AS INTEGER) = 0\n               AND CAST(Comments.commentsPublic AS INTEGER) = 0\n          ORDER BY Comments.commentsDateTimeAdded DESC \n    ")
  public actual abstract fun findPrivateByEntityTypeAndUidAndForPersonLive2(
    entityType: Int,
    entityUid: Long,
    submitterUid: Long,
  ): DataSource.Factory<Int, CommentsWithPerson>

  @Query(`value` =
      "\n        SELECT Comments.*, Person.* FROM Comments\n        LEFT JOIN Person ON Person.personUid = Comments.commentsPersonUid \n        WHERE Comments.commentsEntityType = :entityType \n        AND Comments.commentsEntityUid = :entityUid\n        AND CAST(Comments.commentsFlagged AS INTEGER) = 0\n        AND CAST(Comments.commentsInActive AS INTEGER) = 0\n        AND CAST(Comments.commentsPublic AS INTEGER) = 0\n        AND Person.personUid = :personUid\n        ORDER BY Comments.commentsDateTimeAdded DESC \n    ")
  public actual abstract fun findPrivateByEntityTypeAndUidAndPersonLive(
    entityType: Int,
    entityUid: Long,
    personUid: Long,
  ): DataSource.Factory<Int, CommentsWithPerson>

  @Query(`value` =
      "\n        SELECT Comments.*, Person.* FROM Comments\n        LEFT JOIN Person ON Person.personUid = Comments.commentsPersonUid \n        WHERE Comments.commentsEntityType = :entityType \n        AND Comments.commentsEntityUid = :entityUid\n        AND CAST(Comments.commentsFlagged AS INTEGER) = 0\n        AND CAST(Comments.commentsInActive AS INTEGER) = 0\n        AND CAST(Comments.commentsPublic AS INTEGER) = 0\n        AND (Comments.commentsToPersonUid = :personFrom \n         OR Comments.commentsPersonUid = :personFrom)\n        ORDER BY Comments.commentsDateTimeAdded DESC \n    ")
  public actual abstract fun findPrivateCommentsByEntityTypeAndUidAndPersonAndPersonToLive(
    entityType: Int,
    entityUid: Long,
    personFrom: Long,
  ): DataSource.Factory<Int, CommentsWithPerson>

  @Query(`value` =
      "\n        SELECT Comments.*, Person.* FROM Comments\n        LEFT JOIN Person ON Person.personUid = Comments.commentsPersonUid \n        WHERE Comments.commentsEntityType = :entityType \n        AND Comments.commentsEntityUid = :entityUid\n        AND CAST(Comments.commentsFlagged AS INTEGER) = 0\n        AND CAST(Comments.commentsInActive AS INTEGER) = 0\n        AND CAST(Comments.commentsPublic AS INTEGER) = 0\n        AND Comments.commentsPersonUid = :personFrom \n        OR (:personTo = 0 OR Comments.commentsToPersonUid = :personFrom)\n        ORDER BY Comments.commentsDateTimeAdded DESC \n    ")
  public actual abstract fun findPrivateCommentsByEntityTypeAndUidAndPersonAndPersonToTest(
    entityType: Int,
    entityUid: Long,
    personFrom: Long,
    personTo: Long,
  ): List<CommentsWithPerson>

  @Query(`value` =
      "\n        UPDATE Comments \n           SET commentsInActive = :inActive,\n               commentsLct = :changeTime\n         WHERE Comments.commentsUid = :uid\n    ")
  public actual abstract suspend fun updateInActiveByCommentUid(
    uid: Long,
    inActive: Boolean,
    changeTime: Long,
  ): Unit
}
