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

public class ContentEntryImportJobDao_JdbcImpl(
  public val _db: RoomDatabase,
) : ContentEntryImportJobDao() {
  public val _insertAdapterContentEntryImportJob_abort:
      EntityInsertionAdapter<ContentEntryImportJob> = object :
      EntityInsertionAdapter<ContentEntryImportJob>(_db) {
    override fun makeSql(returnsId: Boolean): String = when(dbType) {
      DoorDbType.SQLITE -> {
        "INSERT INTO ContentEntryImportJob (cjiUid, sourceUri, cjiOriginalFilename, cjiContentEntryUid, cjiParentContentEntryUid, cjiContentEntryVersion, cjiItemProgress, cjiItemTotal, cjiStatus, cjiRecursiveStatus, cjiPluginId, cjiParentCjiUid, cjiStartTime, cjiFinishTime, cjiContentDeletedOnCancellation, cjiCompressionLevel, cjiError, cjiErrorDismissed, cjiOwnerPersonUid, cjiParams) VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"
      }
      DoorDbType.POSTGRES ->  {
        "INSERT INTO ContentEntryImportJob (cjiUid, sourceUri, cjiOriginalFilename, cjiContentEntryUid, cjiParentContentEntryUid, cjiContentEntryVersion, cjiItemProgress, cjiItemTotal, cjiStatus, cjiRecursiveStatus, cjiPluginId, cjiParentCjiUid, cjiStartTime, cjiFinishTime, cjiContentDeletedOnCancellation, cjiCompressionLevel, cjiError, cjiErrorDismissed, cjiOwnerPersonUid, cjiParams) VALUES(COALESCE(?,nextval('ContentEntryImportJob_cjiUid_seq')), ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)" + if(returnsId) { " RETURNING cjiUid" } else "" 
      }
      else -> {
        throw IllegalArgumentException("Unsupported db type")
      }
    }

    override fun bindPreparedStmtToEntity(stmt: PreparedStatement, entity: ContentEntryImportJob) {
      if(entity.cjiUid == 0L) {
        stmt.setObject(1, null)
      } else {
        stmt.setLong(1, entity.cjiUid)
      }
      stmt.setString(2, entity.sourceUri)
      stmt.setString(3, entity.cjiOriginalFilename)
      stmt.setLong(4, entity.cjiContentEntryUid)
      stmt.setLong(5, entity.cjiParentContentEntryUid)
      stmt.setLong(6, entity.cjiContentEntryVersion)
      stmt.setLong(7, entity.cjiItemProgress)
      stmt.setLong(8, entity.cjiItemTotal)
      stmt.setInt(9, entity.cjiStatus)
      stmt.setInt(10, entity.cjiRecursiveStatus)
      stmt.setInt(11, entity.cjiPluginId)
      stmt.setLong(12, entity.cjiParentCjiUid)
      stmt.setLong(13, entity.cjiStartTime)
      stmt.setLong(14, entity.cjiFinishTime)
      stmt.setBoolean(15, entity.cjiContentDeletedOnCancellation)
      stmt.setInt(16, entity.cjiCompressionLevel)
      stmt.setString(17, entity.cjiError)
      stmt.setBoolean(18, entity.cjiErrorDismissed)
      stmt.setLong(19, entity.cjiOwnerPersonUid)
      stmt.setString(20, entity.cjiParams)
    }
  }

  override suspend fun insertJobItem(jobItem: ContentEntryImportJob): Long {
    val _retVal = _insertAdapterContentEntryImportJob_abort.insertAndReturnIdAsync(jobItem)
    return _retVal
  }

  override suspend fun updateItemStatus(cjiUid: Long, status: Int) {
    _db.prepareAndUseStatementAsync(PreparedStatementConfig(
      sql = """
      |
      |        UPDATE ContentEntryImportJob 
      |           SET cjiStatus = ?
      |         WHERE cjiUid= ?  
      |    
      """.trimMargin(),
      readOnly = false,)
    ) { _stmt -> 
      _stmt.setInt(1,status)
      _stmt.setLong(2,cjiUid)
      _stmt.executeUpdateAsyncKmp()
    }
  }

  override suspend fun updateItemStatusAndError(
    cjiUid: Long,
    status: Int,
    error: String?,
  ) {
    _db.prepareAndUseStatementAsync(PreparedStatementConfig(
      sql = """
      |
      |        UPDATE ContentEntryImportJob 
      |           SET cjiStatus = ?,
      |               cjiError = ?
      |         WHERE cjiUid= ?  
      |    
      """.trimMargin(),
      readOnly = false,)
    ) { _stmt -> 
      _stmt.setInt(1,status)
      _stmt.setString(2,error)
      _stmt.setLong(3,cjiUid)
      _stmt.executeUpdateAsyncKmp()
    }
  }

  override suspend fun updateErrorDismissed(cjiUid: Long, dismissed: Boolean) {
    _db.prepareAndUseStatementAsync(PreparedStatementConfig(
      sql = """
      |
      |        UPDATE ContentEntryImportJob
      |           SET cjiErrorDismissed = ?
      |         WHERE cjiUid = ?  
      |    
      """.trimMargin(),
      readOnly = false,)
    ) { _stmt -> 
      _stmt.setBoolean(1,dismissed)
      _stmt.setLong(2,cjiUid)
      _stmt.executeUpdateAsyncKmp()
    }
  }

  override suspend fun updateItemProgress(
    cjiUid: Long,
    cjiProgress: Long,
    cjiTotal: Long,
  ) {
    _db.prepareAndUseStatementAsync(PreparedStatementConfig(
      sql = """
      |
      |        UPDATE ContentEntryImportJob
      |           SET cjiItemProgress = ?,
      |               cjiItemTotal = ?
      |         WHERE cjiUid = ?     
      |    
      """.trimMargin(),
      readOnly = false,)
    ) { _stmt -> 
      _stmt.setLong(1,cjiProgress)
      _stmt.setLong(2,cjiTotal)
      _stmt.setLong(3,cjiUid)
      _stmt.executeUpdateAsyncKmp()
    }
  }

  override suspend fun findByUidAsync(cjiUid: Long): ContentEntryImportJob? =
      _db.prepareAndUseStatementAsync(PreparedStatementConfig(
    sql = """
    |
    |        SELECT ContentEntryImportJob.*
    |          FROM ContentEntryImportJob
    |         WHERE cjiUid = ? 
    |    
    """.trimMargin(),
    readOnly = true,)
  ) { _stmt -> 
    _stmt.setLong(1,cjiUid)
    _stmt.executeQueryAsyncKmp().useResults{ _result -> 
      _result.mapNextRow(null) {
        val _tmp_cjiUid = _result.getLong("cjiUid")
        val _tmp_sourceUri = _result.getString("sourceUri")
        val _tmp_cjiOriginalFilename = _result.getString("cjiOriginalFilename")
        val _tmp_cjiContentEntryUid = _result.getLong("cjiContentEntryUid")
        val _tmp_cjiParentContentEntryUid = _result.getLong("cjiParentContentEntryUid")
        val _tmp_cjiContentEntryVersion = _result.getLong("cjiContentEntryVersion")
        val _tmp_cjiItemProgress = _result.getLong("cjiItemProgress")
        val _tmp_cjiItemTotal = _result.getLong("cjiItemTotal")
        val _tmp_cjiStatus = _result.getInt("cjiStatus")
        val _tmp_cjiRecursiveStatus = _result.getInt("cjiRecursiveStatus")
        val _tmp_cjiPluginId = _result.getInt("cjiPluginId")
        val _tmp_cjiParentCjiUid = _result.getLong("cjiParentCjiUid")
        val _tmp_cjiStartTime = _result.getLong("cjiStartTime")
        val _tmp_cjiFinishTime = _result.getLong("cjiFinishTime")
        val _tmp_cjiContentDeletedOnCancellation =
            _result.getBoolean("cjiContentDeletedOnCancellation")
        val _tmp_cjiCompressionLevel = _result.getInt("cjiCompressionLevel")
        val _tmp_cjiError = _result.getString("cjiError")
        val _tmp_cjiErrorDismissed = _result.getBoolean("cjiErrorDismissed")
        val _tmp_cjiOwnerPersonUid = _result.getLong("cjiOwnerPersonUid")
        val _tmp_cjiParams = _result.getString("cjiParams")
        ContentEntryImportJob().apply {
          this.cjiUid = _tmp_cjiUid
          this.sourceUri = _tmp_sourceUri
          this.cjiOriginalFilename = _tmp_cjiOriginalFilename
          this.cjiContentEntryUid = _tmp_cjiContentEntryUid
          this.cjiParentContentEntryUid = _tmp_cjiParentContentEntryUid
          this.cjiContentEntryVersion = _tmp_cjiContentEntryVersion
          this.cjiItemProgress = _tmp_cjiItemProgress
          this.cjiItemTotal = _tmp_cjiItemTotal
          this.cjiStatus = _tmp_cjiStatus
          this.cjiRecursiveStatus = _tmp_cjiRecursiveStatus
          this.cjiPluginId = _tmp_cjiPluginId
          this.cjiParentCjiUid = _tmp_cjiParentCjiUid
          this.cjiStartTime = _tmp_cjiStartTime
          this.cjiFinishTime = _tmp_cjiFinishTime
          this.cjiContentDeletedOnCancellation = _tmp_cjiContentDeletedOnCancellation
          this.cjiCompressionLevel = _tmp_cjiCompressionLevel
          this.cjiError = _tmp_cjiError
          this.cjiErrorDismissed = _tmp_cjiErrorDismissed
          this.cjiOwnerPersonUid = _tmp_cjiOwnerPersonUid
          this.cjiParams = _tmp_cjiParams
        }
      }
    }
  }

  override suspend fun findOwnerByUidAsync(cjiUid: Long): Long =
      _db.prepareAndUseStatementAsync(PreparedStatementConfig(
    sql = """
    |
    |        SELECT COALESCE(
    |               (SELECT ContentEntryImportJob.cjiOwnerPersonUid
    |                  FROM ContentEntryImportJob
    |                 WHERE ContentEntryImportJob.cjiUid = ?), 0)
    |    
    """.trimMargin(),
    readOnly = true,)
  ) { _stmt -> 
    _stmt.setLong(1,cjiUid)
    _stmt.executeQueryAsyncKmp().useResults{ _result -> 
      _result.mapNextRow(0L) {
        _result.getLong(1)
      }
    }
  }

  override fun findInProgressJobsByContentEntryUid(contentEntryUid: Long):
      Flow<List<ContentEntryImportJobProgress>> = _db.doorFlow(arrayOf("ContentEntryImportJob")) {
    _db.prepareAndUseStatementAsync(PreparedStatementConfig(
      sql = """
      |
      |        SELECT ContentEntryImportJob.cjiUid,
      |               ContentEntryImportJob.cjiItemProgress,
      |               ContentEntryImportJob.cjiItemTotal,
      |               ContentEntryImportJob.cjiStatus,
      |               ContentEntryImportJob.cjiError,
      |               ContentEntryImportJob.cjiOwnerPersonUid
      |          FROM ContentEntryImportJob
      |         WHERE ContentEntryImportJob.cjiContentEntryUid = ?
      |           AND (   ContentEntryImportJob.cjiStatus BETWEEN 4 AND 20
      |                OR (ContentEntryImportJob.cjiStatus = 25 AND NOT ContentEntryImportJob.cjiErrorDismissed))
      |    
      """.trimMargin(),
      readOnly = true,)
    ) { _stmt -> 
      _stmt.setLong(1,contentEntryUid)
      _stmt.executeQueryAsyncKmp().useResults{ _result -> 
        _result.mapRows {
          val _tmp_cjiUid = _result.getLong("cjiUid")
          val _tmp_cjiItemProgress = _result.getLong("cjiItemProgress")
          val _tmp_cjiItemTotal = _result.getLong("cjiItemTotal")
          val _tmp_cjiStatus = _result.getInt("cjiStatus")
          val _tmp_cjiError = _result.getString("cjiError")
          val _tmp_cjiOwnerPersonUid = _result.getLong("cjiOwnerPersonUid")
          ContentEntryImportJobProgress().apply {
            this.cjiUid = _tmp_cjiUid
            this.cjiItemProgress = _tmp_cjiItemProgress
            this.cjiItemTotal = _tmp_cjiItemTotal
            this.cjiStatus = _tmp_cjiStatus
            this.cjiError = _tmp_cjiError
            this.cjiOwnerPersonUid = _tmp_cjiOwnerPersonUid
          }
        }
      }
    }
  }

  override suspend fun findInProgressJobsByContentEntryUidAsync(contentEntryUid: Long):
      List<ContentEntryImportJobProgress> = _db.prepareAndUseStatementAsync(PreparedStatementConfig(
    sql = """
    |
    |        SELECT ContentEntryImportJob.cjiUid,
    |               ContentEntryImportJob.cjiItemProgress,
    |               ContentEntryImportJob.cjiItemTotal,
    |               ContentEntryImportJob.cjiStatus,
    |               ContentEntryImportJob.cjiError,
    |               ContentEntryImportJob.cjiOwnerPersonUid
    |          FROM ContentEntryImportJob
    |         WHERE ContentEntryImportJob.cjiContentEntryUid = ?
    |           AND (   ContentEntryImportJob.cjiStatus BETWEEN 4 AND 20
    |                OR (ContentEntryImportJob.cjiStatus = 25 AND NOT ContentEntryImportJob.cjiErrorDismissed))
    |    
    """.trimMargin(),
    readOnly = true,)
  ) { _stmt -> 
    _stmt.setLong(1,contentEntryUid)
    _stmt.executeQueryAsyncKmp().useResults{ _result -> 
      _result.mapRows {
        val _tmp_cjiUid = _result.getLong("cjiUid")
        val _tmp_cjiItemProgress = _result.getLong("cjiItemProgress")
        val _tmp_cjiItemTotal = _result.getLong("cjiItemTotal")
        val _tmp_cjiStatus = _result.getInt("cjiStatus")
        val _tmp_cjiError = _result.getString("cjiError")
        val _tmp_cjiOwnerPersonUid = _result.getLong("cjiOwnerPersonUid")
        ContentEntryImportJobProgress().apply {
          this.cjiUid = _tmp_cjiUid
          this.cjiItemProgress = _tmp_cjiItemProgress
          this.cjiItemTotal = _tmp_cjiItemTotal
          this.cjiStatus = _tmp_cjiStatus
          this.cjiError = _tmp_cjiError
          this.cjiOwnerPersonUid = _tmp_cjiOwnerPersonUid
        }
      }
    }
  }
}
