package com.ustadmobile.core.db.dao

import androidx.room.Dao
import androidx.room.Query
import com.ustadmobile.lib.db.entities.StateEntity
import kotlin.Boolean
import kotlin.Long
import kotlin.String
import kotlin.Unit
import kotlin.collections.List

@Dao
public actual abstract class StateDao : BaseDao<StateEntity> {
  @Query(`value` =
      "\n     REPLACE INTO StateEntityReplicate(sePk, seDestination)\n      SELECT DISTINCT StateEntity.stateUid AS sePk,\n             :newNodeId AS seDestination\n        FROM StateEntity\n             JOIN AgentEntity\n                  ON StateEntity.agentUid = AgentEntity.agentUid\n             JOIN UserSession\n                  ON AgentEntity.agentPersonUid = UserSession.usPersonUid\n       WHERE UserSession.usClientNodeId = :newNodeId\n         AND UserSession.usStatus = 1\n         AND StateEntity.stateLct != COALESCE(\n             (SELECT seVersionId\n                FROM StateEntityReplicate\n               WHERE sePk = StateEntity.stateUid\n                 AND seDestination = :newNodeId), 0) \n      /*psql ON CONFLICT(sePk, seDestination) DO UPDATE\n             SET sePending = true\n      */       \n ")
  public actual abstract suspend fun replicateOnNewNode(newNodeId: Long): Unit

  @Query(`value` =
      "\n REPLACE INTO StateEntityReplicate(sePk, seDestination)\n  SELECT DISTINCT StateEntity.stateUid AS seUid,\n         UserSession.usClientNodeId AS seDestination\n    FROM ChangeLog\n         JOIN StateEntity\n              ON ChangeLog.chTableId = 70\n                 AND ChangeLog.chEntityPk = StateEntity.stateUid\n         JOIN AgentEntity\n              ON StateEntity.agentUid = AgentEntity.agentUid\n         JOIN UserSession\n              ON AgentEntity.agentPersonUid = UserSession.usPersonUid\n                 AND UserSession.usStatus = 1\n   WHERE UserSession.usClientNodeId != (\n         SELECT nodeClientId \n           FROM SyncNode\n          LIMIT 1)\n     AND StateEntity.stateLct != COALESCE(\n         (SELECT seVersionId\n            FROM StateEntityReplicate\n           WHERE sePk = StateEntity.stateUid\n             AND seDestination = UserSession.usClientNodeId), 0)\n /*psql ON CONFLICT(sePk, seDestination) DO UPDATE\n     SET sePending = true\n  */               \n    ")
  public actual abstract suspend fun replicateOnChange(): Unit

  @Query(`value` =
      "SELECT * FROM StateEntity WHERE stateId = :id AND agentUid = :agentUid AND activityId = :activityId AND registration = :registration AND isIsactive LIMIT 1")
  public actual abstract fun findByStateId(
    id: String?,
    agentUid: Long,
    activityId: String?,
    registration: String?,
  ): StateEntity?

  @Query(`value` =
      "SELECT * FROM StateEntity WHERE agentUid = :agentUid AND activityId = :activityId AND registration = :registration AND isIsactive AND timestamp > :since")
  public actual abstract fun findStateIdByAgentAndActivity(
    agentUid: Long,
    activityId: String,
    registration: String,
    since: String,
  ): List<StateEntity>

  @Query(`value` =
      "\n        UPDATE StateEntity \n           SET isIsactive = :isActive,\n               stateLct = :updateTime\n         WHERE agentUid = :agentUid AND activityId = :activityId \n           AND registration = :registration AND isIsactive\n    ")
  public actual abstract fun updateStateToInActive(
    agentUid: Long,
    activityId: String,
    registration: String,
    isActive: Boolean,
    updateTime: Long,
  ): Unit

  @Query(`value` =
      "\n        UPDATE StateEntity \n          SET isIsactive = :isActive, \n              stateLct = :updateTime\n        WHERE stateId = :stateId AND agentUid = :agentUid \n          AND activityId = :activityId AND registration = :registration \n          AND isIsactive")
  public actual abstract fun setStateInActive(
    stateId: String,
    agentUid: Long,
    activityId: String,
    registration: String,
    isActive: Boolean,
    updateTime: Long,
  ): Unit
}
