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.jdbc.PreparedStatement
import com.ustadmobile.door.jdbc.ext.executeQueryAsyncKmp
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.StudentResultAndCourseBlockSourcedId
import com.ustadmobile.lib.db.entities.StudentResult
import kotlin.Boolean
import kotlin.IllegalArgumentException
import kotlin.Long
import kotlin.String
import kotlin.collections.List

public class StudentResultDao_JdbcImpl(
  public val _db: RoomDatabase,
) : StudentResultDao() {
  public val _insertAdapterStudentResult_abort: EntityInsertionAdapter<StudentResult> = object :
      EntityInsertionAdapter<StudentResult>(_db) {
    override fun makeSql(returnsId: Boolean): String = when(dbType) {
      DoorDbType.SQLITE -> {
        "INSERT INTO StudentResult (srUid, srSourcedId, srCourseBlockUid, srLineItemSourcedId, srLineItemHref, srClazzUid, srAssignmentUid, srStatus, srMetaData, srStudentPersonUid, srStudentPersonSourcedId, srStudentGroupId, srMarkerPersonUid, srMarkerGroupId, srScoreStatus, srScore, srScoreDate, srLastModified, srComment, srAppId, srDeleted) VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"
      }
      DoorDbType.POSTGRES ->  {
        "INSERT INTO StudentResult (srUid, srSourcedId, srCourseBlockUid, srLineItemSourcedId, srLineItemHref, srClazzUid, srAssignmentUid, srStatus, srMetaData, srStudentPersonUid, srStudentPersonSourcedId, srStudentGroupId, srMarkerPersonUid, srMarkerGroupId, srScoreStatus, srScore, srScoreDate, srLastModified, srComment, srAppId, srDeleted) VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)" + if(returnsId) { " RETURNING srUid" } else "" 
      }
      else -> {
        throw IllegalArgumentException("Unsupported db type")
      }
    }

    override fun bindPreparedStmtToEntity(stmt: PreparedStatement, entity: StudentResult) {
      stmt.setLong(1, entity.srUid)
      stmt.setString(2, entity.srSourcedId)
      stmt.setLong(3, entity.srCourseBlockUid)
      stmt.setString(4, entity.srLineItemSourcedId)
      stmt.setString(5, entity.srLineItemHref)
      stmt.setLong(6, entity.srClazzUid)
      stmt.setLong(7, entity.srAssignmentUid)
      stmt.setInt(8, entity.srStatus)
      stmt.setString(9, entity.srMetaData)
      stmt.setLong(10, entity.srStudentPersonUid)
      stmt.setString(11, entity.srStudentPersonSourcedId)
      stmt.setInt(12, entity.srStudentGroupId)
      stmt.setLong(13, entity.srMarkerPersonUid)
      stmt.setInt(14, entity.srMarkerGroupId)
      stmt.setInt(15, entity.srScoreStatus)
      stmt.setFloat(16, entity.srScore)
      stmt.setLong(17, entity.srScoreDate)
      stmt.setLong(18, entity.srLastModified)
      stmt.setString(19, entity.srComment)
      stmt.setString(20, entity.srAppId)
      stmt.setBoolean(21, entity.srDeleted)
    }
  }

  public val _insertAdapterStudentResult_upsert: EntityInsertionAdapter<StudentResult> = object :
      EntityInsertionAdapter<StudentResult>(_db) {
    override fun makeSql(returnsId: Boolean): String = when(dbType) {
      DoorDbType.SQLITE -> {
        "INSERT OR REPLACE INTO StudentResult (srUid, srSourcedId, srCourseBlockUid, srLineItemSourcedId, srLineItemHref, srClazzUid, srAssignmentUid, srStatus, srMetaData, srStudentPersonUid, srStudentPersonSourcedId, srStudentGroupId, srMarkerPersonUid, srMarkerGroupId, srScoreStatus, srScore, srScoreDate, srLastModified, srComment, srAppId, srDeleted) VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"
      }
      DoorDbType.POSTGRES ->  {
        "INSERT INTO StudentResult (srUid, srSourcedId, srCourseBlockUid, srLineItemSourcedId, srLineItemHref, srClazzUid, srAssignmentUid, srStatus, srMetaData, srStudentPersonUid, srStudentPersonSourcedId, srStudentGroupId, srMarkerPersonUid, srMarkerGroupId, srScoreStatus, srScore, srScoreDate, srLastModified, srComment, srAppId, srDeleted) VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) ON CONFLICT (srUid) DO UPDATE SET srSourcedId = excluded.srSourcedId,srCourseBlockUid = excluded.srCourseBlockUid,srLineItemSourcedId = excluded.srLineItemSourcedId,srLineItemHref = excluded.srLineItemHref,srClazzUid = excluded.srClazzUid,srAssignmentUid = excluded.srAssignmentUid,srStatus = excluded.srStatus,srMetaData = excluded.srMetaData,srStudentPersonUid = excluded.srStudentPersonUid,srStudentPersonSourcedId = excluded.srStudentPersonSourcedId,srStudentGroupId = excluded.srStudentGroupId,srMarkerPersonUid = excluded.srMarkerPersonUid,srMarkerGroupId = excluded.srMarkerGroupId,srScoreStatus = excluded.srScoreStatus,srScore = excluded.srScore,srScoreDate = excluded.srScoreDate,srLastModified = excluded.srLastModified,srComment = excluded.srComment,srAppId = excluded.srAppId,srDeleted = excluded.srDeleted" + if(returnsId) { " RETURNING srUid" } else "" 
      }
      else -> {
        throw IllegalArgumentException("Unsupported db type")
      }
    }

    override fun bindPreparedStmtToEntity(stmt: PreparedStatement, entity: StudentResult) {
      stmt.setLong(1, entity.srUid)
      stmt.setString(2, entity.srSourcedId)
      stmt.setLong(3, entity.srCourseBlockUid)
      stmt.setString(4, entity.srLineItemSourcedId)
      stmt.setString(5, entity.srLineItemHref)
      stmt.setLong(6, entity.srClazzUid)
      stmt.setLong(7, entity.srAssignmentUid)
      stmt.setInt(8, entity.srStatus)
      stmt.setString(9, entity.srMetaData)
      stmt.setLong(10, entity.srStudentPersonUid)
      stmt.setString(11, entity.srStudentPersonSourcedId)
      stmt.setInt(12, entity.srStudentGroupId)
      stmt.setLong(13, entity.srMarkerPersonUid)
      stmt.setInt(14, entity.srMarkerGroupId)
      stmt.setInt(15, entity.srScoreStatus)
      stmt.setFloat(16, entity.srScore)
      stmt.setLong(17, entity.srScoreDate)
      stmt.setLong(18, entity.srLastModified)
      stmt.setString(19, entity.srComment)
      stmt.setString(20, entity.srAppId)
      stmt.setBoolean(21, entity.srDeleted)
    }
  }

  override suspend fun insertListAsync(list: List<StudentResult>) {
    _insertAdapterStudentResult_abort.insertListAsync(list)
  }

  override suspend fun upsertAsync(studentResult: StudentResult) {
    _insertAdapterStudentResult_upsert.insertAsync(studentResult)
  }

  override suspend fun findByClazzAndStudent(
    clazzUid: Long,
    studentPersonUid: Long,
    accountPersonUid: Long,
  ): List<StudentResultAndCourseBlockSourcedId> =
      _db.prepareAndUseStatementAsync(PreparedStatementConfig(
    sql = """
    |
    |        SELECT StudentResult.*,
    |               CourseBlock.cbSourcedId AS cbSourcedId
    |          FROM StudentResult
    |               LEFT JOIN CourseBlock
    |                         ON StudentResult.srCourseBlockUid = CourseBlock.cbUid 
    |         WHERE StudentResult.srClazzUid = ?
    |           AND StudentResult.srStudentPersonUid = ?
    |           AND ? = ?
    |    
    """.trimMargin(),
    readOnly = true,)
  ) { _stmt -> 
    _stmt.setLong(1,clazzUid)
    _stmt.setLong(2,studentPersonUid)
    _stmt.setLong(3,accountPersonUid)
    _stmt.setLong(4,accountPersonUid)
    _stmt.executeQueryAsyncKmp().useResults{ _result -> 
      _result.mapRows {
        val _tmp_cbSourcedId = _result.getString("cbSourcedId")
        var _tmp_StudentResult_nullCount = 0
        val _tmp_srUid = _result.getLong("srUid")
        if(_result.wasNull()) _tmp_StudentResult_nullCount++
        val _tmp_srSourcedId = _result.getString("srSourcedId")
        if(_result.wasNull()) _tmp_StudentResult_nullCount++
        val _tmp_srCourseBlockUid = _result.getLong("srCourseBlockUid")
        if(_result.wasNull()) _tmp_StudentResult_nullCount++
        val _tmp_srLineItemSourcedId = _result.getString("srLineItemSourcedId")
        if(_result.wasNull()) _tmp_StudentResult_nullCount++
        val _tmp_srLineItemHref = _result.getString("srLineItemHref")
        if(_result.wasNull()) _tmp_StudentResult_nullCount++
        val _tmp_srClazzUid = _result.getLong("srClazzUid")
        if(_result.wasNull()) _tmp_StudentResult_nullCount++
        val _tmp_srAssignmentUid = _result.getLong("srAssignmentUid")
        if(_result.wasNull()) _tmp_StudentResult_nullCount++
        val _tmp_srStatus = _result.getInt("srStatus")
        if(_result.wasNull()) _tmp_StudentResult_nullCount++
        val _tmp_srMetaData = _result.getString("srMetaData")
        if(_result.wasNull()) _tmp_StudentResult_nullCount++
        val _tmp_srStudentPersonUid = _result.getLong("srStudentPersonUid")
        if(_result.wasNull()) _tmp_StudentResult_nullCount++
        val _tmp_srStudentPersonSourcedId = _result.getString("srStudentPersonSourcedId")
        if(_result.wasNull()) _tmp_StudentResult_nullCount++
        val _tmp_srStudentGroupId = _result.getInt("srStudentGroupId")
        if(_result.wasNull()) _tmp_StudentResult_nullCount++
        val _tmp_srMarkerPersonUid = _result.getLong("srMarkerPersonUid")
        if(_result.wasNull()) _tmp_StudentResult_nullCount++
        val _tmp_srMarkerGroupId = _result.getInt("srMarkerGroupId")
        if(_result.wasNull()) _tmp_StudentResult_nullCount++
        val _tmp_srScoreStatus = _result.getInt("srScoreStatus")
        if(_result.wasNull()) _tmp_StudentResult_nullCount++
        val _tmp_srScore = _result.getFloat("srScore")
        if(_result.wasNull()) _tmp_StudentResult_nullCount++
        val _tmp_srScoreDate = _result.getLong("srScoreDate")
        if(_result.wasNull()) _tmp_StudentResult_nullCount++
        val _tmp_srLastModified = _result.getLong("srLastModified")
        if(_result.wasNull()) _tmp_StudentResult_nullCount++
        val _tmp_srComment = _result.getString("srComment")
        if(_result.wasNull()) _tmp_StudentResult_nullCount++
        val _tmp_srAppId = _result.getString("srAppId")
        if(_result.wasNull()) _tmp_StudentResult_nullCount++
        val _tmp_srDeleted = _result.getBoolean("srDeleted")
        if(_result.wasNull()) _tmp_StudentResult_nullCount++
        val _tmp_StudentResult_isAllNull = _tmp_StudentResult_nullCount == 21
        StudentResultAndCourseBlockSourcedId().apply {
          this.cbSourcedId = _tmp_cbSourcedId
          if(!_tmp_StudentResult_isAllNull) {
            this.studentResult = StudentResult().apply {
              this.srUid = _tmp_srUid
              this.srSourcedId = _tmp_srSourcedId
              this.srCourseBlockUid = _tmp_srCourseBlockUid
              this.srLineItemSourcedId = _tmp_srLineItemSourcedId
              this.srLineItemHref = _tmp_srLineItemHref
              this.srClazzUid = _tmp_srClazzUid
              this.srAssignmentUid = _tmp_srAssignmentUid
              this.srStatus = _tmp_srStatus
              this.srMetaData = _tmp_srMetaData
              this.srStudentPersonUid = _tmp_srStudentPersonUid
              this.srStudentPersonSourcedId = _tmp_srStudentPersonSourcedId
              this.srStudentGroupId = _tmp_srStudentGroupId
              this.srMarkerPersonUid = _tmp_srMarkerPersonUid
              this.srMarkerGroupId = _tmp_srMarkerGroupId
              this.srScoreStatus = _tmp_srScoreStatus
              this.srScore = _tmp_srScore
              this.srScoreDate = _tmp_srScoreDate
              this.srLastModified = _tmp_srLastModified
              this.srComment = _tmp_srComment
              this.srAppId = _tmp_srAppId
              this.srDeleted = _tmp_srDeleted
            }
          }
        }
      }
    }
  }

  override suspend fun findUidBySourcedId(sourcedId: String): Long =
      _db.prepareAndUseStatementAsync(PreparedStatementConfig(
    sql = """
    |
    |        SELECT COALESCE(
    |               (SELECT StudentResult.srUid  
    |                  FROM StudentResult 
    |                 WHERE srSourcedId = ?), 0)
    |    
    """.trimMargin(),
    readOnly = true,)
  ) { _stmt -> 
    _stmt.setString(1,sourcedId)
    _stmt.executeQueryAsyncKmp().useResults{ _result -> 
      _result.mapNextRow(0L) {
        _result.getLong(1)
      }
    }
  }

  override suspend fun existsByUid(srUid: Long): Boolean =
      _db.prepareAndUseStatementAsync(PreparedStatementConfig(
    sql = """
    |
    |        SELECT EXISTS(
    |               SELECT StudentResult.srUid
    |                 FROM StudentResult
    |                WHERE StudentResult.srUid = ?)
    |    
    """.trimMargin(),
    readOnly = true,)
  ) { _stmt -> 
    _stmt.setLong(1,srUid)
    _stmt.executeQueryAsyncKmp().useResults{ _result -> 
      _result.mapNextRow(false) {
        _result.getBoolean(1)
      }
    }
  }
}
