package com.ustadmobile.core.db.dao

import com.ustadmobile.door.DoorDbType
import com.ustadmobile.door.EntityInsertionAdapter
import com.ustadmobile.door.PreparedStatementConfig
import com.ustadmobile.door.entities.OutgoingReplication
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.mapRows
import com.ustadmobile.door.jdbc.ext.useResults
import com.ustadmobile.door.room.RoomDatabase
import kotlin.Boolean
import kotlin.IllegalArgumentException
import kotlin.String
import kotlin.collections.List

public class OutgoingReplicationDao_JdbcImpl(
  public val _db: RoomDatabase,
) : OutgoingReplicationDao() {
  public val _insertAdapterOutgoingReplication_abort: EntityInsertionAdapter<OutgoingReplication> =
      object : EntityInsertionAdapter<OutgoingReplication>(_db) {
    override fun makeSql(returnsId: Boolean): String = when(dbType) {
      DoorDbType.SQLITE -> {
        "INSERT INTO OutgoingReplication (destNodeId, orPk1, orPk2, orPk3, orPk4, orTableId, orUid) VALUES(?, ?, ?, ?, ?, ?, ?)"
      }
      DoorDbType.POSTGRES ->  {
        "INSERT INTO OutgoingReplication (destNodeId, orPk1, orPk2, orPk3, orPk4, orTableId, orUid) VALUES(?, ?, ?, ?, ?, ?, COALESCE(?,nextval('OutgoingReplication_orUid_seq')))" + if(returnsId) { " RETURNING orUid" } else "" 
      }
      else -> {
        throw IllegalArgumentException("Unsupported db type")
      }
    }

    override fun bindPreparedStmtToEntity(stmt: PreparedStatement, entity: OutgoingReplication) {
      stmt.setLong(1, entity.destNodeId)
      stmt.setLong(2, entity.orPk1)
      stmt.setLong(3, entity.orPk2)
      stmt.setLong(4, entity.orPk3)
      stmt.setLong(5, entity.orPk4)
      stmt.setInt(6, entity.orTableId)
      if(entity.orUid == 0L) {
        stmt.setObject(7, null)
      } else {
        stmt.setLong(7, entity.orUid)
      }
    }
  }

  override suspend fun insert(outgoing: List<OutgoingReplication>) {
    _insertAdapterOutgoingReplication_abort.insertListAsync(outgoing)
  }

  override suspend fun listReplications(): List<OutgoingReplication> =
      _db.prepareAndUseStatementAsync(PreparedStatementConfig(
    sql = """
    |
    |        SELECT OutgoingReplication.*
    |          FROM OutgoingReplication
    |    
    """.trimMargin(),
    readOnly = true,)
  ) { _stmt -> 
    _stmt.executeQueryAsyncKmp().useResults{ _result -> 
      _result.mapRows {
        val _tmp_destNodeId = _result.getLong("destNodeId")
        val _tmp_orPk1 = _result.getLong("orPk1")
        val _tmp_orPk2 = _result.getLong("orPk2")
        val _tmp_orPk3 = _result.getLong("orPk3")
        val _tmp_orPk4 = _result.getLong("orPk4")
        val _tmp_orTableId = _result.getInt("orTableId")
        val _tmp_orUid = _result.getLong("orUid")
        OutgoingReplication().apply {
          this.destNodeId = _tmp_destNodeId
          this.orPk1 = _tmp_orPk1
          this.orPk2 = _tmp_orPk2
          this.orPk3 = _tmp_orPk3
          this.orPk4 = _tmp_orPk4
          this.orTableId = _tmp_orTableId
          this.orUid = _tmp_orUid
        }
      }
    }
  }
}
