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.flow.doorFlow
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.mapNextRow
import com.ustadmobile.door.jdbc.ext.useResults
import com.ustadmobile.door.room.RoomDatabase
import com.ustadmobile.lib.db.entities.ContentEntryPicture
import kotlin.Boolean
import kotlin.IllegalArgumentException
import kotlin.Long
import kotlin.String
import kotlin.collections.List
import kotlinx.coroutines.flow.Flow

public class ContentEntryPictureDao_JdbcImpl(
  public val _db: RoomDatabase,
) : ContentEntryPictureDao() {
  public val _insertAdapterContentEntryPicture_abort: EntityInsertionAdapter<ContentEntryPicture> =
      object : EntityInsertionAdapter<ContentEntryPicture>(_db) {
    override fun makeSql(returnsId: Boolean): String = when(dbType) {
      DoorDbType.SQLITE -> {
        "INSERT INTO ContentEntryPicture (cepUid, cepContentEntryUid, cepUri, cepMd5, cepFileSize, cepTimestamp, cepMimeType, cepActive) VALUES(?, ?, ?, ?, ?, ?, ?, ?)"
      }
      DoorDbType.POSTGRES ->  {
        "INSERT INTO ContentEntryPicture (cepUid, cepContentEntryUid, cepUri, cepMd5, cepFileSize, cepTimestamp, cepMimeType, cepActive) VALUES(COALESCE(?,nextval('ContentEntryPicture_cepUid_seq')), ?, ?, ?, ?, ?, ?, ?)" + if(returnsId) { " RETURNING cepUid" } else "" 
      }
      else -> {
        throw IllegalArgumentException("Unsupported db type")
      }
    }

    override fun bindPreparedStmtToEntity(stmt: PreparedStatement, entity: ContentEntryPicture) {
      if(entity.cepUid == 0L) {
        stmt.setObject(1, null)
      } else {
        stmt.setLong(1, entity.cepUid)
      }
      stmt.setLong(2, entity.cepContentEntryUid)
      stmt.setString(3, entity.cepUri)
      stmt.setString(4, entity.cepMd5)
      stmt.setInt(5, entity.cepFileSize)
      stmt.setLong(6, entity.cepTimestamp)
      stmt.setString(7, entity.cepMimeType)
      stmt.setBoolean(8, entity.cepActive)
    }
  }

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

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

  public override fun insertList(entityList: List<ContentEntryPicture>) {
    _insertAdapterContentEntryPicture_abort.insertList(entityList)
  }

  override suspend fun updateAsync(ContentEntryPicture: ContentEntryPicture) {
    val _sql =
        "UPDATE ContentEntryPicture SET cepContentEntryUid = ?, cepUri = ?, cepMd5 = ?, cepFileSize = ?, cepTimestamp = ?, cepMimeType = ?, cepActive = ? WHERE cepUid = ?"
    _db.prepareAndUseStatementAsync(_sql) {
       _stmt ->
      _stmt.setLong(1, ContentEntryPicture.cepContentEntryUid)
      _stmt.setString(2, ContentEntryPicture.cepUri)
      _stmt.setString(3, ContentEntryPicture.cepMd5)
      _stmt.setInt(4, ContentEntryPicture.cepFileSize)
      _stmt.setLong(5, ContentEntryPicture.cepTimestamp)
      _stmt.setString(6, ContentEntryPicture.cepMimeType)
      _stmt.setBoolean(7, ContentEntryPicture.cepActive)
      _stmt.setLong(8, ContentEntryPicture.cepUid)
      _stmt.executeUpdateAsyncKmp()
    }
  }

  public override fun update(entity: ContentEntryPicture) {
    val _sql =
        "UPDATE ContentEntryPicture SET cepContentEntryUid = ?, cepUri = ?, cepMd5 = ?, cepFileSize = ?, cepTimestamp = ?, cepMimeType = ?, cepActive = ? WHERE cepUid = ?"
    _db.prepareAndUseStatement(_sql) {
       _stmt ->
      _stmt.setLong(1, entity.cepContentEntryUid)
      _stmt.setString(2, entity.cepUri)
      _stmt.setString(3, entity.cepMd5)
      _stmt.setInt(4, entity.cepFileSize)
      _stmt.setLong(5, entity.cepTimestamp)
      _stmt.setString(6, entity.cepMimeType)
      _stmt.setBoolean(7, entity.cepActive)
      _stmt.setLong(8, entity.cepUid)
      _stmt.executeUpdate()
    }
  }

  override suspend fun findByContentEntryUidAsync(entryUid: Long): ContentEntryPicture? =
      _db.prepareAndUseStatementAsync(PreparedStatementConfig(
    sql = """
    |
    |        SELECT * 
    |          FROM ContentEntryPicture 
    |         WHERE cepContentEntryUid = ?
    |           AND cepActive
    |      ORDER BY cepTimestamp DESC 
    |         LIMIT 1
    |         
    """.trimMargin(),
    readOnly = true,)
  ) { _stmt -> 
    _stmt.setLong(1,entryUid)
    _stmt.executeQueryAsyncKmp().useResults{ _result -> 
      _result.mapNextRow(null) {
        val _tmp_cepUid = _result.getLong("cepUid")
        val _tmp_cepContentEntryUid = _result.getLong("cepContentEntryUid")
        val _tmp_cepUri = _result.getString("cepUri")
        val _tmp_cepMd5 = _result.getString("cepMd5")
        val _tmp_cepFileSize = _result.getInt("cepFileSize")
        val _tmp_cepTimestamp = _result.getLong("cepTimestamp")
        val _tmp_cepMimeType = _result.getString("cepMimeType")
        val _tmp_cepActive = _result.getBoolean("cepActive")
        ContentEntryPicture().apply {
          this.cepUid = _tmp_cepUid
          this.cepContentEntryUid = _tmp_cepContentEntryUid
          this.cepUri = _tmp_cepUri
          this.cepMd5 = _tmp_cepMd5
          this.cepFileSize = _tmp_cepFileSize
          this.cepTimestamp = _tmp_cepTimestamp
          this.cepMimeType = _tmp_cepMimeType
          this.cepActive = _tmp_cepActive
        }
      }
    }
  }

  override fun findByContentEntryUidLive(entryUid: Long): Flow<ContentEntryPicture?> =
      _db.doorFlow(arrayOf("ContentEntryPicture")) {
    _db.prepareAndUseStatementAsync(PreparedStatementConfig(
      sql = """
      |
      |         SELECT * 
      |          FROM ContentEntryPicture 
      |         WHERE cepContentEntryUid = ?
      |           AND cepActive
      |      ORDER BY cepTimestamp DESC 
      |         LIMIT 1
      |         
      """.trimMargin(),
      readOnly = true,)
    ) { _stmt -> 
      _stmt.setLong(1,entryUid)
      _stmt.executeQueryAsyncKmp().useResults{ _result -> 
        _result.mapNextRow(null) {
          val _tmp_cepUid = _result.getLong("cepUid")
          val _tmp_cepContentEntryUid = _result.getLong("cepContentEntryUid")
          val _tmp_cepUri = _result.getString("cepUri")
          val _tmp_cepMd5 = _result.getString("cepMd5")
          val _tmp_cepFileSize = _result.getInt("cepFileSize")
          val _tmp_cepTimestamp = _result.getLong("cepTimestamp")
          val _tmp_cepMimeType = _result.getString("cepMimeType")
          val _tmp_cepActive = _result.getBoolean("cepActive")
          ContentEntryPicture().apply {
            this.cepUid = _tmp_cepUid
            this.cepContentEntryUid = _tmp_cepContentEntryUid
            this.cepUri = _tmp_cepUri
            this.cepMd5 = _tmp_cepMd5
            this.cepFileSize = _tmp_cepFileSize
            this.cepTimestamp = _tmp_cepTimestamp
            this.cepMimeType = _tmp_cepMimeType
            this.cepActive = _tmp_cepActive
          }
        }
      }
    }
  }
}
