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

public class HolidayDao_JdbcImpl(
  public val _db: RoomDatabase,
) : HolidayDao() {
  public val _insertAdapterHoliday_abort: EntityInsertionAdapter<Holiday> = object :
      EntityInsertionAdapter<Holiday>(_db) {
    override fun makeSql(returnsId: Boolean): String = when(dbType) {
      DoorDbType.SQLITE -> {
        "INSERT INTO Holiday (holUid, holMasterCsn, holLocalCsn, holLastModBy, holLct, holActive, holHolidayCalendarUid, holStartTime, holEndTime, holName) VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"
      }
      DoorDbType.POSTGRES ->  {
        "INSERT INTO Holiday (holUid, holMasterCsn, holLocalCsn, holLastModBy, holLct, holActive, holHolidayCalendarUid, holStartTime, holEndTime, holName) VALUES(COALESCE(?,nextval('Holiday_holUid_seq')), ?, ?, ?, ?, ?, ?, ?, ?, ?)" + if(returnsId) { " RETURNING holUid" } else "" 
      }
      else -> {
        throw IllegalArgumentException("Unsupported db type")
      }
    }

    override fun bindPreparedStmtToEntity(stmt: PreparedStatement, entity: Holiday) {
      if(entity.holUid == 0L) {
        stmt.setObject(1, null)
      } else {
        stmt.setLong(1, entity.holUid)
      }
      stmt.setLong(2, entity.holMasterCsn)
      stmt.setLong(3, entity.holLocalCsn)
      stmt.setInt(4, entity.holLastModBy)
      stmt.setLong(5, entity.holLct)
      stmt.setBoolean(6, entity.holActive)
      stmt.setLong(7, entity.holHolidayCalendarUid)
      stmt.setLong(8, entity.holStartTime)
      stmt.setLong(9, entity.holEndTime)
      stmt.setString(10, entity.holName)
    }
  }

  override suspend fun updateAsync(entity: Holiday) {
    _insertAdapterHoliday_abort.insertAsync(entity)
  }

  public override fun insert(entity: Holiday): Long {
    val _retVal = _insertAdapterHoliday_abort.insertAndReturnId(entity)
    return _retVal
  }

  public override suspend fun insertAsync(entity: Holiday): Long {
    val _retVal = _insertAdapterHoliday_abort.insertAndReturnIdAsync(entity)
    return _retVal
  }

  public override fun insertList(entityList: List<Holiday>) {
    _insertAdapterHoliday_abort.insertList(entityList)
  }

  public override suspend fun insertListAsync(entityList: List<Holiday>) {
    _insertAdapterHoliday_abort.insertListAsync(entityList)
  }

  public override fun update(entity: Holiday) {
    val _sql =
        "UPDATE Holiday SET holMasterCsn = ?, holLocalCsn = ?, holLastModBy = ?, holLct = ?, holActive = ?, holHolidayCalendarUid = ?, holStartTime = ?, holEndTime = ?, holName = ? WHERE holUid = ?"
    _db.prepareAndUseStatement(_sql) {
       _stmt ->
      _stmt.setLong(1, entity.holMasterCsn)
      _stmt.setLong(2, entity.holLocalCsn)
      _stmt.setInt(3, entity.holLastModBy)
      _stmt.setLong(4, entity.holLct)
      _stmt.setBoolean(5, entity.holActive)
      _stmt.setLong(6, entity.holHolidayCalendarUid)
      _stmt.setLong(7, entity.holStartTime)
      _stmt.setLong(8, entity.holEndTime)
      _stmt.setString(9, entity.holName)
      _stmt.setLong(10, entity.holUid)
      _stmt.executeUpdate()
    }
  }

  public override suspend fun updateListAsync(entityList: List<Holiday>) {
    val _sql =
        "UPDATE Holiday SET holMasterCsn = ?, holLocalCsn = ?, holLastModBy = ?, holLct = ?, holActive = ?, holHolidayCalendarUid = ?, holStartTime = ?, holEndTime = ?, holName = ? WHERE holUid = ?"
    _db.prepareAndUseStatementAsync(_sql) {
       _stmt ->
      _stmt.getConnection().setAutoCommit(false)
      for(_entity in entityList) {
        _stmt.setLong(1, _entity.holMasterCsn)
        _stmt.setLong(2, _entity.holLocalCsn)
        _stmt.setInt(3, _entity.holLastModBy)
        _stmt.setLong(4, _entity.holLct)
        _stmt.setBoolean(5, _entity.holActive)
        _stmt.setLong(6, _entity.holHolidayCalendarUid)
        _stmt.setLong(7, _entity.holStartTime)
        _stmt.setLong(8, _entity.holEndTime)
        _stmt.setString(9, _entity.holName)
        _stmt.setLong(10, _entity.holUid)
        _stmt.executeUpdateAsyncKmp()
      }
      _stmt.getConnection().commit()
    }
  }

  override fun findByHolidayCalendaUid(holidayCalendarUid: Long): List<Holiday> =
      _db.prepareAndUseStatement(PreparedStatementConfig(
    sql = "SELECT * FROM Holiday WHERE holHolidayCalendarUid = ?",
    readOnly = true,)
  ) { _stmt -> 
    _stmt.setLong(1,holidayCalendarUid)
    _stmt.executeQuery().useResults{ _result -> 
      _result.mapRows {
        val _tmp_holUid = _result.getLong("holUid")
        val _tmp_holMasterCsn = _result.getLong("holMasterCsn")
        val _tmp_holLocalCsn = _result.getLong("holLocalCsn")
        val _tmp_holLastModBy = _result.getInt("holLastModBy")
        val _tmp_holLct = _result.getLong("holLct")
        val _tmp_holActive = _result.getBoolean("holActive")
        val _tmp_holHolidayCalendarUid = _result.getLong("holHolidayCalendarUid")
        val _tmp_holStartTime = _result.getLong("holStartTime")
        val _tmp_holEndTime = _result.getLong("holEndTime")
        val _tmp_holName = _result.getString("holName")
        Holiday().apply {
          this.holUid = _tmp_holUid
          this.holMasterCsn = _tmp_holMasterCsn
          this.holLocalCsn = _tmp_holLocalCsn
          this.holLastModBy = _tmp_holLastModBy
          this.holLct = _tmp_holLct
          this.holActive = _tmp_holActive
          this.holHolidayCalendarUid = _tmp_holHolidayCalendarUid
          this.holStartTime = _tmp_holStartTime
          this.holEndTime = _tmp_holEndTime
          this.holName = _tmp_holName
        }
      }
    }
  }

  override suspend fun findByHolidayCalendaUidAsync(holidayCalendarUid: Long): List<Holiday> =
      _db.prepareAndUseStatementAsync(PreparedStatementConfig(
    sql = "SELECT * FROM Holiday WHERE holHolidayCalendarUid = ?",
    readOnly = true,)
  ) { _stmt -> 
    _stmt.setLong(1,holidayCalendarUid)
    _stmt.executeQueryAsyncKmp().useResults{ _result -> 
      _result.mapRows {
        val _tmp_holUid = _result.getLong("holUid")
        val _tmp_holMasterCsn = _result.getLong("holMasterCsn")
        val _tmp_holLocalCsn = _result.getLong("holLocalCsn")
        val _tmp_holLastModBy = _result.getInt("holLastModBy")
        val _tmp_holLct = _result.getLong("holLct")
        val _tmp_holActive = _result.getBoolean("holActive")
        val _tmp_holHolidayCalendarUid = _result.getLong("holHolidayCalendarUid")
        val _tmp_holStartTime = _result.getLong("holStartTime")
        val _tmp_holEndTime = _result.getLong("holEndTime")
        val _tmp_holName = _result.getString("holName")
        Holiday().apply {
          this.holUid = _tmp_holUid
          this.holMasterCsn = _tmp_holMasterCsn
          this.holLocalCsn = _tmp_holLocalCsn
          this.holLastModBy = _tmp_holLastModBy
          this.holLct = _tmp_holLct
          this.holActive = _tmp_holActive
          this.holHolidayCalendarUid = _tmp_holHolidayCalendarUid
          this.holStartTime = _tmp_holStartTime
          this.holEndTime = _tmp_holEndTime
          this.holName = _tmp_holName
        }
      }
    }
  }

  override fun updateActiveByUid(
    holidayUid: Long,
    active: Boolean,
    changeTime: Long,
  ) {
    _db.prepareAndUseStatement(PreparedStatementConfig(
      sql = """
      |
      |        UPDATE Holiday 
      |           SET holActive = ?, 
      |               holLct = ?
      |         WHERE holUid = ?
      """.trimMargin(),
      readOnly = false,)
    ) { _stmt -> 
      _stmt.setBoolean(1,active)
      _stmt.setLong(2,changeTime)
      _stmt.setLong(3,holidayUid)
      _stmt.executeUpdate()
    }
  }
}
