package com.ustadmobile.core.db.dao

import androidx.lifecycle.LiveData
import androidx.paging.DataSource
import androidx.room.Dao
import androidx.room.Query
import androidx.room.Update
import com.ustadmobile.lib.db.entities.DiscussionPost
import com.ustadmobile.lib.db.entities.DiscussionPostWithDetails
import kotlin.Int
import kotlin.Long
import kotlin.String
import kotlin.Unit

@Dao
public actual abstract class DiscussionPostDao : BaseDao<DiscussionPost> {
  @Query(`value` =
      "\n     REPLACE INTO DiscussionPostReplicate(discussionPostPk, discussionPostDestination)\n      SELECT DISTINCT DiscussionPost.discussionPostUid AS discussionPostPk,\n             :newNodeId AS discussionPostDestination\n             \n       FROM UserSession\n             JOIN PersonGroupMember \n                  ON UserSession.usPersonUid = PersonGroupMember.groupMemberPersonUid\n             \n               JOIN ScopedGrant\n                    ON ScopedGrant.sgGroupUid = PersonGroupMember.groupMemberGroupUid\n                        AND (ScopedGrant.sgPermissions & \n        \n                  2 \n                  \n                       ) > 0\n               JOIN Clazz \n                    ON \n            ((ScopedGrant.sgTableId = -2\n                                AND ScopedGrant.sgEntityUid = -2)\n                            OR (ScopedGrant.sgTableId = 6\n                                AND ScopedGrant.sgEntityUid = Clazz.clazzUid)\n                            OR (ScopedGrant.sgTableId = 164\n                                AND ScopedGrant.sgEntityUid = Clazz.clazzSchoolUid))\n        \n        \n                  \n            JOIN DiscussionPost \n                 ON DiscussionPost.discussionPostClazzUid = Clazz.clazzUid\n                 \n       WHERE DiscussionPost.discussionPostLct != COALESCE(\n             (SELECT discussionPostVersionId\n                FROM discussionPostReplicate\n               WHERE discussionPostPk = DiscussionPost.discussionPostUid\n                 AND discussionPostDestination = :newNodeId), 0) \n      /*psql ON CONFLICT(discussionPostPk, discussionPostDestination) DO UPDATE\n             SET discussionPostPending = true\n      */       \n    ")
  public actual abstract suspend fun replicateOnNewNode(newNodeId: Long): Unit

  @Query(`value` =
      "\n        REPLACE INTO DiscussionPostReplicate(discussionPostPk, discussionPostDestination)\n          SELECT DISTINCT DiscussionPost.discussionPostUid AS discussionPostUid,\n                 UserSession.usClientNodeId AS discussionPostDestination\n            FROM ChangeLog\n                 JOIN DiscussionPost\n                     ON ChangeLog.chTableId = 132\n                        AND ChangeLog.chEntityPk = DiscussionPost.discussionPostUid\n                        \n                        \n                 JOIN Clazz \n                      ON Clazz.clazzUid = DiscussionPost.discussionPostClazzUid\n                      \n                 \n            JOIN ScopedGrant\n                 ON \n            ((ScopedGrant.sgTableId = -2\n                                AND ScopedGrant.sgEntityUid = -2)\n                            OR (ScopedGrant.sgTableId = 6\n                                AND ScopedGrant.sgEntityUid = Clazz.clazzUid)\n                            OR (ScopedGrant.sgTableId = 164\n                                AND ScopedGrant.sgEntityUid = Clazz.clazzSchoolUid))\n        \n                    AND (ScopedGrant.sgPermissions & \n        \n                  2\n                 \n              \n                                                       ) > 0\n             JOIN PersonGroupMember AS PrsGrpMbr\n                   ON ScopedGrant.sgGroupUid = PrsGrpMbr.groupMemberGroupUid\n                                               \n              JOIN UserSession\n                   ON UserSession.usPersonUid = PrsGrpMbr.groupMemberPersonUid\n                      AND UserSession.usStatus = 1\n        \n                 \n           WHERE UserSession.usClientNodeId != (\n                 SELECT nodeClientId \n                   FROM SyncNode\n                  LIMIT 1)\n             AND DiscussionPost.discussionPostLct != COALESCE(\n                 (SELECT discussionPostVersionId\n                    FROM discussionPostReplicate\n                   WHERE discussionPostPk = DiscussionPost.discussionPostUid\n                     AND DiscussionPostDestination = UserSession.usClientNodeId), 0)\n         /*psql ON CONFLICT(discussionPostPk, discussionPostDestination) DO UPDATE\n             SET discussionPostPending = true\n          */               \n    ")
  public actual abstract suspend fun replicateOnChange(): Unit

  @Query(`value` =
      "\n        SELECT DiscussionPost.*,\n            Person.firstNames as authorPersonFirstNames,\n            Person.lastName as authorPersonLastName,\n            (\n                SELECT Message.messageText \n                  FROM Message \n                 WHERE Message.messageTableId = 132\n                   AND Message.messageEntityUid = DiscussionPost.discussionPostUid \n                 ORDER BY messageTimestamp \n                  DESC LIMIT 1\n            ) AS postLatestMessage,\n            (\n                SELECT COUNT(*) \n                  FROM Message\n                 WHERE Message.messageTableId = 132\n                   AND Message.messageEntityUid = DiscussionPost.discussionPostUid \n                   \n            ) AS postRepliesCount, \n            \n            (\n                SELECT Message.messageTimestamp \n                  FROM Message \n                 WHERE Message.messageTableId = 132\n                   AND Message.messageEntityUid = DiscussionPost.discussionPostUid \n                 ORDER BY messageTimestamp \n                  DESC LIMIT 1\n            ) AS postLatestMessageTimestamp\n             \n          FROM DiscussionPost     \n          LEFT JOIN Person ON Person.personUid = DiscussionPost.discussionPostStartedPersonUid\n         WHERE DiscussionPost.discussionPostDiscussionTopicUid = :discussionTopicUid\n           AND CAST(DiscussionPost.discussionPostVisible AS INTEGER) = 1\n           AND CAST(DiscussionPost.discussionPostArchive AS INTEGER) = 0\n      ORDER BY DiscussionPost.discussionPostStartDate DESC\n    ")
  public actual abstract fun getPostsByDiscussionTopic(discussionTopicUid: Long):
      DataSource.Factory<Int, DiscussionPostWithDetails>

  @Query(`value` =
      "\n        SELECT DiscussionPost.discussionPostTitle \n          FROM DiscussionPost \n         WHERE DiscussionPost.discussionPostUid = :postUid\n    ")
  public actual abstract suspend fun getPostTitle(postUid: Long): String?

  @Query(`value` =
      "\n        SELECT * \n         FROM DiscussionPost\n        WHERE DiscussionPost.discussionPostUid = :uid\n    ")
  public actual abstract suspend fun findByUid(uid: Long): DiscussionPost?

  @Query(`value` =
      "\n        SELECT DiscussionPost.*,\n            Person.firstNames as authorPersonFirstNames,\n            Person.lastName as authorPersonLastName,\n            '' AS postLatestMessage,\n            0 AS postRepliesCount, \n            DiscussionPost.discussionPostLct AS postLatestMessageTimestamp\n             \n          FROM DiscussionPost     \n          LEFT JOIN Person ON Person.personUid = DiscussionPost.discussionPostStartedPersonUid\n         WHERE DiscussionPost.discussionPostUid = :uid\n           \n    ")
  public actual abstract suspend fun findWithDetailsByUid(uid: Long): DiscussionPostWithDetails?

  @Query(`value` =
      "\n        SELECT DiscussionPost.*,\n            Person.firstNames as authorPersonFirstNames,\n            Person.lastName as authorPersonLastName,\n            '' AS postLatestMessage,\n            0 AS postRepliesCount, \n            DiscussionPost.discussionPostLct AS postLatestMessageTimestamp\n             \n          FROM DiscussionPost     \n          LEFT JOIN Person ON Person.personUid = DiscussionPost.discussionPostStartedPersonUid\n         WHERE DiscussionPost.discussionPostUid = :uid\n           \n    ")
  public actual abstract fun findWithDetailsByUidLive(uid: Long):
      LiveData<DiscussionPostWithDetails?>

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