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.mapNextRow
import com.ustadmobile.door.jdbc.ext.useResults
import com.ustadmobile.door.room.RoomDatabase
import com.ustadmobile.lib.db.entities.xapi.VerbEntity
import kotlin.Boolean
import kotlin.IllegalArgumentException
import kotlin.Long
import kotlin.String
import kotlin.collections.List

public class VerbDao_JdbcImpl(
  public val _db: RoomDatabase,
) : VerbDao() {
  public val _insertAdapterVerbEntity_ignore: EntityInsertionAdapter<VerbEntity> = object :
      EntityInsertionAdapter<VerbEntity>(_db) {
    override fun makeSql(returnsId: Boolean): String = when(dbType) {
      DoorDbType.SQLITE -> {
        "INSERT  OR IGNORE INTO VerbEntity (verbUid, verbUrlId, verbDeleted, verbLct) VALUES(?, ?, ?, ?)"
      }
      DoorDbType.POSTGRES ->  {
        "INSERT INTO VerbEntity (verbUid, verbUrlId, verbDeleted, verbLct) VALUES(?, ?, ?, ?) ON CONFLICT (verbUid) DO NOTHING" + if(returnsId) { " RETURNING verbUid" } else "" 
      }
      else -> {
        throw IllegalArgumentException("Unsupported db type")
      }
    }

    override fun bindPreparedStmtToEntity(stmt: PreparedStatement, entity: VerbEntity) {
      stmt.setLong(1, entity.verbUid)
      stmt.setString(2, entity.verbUrlId)
      stmt.setBoolean(3, entity.verbDeleted)
      stmt.setLong(4, entity.verbLct)
    }
  }

  override suspend fun insertOrIgnoreAsync(entities: List<VerbEntity>) {
    _insertAdapterVerbEntity_ignore.insertListAsync(entities)
  }

  override suspend fun findByUid(uid: Long): VerbEntity? =
      _db.prepareAndUseStatementAsync(PreparedStatementConfig(
    sql = """
    |
    |        SELECT VerbEntity.*
    |        FROM VerbEntity
    |        WHERE VerbEntity.verbUid = ? 
    |    
    """.trimMargin(),
    readOnly = true,)
  ) { _stmt -> 
    _stmt.setLong(1,uid)
    _stmt.executeQueryAsyncKmp().useResults{ _result -> 
      _result.mapNextRow(null) {
        val _tmp_verbUid = _result.getLong("verbUid")
        val _tmp_verbUrlId = _result.getString("verbUrlId")
        val _tmp_verbDeleted = _result.getBoolean("verbDeleted")
        val _tmp_verbLct = _result.getLong("verbLct")
        VerbEntity().apply {
          this.verbUid = _tmp_verbUid
          this.verbUrlId = _tmp_verbUrlId
          this.verbDeleted = _tmp_verbDeleted
          this.verbLct = _tmp_verbLct
        }
      }
    }
  }

  override suspend fun findByVerbUrl(verbUrl: String): VerbEntity? =
      _db.prepareAndUseStatementAsync(PreparedStatementConfig(
    sql = """
    |
    |        SELECT VerbEntity.*
    |        FROM VerbEntity
    |        WHERE VerbEntity.verbUrlId = ? 
    |    
    """.trimMargin(),
    readOnly = true,)
  ) { _stmt -> 
    _stmt.setString(1,verbUrl)
    _stmt.executeQueryAsyncKmp().useResults{ _result -> 
      _result.mapNextRow(null) {
        val _tmp_verbUid = _result.getLong("verbUid")
        val _tmp_verbUrlId = _result.getString("verbUrlId")
        val _tmp_verbDeleted = _result.getBoolean("verbDeleted")
        val _tmp_verbLct = _result.getLong("verbLct")
        VerbEntity().apply {
          this.verbUid = _tmp_verbUid
          this.verbUrlId = _tmp_verbUrlId
          this.verbDeleted = _tmp_verbDeleted
          this.verbLct = _tmp_verbLct
        }
      }
    }
  }
}
