package com.ustadmobile.core.db.dao.xapi

import com.ustadmobile.door.DoorDbType
import com.ustadmobile.door.EntityInsertionAdapter
import com.ustadmobile.door.PreparedStatementConfig
import com.ustadmobile.door.ext.prepareAndUseStatementAsync
import com.ustadmobile.door.jdbc.PreparedStatement
import com.ustadmobile.door.jdbc.ext.executeQueryAsyncKmp
import com.ustadmobile.door.jdbc.ext.executeUpdateAsyncKmp
import com.ustadmobile.door.jdbc.ext.getStringNonNull
import com.ustadmobile.door.jdbc.ext.mapNextRow
import com.ustadmobile.door.jdbc.ext.useResults
import com.ustadmobile.door.room.RoomDatabase
import com.ustadmobile.lib.db.entities.xapi.XapiSessionEntity
import kotlin.Boolean
import kotlin.IllegalArgumentException
import kotlin.Long
import kotlin.String

public class XapiSessionEntityDao_JdbcImpl(
  public val _db: RoomDatabase,
) : XapiSessionEntityDao() {
  public val _insertAdapterXapiSessionEntity_abort: EntityInsertionAdapter<XapiSessionEntity> =
      object : EntityInsertionAdapter<XapiSessionEntity>(_db) {
    override fun makeSql(returnsId: Boolean): String = when(dbType) {
      DoorDbType.SQLITE -> {
        "INSERT INTO XapiSessionEntity (xseUid, xseLastMod, xseRegistrationHi, xseRegistrationLo, xseUsUid, xseAccountPersonUid, xseActorUid, xseAccountUsername, xseClazzUid, xseCbUid, xseContentEntryUid, xseContentEntryVersionUid, xseRootActivityId, xseRootActivityUid, xseStartTime, xseExpireTime, xseAuth, xseCompleted, knownActorUidToPersonUids) VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"
      }
      DoorDbType.POSTGRES ->  {
        "INSERT INTO XapiSessionEntity (xseUid, xseLastMod, xseRegistrationHi, xseRegistrationLo, xseUsUid, xseAccountPersonUid, xseActorUid, xseAccountUsername, xseClazzUid, xseCbUid, xseContentEntryUid, xseContentEntryVersionUid, xseRootActivityId, xseRootActivityUid, xseStartTime, xseExpireTime, xseAuth, xseCompleted, knownActorUidToPersonUids) VALUES(COALESCE(?,nextval('XapiSessionEntity_xseUid_seq')), ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)" + if(returnsId) { " RETURNING xseUid" } else "" 
      }
      else -> {
        throw IllegalArgumentException("Unsupported db type")
      }
    }

    override fun bindPreparedStmtToEntity(stmt: PreparedStatement, entity: XapiSessionEntity) {
      if(entity.xseUid == 0L) {
        stmt.setObject(1, null)
      } else {
        stmt.setLong(1, entity.xseUid)
      }
      stmt.setLong(2, entity.xseLastMod)
      stmt.setLong(3, entity.xseRegistrationHi)
      stmt.setLong(4, entity.xseRegistrationLo)
      stmt.setLong(5, entity.xseUsUid)
      stmt.setLong(6, entity.xseAccountPersonUid)
      stmt.setLong(7, entity.xseActorUid)
      stmt.setString(8, entity.xseAccountUsername)
      stmt.setLong(9, entity.xseClazzUid)
      stmt.setLong(10, entity.xseCbUid)
      stmt.setLong(11, entity.xseContentEntryUid)
      stmt.setLong(12, entity.xseContentEntryVersionUid)
      stmt.setString(13, entity.xseRootActivityId)
      stmt.setLong(14, entity.xseRootActivityUid)
      stmt.setLong(15, entity.xseStartTime)
      stmt.setLong(16, entity.xseExpireTime)
      stmt.setString(17, entity.xseAuth)
      stmt.setBoolean(18, entity.xseCompleted)
      stmt.setString(19, entity.knownActorUidToPersonUids)
    }
  }

  override suspend fun insertAsync(xapiSessionEntity: XapiSessionEntity) {
    _insertAdapterXapiSessionEntity_abort.insertAsync(xapiSessionEntity)
  }

  override suspend fun findByUidAsync(uid: Long): XapiSessionEntity? =
      _db.prepareAndUseStatementAsync(PreparedStatementConfig(
    sql = """
    |
    |        SELECT XapiSessionEntity.*
    |          FROM XapiSessionEntity
    |         WHERE XapiSessionEntity.xseUid = ?
    |    
    """.trimMargin(),
    readOnly = true,)
  ) { _stmt -> 
    _stmt.setLong(1,uid)
    _stmt.executeQueryAsyncKmp().useResults{ _result -> 
      _result.mapNextRow(null) {
        val _tmp_xseUid = _result.getLong("xseUid")
        val _tmp_xseLastMod = _result.getLong("xseLastMod")
        val _tmp_xseRegistrationHi = _result.getLong("xseRegistrationHi")
        val _tmp_xseRegistrationLo = _result.getLong("xseRegistrationLo")
        val _tmp_xseUsUid = _result.getLong("xseUsUid")
        val _tmp_xseAccountPersonUid = _result.getLong("xseAccountPersonUid")
        val _tmp_xseActorUid = _result.getLong("xseActorUid")
        val _tmp_xseAccountUsername = _result.getStringNonNull("xseAccountUsername")
        val _tmp_xseClazzUid = _result.getLong("xseClazzUid")
        val _tmp_xseCbUid = _result.getLong("xseCbUid")
        val _tmp_xseContentEntryUid = _result.getLong("xseContentEntryUid")
        val _tmp_xseContentEntryVersionUid = _result.getLong("xseContentEntryVersionUid")
        val _tmp_xseRootActivityId = _result.getStringNonNull("xseRootActivityId")
        val _tmp_xseRootActivityUid = _result.getLong("xseRootActivityUid")
        val _tmp_xseStartTime = _result.getLong("xseStartTime")
        val _tmp_xseExpireTime = _result.getLong("xseExpireTime")
        val _tmp_xseAuth = _result.getString("xseAuth")
        val _tmp_xseCompleted = _result.getBoolean("xseCompleted")
        val _tmp_knownActorUidToPersonUids = _result.getStringNonNull("knownActorUidToPersonUids")
        XapiSessionEntity().apply {
          this.xseUid = _tmp_xseUid
          this.xseLastMod = _tmp_xseLastMod
          this.xseRegistrationHi = _tmp_xseRegistrationHi
          this.xseRegistrationLo = _tmp_xseRegistrationLo
          this.xseUsUid = _tmp_xseUsUid
          this.xseAccountPersonUid = _tmp_xseAccountPersonUid
          this.xseActorUid = _tmp_xseActorUid
          this.xseAccountUsername = _tmp_xseAccountUsername
          this.xseClazzUid = _tmp_xseClazzUid
          this.xseCbUid = _tmp_xseCbUid
          this.xseContentEntryUid = _tmp_xseContentEntryUid
          this.xseContentEntryVersionUid = _tmp_xseContentEntryVersionUid
          this.xseRootActivityId = _tmp_xseRootActivityId
          this.xseRootActivityUid = _tmp_xseRootActivityUid
          this.xseStartTime = _tmp_xseStartTime
          this.xseExpireTime = _tmp_xseExpireTime
          this.xseAuth = _tmp_xseAuth
          this.xseCompleted = _tmp_xseCompleted
          this.knownActorUidToPersonUids = _tmp_knownActorUidToPersonUids
        }
      }
    }
  }

  override suspend fun updateLatestAsComplete(
    completed: Boolean,
    time: Long,
    xseUid: Long,
  ) {
    _db.prepareAndUseStatementAsync(PreparedStatementConfig(
      sql = """
      |
      |        UPDATE XapiSessionEntity
      |           SET xseCompleted = ?,
      |               xseLastMod = ?
      |         WHERE xseUid = ?
      |
      |    
      """.trimMargin(),
      readOnly = false,)
    ) { _stmt -> 
      _stmt.setBoolean(1,completed)
      _stmt.setLong(2,time)
      _stmt.setLong(3,xseUid)
      _stmt.executeUpdateAsyncKmp()
    }
  }

  override suspend fun findMostRecentSessionByActorAndActivity(
    accountPersonUid: Long,
    actorUid: Long,
    xseRootActivityUid: Long,
    contentEntryVersionUid: Long,
    clazzUid: Long,
  ): XapiSessionEntity? = _db.prepareAndUseStatementAsync(PreparedStatementConfig(
    sql = """
    |
    |        SELECT XapiSessionEntity.*
    |          FROM XapiSessionEntity
    |         WHERE XapiSessionEntity.xseRootActivityUid = ?
    |           AND XapiSessionEntity.xseActorUid = ?
    |           AND XapiSessionEntity.xseContentEntryVersionUid = ?
    |           AND XapiSessionEntity.xseClazzUid = ?
    |           AND EXISTS(
    |               SELECT 1
    |                 FROM ActorEntity
    |                WHERE ActorEntity.actorUid = ?
    |                  AND ActorEntity.actorPersonUid = ?)     
    |    
    """.trimMargin(),
    readOnly = true,)
  ) { _stmt -> 
    _stmt.setLong(1,xseRootActivityUid)
    _stmt.setLong(2,actorUid)
    _stmt.setLong(3,contentEntryVersionUid)
    _stmt.setLong(4,clazzUid)
    _stmt.setLong(5,actorUid)
    _stmt.setLong(6,accountPersonUid)
    _stmt.executeQueryAsyncKmp().useResults{ _result -> 
      _result.mapNextRow(null) {
        val _tmp_xseUid = _result.getLong("xseUid")
        val _tmp_xseLastMod = _result.getLong("xseLastMod")
        val _tmp_xseRegistrationHi = _result.getLong("xseRegistrationHi")
        val _tmp_xseRegistrationLo = _result.getLong("xseRegistrationLo")
        val _tmp_xseUsUid = _result.getLong("xseUsUid")
        val _tmp_xseAccountPersonUid = _result.getLong("xseAccountPersonUid")
        val _tmp_xseActorUid = _result.getLong("xseActorUid")
        val _tmp_xseAccountUsername = _result.getStringNonNull("xseAccountUsername")
        val _tmp_xseClazzUid = _result.getLong("xseClazzUid")
        val _tmp_xseCbUid = _result.getLong("xseCbUid")
        val _tmp_xseContentEntryUid = _result.getLong("xseContentEntryUid")
        val _tmp_xseContentEntryVersionUid = _result.getLong("xseContentEntryVersionUid")
        val _tmp_xseRootActivityId = _result.getStringNonNull("xseRootActivityId")
        val _tmp_xseRootActivityUid = _result.getLong("xseRootActivityUid")
        val _tmp_xseStartTime = _result.getLong("xseStartTime")
        val _tmp_xseExpireTime = _result.getLong("xseExpireTime")
        val _tmp_xseAuth = _result.getString("xseAuth")
        val _tmp_xseCompleted = _result.getBoolean("xseCompleted")
        val _tmp_knownActorUidToPersonUids = _result.getStringNonNull("knownActorUidToPersonUids")
        XapiSessionEntity().apply {
          this.xseUid = _tmp_xseUid
          this.xseLastMod = _tmp_xseLastMod
          this.xseRegistrationHi = _tmp_xseRegistrationHi
          this.xseRegistrationLo = _tmp_xseRegistrationLo
          this.xseUsUid = _tmp_xseUsUid
          this.xseAccountPersonUid = _tmp_xseAccountPersonUid
          this.xseActorUid = _tmp_xseActorUid
          this.xseAccountUsername = _tmp_xseAccountUsername
          this.xseClazzUid = _tmp_xseClazzUid
          this.xseCbUid = _tmp_xseCbUid
          this.xseContentEntryUid = _tmp_xseContentEntryUid
          this.xseContentEntryVersionUid = _tmp_xseContentEntryVersionUid
          this.xseRootActivityId = _tmp_xseRootActivityId
          this.xseRootActivityUid = _tmp_xseRootActivityUid
          this.xseStartTime = _tmp_xseStartTime
          this.xseExpireTime = _tmp_xseExpireTime
          this.xseAuth = _tmp_xseAuth
          this.xseCompleted = _tmp_xseCompleted
          this.knownActorUidToPersonUids = _tmp_knownActorUidToPersonUids
        }
      }
    }
  }
}
