package com.ustadmobile.core.db.dao.xapi

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.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.xapi.ActivityEntity
import kotlin.Boolean
import kotlin.IllegalArgumentException
import kotlin.Int
import kotlin.Long
import kotlin.String
import kotlin.collections.List

public class ActivityEntityDao_JdbcImpl(
  public val _db: RoomDatabase,
) : ActivityEntityDao() {
  public val _insertAdapterActivityEntity_ignore: EntityInsertionAdapter<ActivityEntity> = object :
      EntityInsertionAdapter<ActivityEntity>(_db) {
    override fun makeSql(returnsId: Boolean): String = when(dbType) {
      DoorDbType.SQLITE -> {
        "INSERT  OR IGNORE INTO ActivityEntity (actUid, actIdIri, actType, actMoreInfo, actInteractionType, actCorrectResponsePatterns, actLct) VALUES(?, ?, ?, ?, ?, ?, ?)"
      }
      DoorDbType.POSTGRES ->  {
        "INSERT INTO ActivityEntity (actUid, actIdIri, actType, actMoreInfo, actInteractionType, actCorrectResponsePatterns, actLct) VALUES(?, ?, ?, ?, ?, ?, ?) ON CONFLICT (actUid) DO NOTHING" + if(returnsId) { " RETURNING actUid" } else "" 
      }
      else -> {
        throw IllegalArgumentException("Unsupported db type")
      }
    }

    override fun bindPreparedStmtToEntity(stmt: PreparedStatement, entity: ActivityEntity) {
      stmt.setLong(1, entity.actUid)
      stmt.setString(2, entity.actIdIri)
      stmt.setString(3, entity.actType)
      stmt.setString(4, entity.actMoreInfo)
      stmt.setInt(5, entity.actInteractionType)
      stmt.setString(6, entity.actCorrectResponsePatterns)
      stmt.setLong(7, entity.actLct)
    }
  }

  override suspend fun insertOrIgnoreAsync(entities: List<ActivityEntity>) {
    _insertAdapterActivityEntity_ignore.insertListAsync(entities)
  }

  override suspend fun updateIfMoreInfoChanged(
    activityUid: Long,
    actMoreInfo: String?,
    actLct: Long,
  ) {
    _db.prepareAndUseStatementAsync(PreparedStatementConfig(
      sql = """
      |
      |        UPDATE ActivityEntity
      |           SET actMoreInfo = ?,
      |               actLct = ?
      |        WHERE actUid = ?
      |          AND actMoreInfo != ?      
      |    
      """.trimMargin(),
      readOnly = false,)
    ) { _stmt -> 
      _stmt.setString(1,actMoreInfo)
      _stmt.setLong(2,actLct)
      _stmt.setLong(3,activityUid)
      _stmt.setString(4,actMoreInfo)
      _stmt.executeUpdateAsyncKmp()
    }
  }

  override suspend fun updateIfNotYetDefined(
    actUid: Long,
    actType: String?,
    actMoreInfo: String?,
    actInteractionType: Int,
    actCorrectResponsePatterns: String?,
  ) {
    _db.prepareAndUseStatementAsync(PreparedStatementConfig(
      sql = """
      |
      |        UPDATE ActivityEntity
      |           SET actType = ?,
      |               actMoreInfo = ?,
      |               actInteractionType = ?,
      |               actCorrectResponsePatterns = ?
      |         WHERE actUid = ?
      |           AND (SELECT ActivityEntityInternal.actType 
      |                  FROM ActivityEntity ActivityEntityInternal 
      |                 WHERE ActivityEntityInternal.actUid = ?) IS NULL
      |           AND (SELECT ActivityEntityInternal.actInteractionType 
      |                  FROM ActivityEntity ActivityEntityInternal 
      |                 WHERE ActivityEntityInternal.actUid = ?) = 0
      |           AND (SELECT ActivityEntityInternal.actCorrectResponsePatterns 
      |                  FROM ActivityEntity ActivityEntityInternal 
      |                 WHERE ActivityEntityInternal.actUid = ?) IS NULL      
      |    
      """.trimMargin(),
      readOnly = false,)
    ) { _stmt -> 
      _stmt.setString(1,actType)
      _stmt.setString(2,actMoreInfo)
      _stmt.setInt(3,actInteractionType)
      _stmt.setString(4,actCorrectResponsePatterns)
      _stmt.setLong(5,actUid)
      _stmt.setLong(6,actUid)
      _stmt.setLong(7,actUid)
      _stmt.setLong(8,actUid)
      _stmt.executeUpdateAsyncKmp()
    }
  }

  override suspend fun findByUidAsync(activityUid: Long): ActivityEntity? =
      _db.prepareAndUseStatementAsync(PreparedStatementConfig(
    sql = """
    |
    |        SELECT ActivityEntity.*
    |          FROM ActivityEntity
    |         WHERE ActivityEntity.actUid = ? 
    |    
    """.trimMargin(),
    readOnly = true,)
  ) { _stmt -> 
    _stmt.setLong(1,activityUid)
    _stmt.executeQueryAsyncKmp().useResults{ _result -> 
      _result.mapNextRow(null) {
        val _tmp_actUid = _result.getLong("actUid")
        val _tmp_actIdIri = _result.getString("actIdIri")
        val _tmp_actType = _result.getString("actType")
        val _tmp_actMoreInfo = _result.getString("actMoreInfo")
        val _tmp_actInteractionType = _result.getInt("actInteractionType")
        val _tmp_actCorrectResponsePatterns = _result.getString("actCorrectResponsePatterns")
        val _tmp_actLct = _result.getLong("actLct")
        ActivityEntity().apply {
          this.actUid = _tmp_actUid
          this.actIdIri = _tmp_actIdIri
          this.actType = _tmp_actType
          this.actMoreInfo = _tmp_actMoreInfo
          this.actInteractionType = _tmp_actInteractionType
          this.actCorrectResponsePatterns = _tmp_actCorrectResponsePatterns
          this.actLct = _tmp_actLct
        }
      }
    }
  }
}
