package com.ustadmobile.core.db.dao

import androidx.paging.PagingSource
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.mapNextRow
import com.ustadmobile.door.jdbc.ext.mapRows
import com.ustadmobile.door.jdbc.ext.useResults
import com.ustadmobile.door.paging.DoorLimitOffsetPagingSource
import com.ustadmobile.door.room.RoomDatabase
import com.ustadmobile.lib.db.entities.ContentEntryRelatedEntryJoin
import com.ustadmobile.lib.db.entities.ContentEntryRelatedEntryJoinWithLangName
import com.ustadmobile.lib.db.entities.ContentEntryRelatedEntryJoinWithLanguage
import com.ustadmobile.lib.db.entities.Language
import kotlin.Boolean
import kotlin.IllegalArgumentException
import kotlin.Int
import kotlin.Long
import kotlin.String
import kotlin.collections.List

public class ContentEntryRelatedEntryJoinDao_JdbcImpl(
  public val _db: RoomDatabase,
) : ContentEntryRelatedEntryJoinDao() {
  public val _insertAdapterContentEntryRelatedEntryJoin_abort:
      EntityInsertionAdapter<ContentEntryRelatedEntryJoin> = object :
      EntityInsertionAdapter<ContentEntryRelatedEntryJoin>(_db) {
    override fun makeSql(returnsId: Boolean): String = when(dbType) {
      DoorDbType.SQLITE -> {
        "INSERT INTO ContentEntryRelatedEntryJoin (cerejUid, cerejContentEntryUid, cerejRelatedEntryUid, cerejLastChangedBy, relType, comment, cerejRelLanguageUid, cerejLocalChangeSeqNum, cerejMasterChangeSeqNum, cerejLct) VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"
      }
      DoorDbType.POSTGRES ->  {
        "INSERT INTO ContentEntryRelatedEntryJoin (cerejUid, cerejContentEntryUid, cerejRelatedEntryUid, cerejLastChangedBy, relType, comment, cerejRelLanguageUid, cerejLocalChangeSeqNum, cerejMasterChangeSeqNum, cerejLct) VALUES(COALESCE(?,nextval('ContentEntryRelatedEntryJoin_cerejUid_seq')), ?, ?, ?, ?, ?, ?, ?, ?, ?)" + if(returnsId) { " RETURNING cerejUid" } else "" 
      }
      else -> {
        throw IllegalArgumentException("Unsupported db type")
      }
    }

    override fun bindPreparedStmtToEntity(stmt: PreparedStatement,
        entity: ContentEntryRelatedEntryJoin) {
      if(entity.cerejUid == 0L) {
        stmt.setObject(1, null)
      } else {
        stmt.setLong(1, entity.cerejUid)
      }
      stmt.setLong(2, entity.cerejContentEntryUid)
      stmt.setLong(3, entity.cerejRelatedEntryUid)
      stmt.setInt(4, entity.cerejLastChangedBy)
      stmt.setInt(5, entity.relType)
      stmt.setString(6, entity.comment)
      stmt.setLong(7, entity.cerejRelLanguageUid)
      stmt.setLong(8, entity.cerejLocalChangeSeqNum)
      stmt.setLong(9, entity.cerejMasterChangeSeqNum)
      stmt.setLong(10, entity.cerejLct)
    }
  }

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

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

  public override fun insertList(entityList: List<ContentEntryRelatedEntryJoin>) {
    _insertAdapterContentEntryRelatedEntryJoin_abort.insertList(entityList)
  }

  override fun update(entity: ContentEntryRelatedEntryJoin) {
    val _sql =
        "UPDATE ContentEntryRelatedEntryJoin SET cerejContentEntryUid = ?, cerejRelatedEntryUid = ?, cerejLastChangedBy = ?, relType = ?, comment = ?, cerejRelLanguageUid = ?, cerejLocalChangeSeqNum = ?, cerejMasterChangeSeqNum = ?, cerejLct = ? WHERE cerejUid = ?"
    _db.prepareAndUseStatement(_sql) {
       _stmt ->
      _stmt.setLong(1, entity.cerejContentEntryUid)
      _stmt.setLong(2, entity.cerejRelatedEntryUid)
      _stmt.setInt(3, entity.cerejLastChangedBy)
      _stmt.setInt(4, entity.relType)
      _stmt.setString(5, entity.comment)
      _stmt.setLong(6, entity.cerejRelLanguageUid)
      _stmt.setLong(7, entity.cerejLocalChangeSeqNum)
      _stmt.setLong(8, entity.cerejMasterChangeSeqNum)
      _stmt.setLong(9, entity.cerejLct)
      _stmt.setLong(10, entity.cerejUid)
      _stmt.executeUpdate()
    }
  }

  override fun publicContentEntryRelatedEntryJoins(): List<ContentEntryRelatedEntryJoin> =
      _db.prepareAndUseStatement(PreparedStatementConfig(
    sql =
        "SELECT ContentEntryRelatedEntryJoin.* FROM ContentEntryRelatedEntryJoin LEFT JOIN ContentEntry ON ContentEntryRelatedEntryJoin.cerejRelatedEntryUid = ContentEntry.contentEntryUid WHERE ContentEntry.publik",
    readOnly = true,)
  ) { _stmt -> 
    _stmt.executeQuery().useResults{ _result -> 
      _result.mapRows {
        val _tmp_cerejUid = _result.getLong("cerejUid")
        val _tmp_cerejContentEntryUid = _result.getLong("cerejContentEntryUid")
        val _tmp_cerejRelatedEntryUid = _result.getLong("cerejRelatedEntryUid")
        val _tmp_cerejLastChangedBy = _result.getInt("cerejLastChangedBy")
        val _tmp_relType = _result.getInt("relType")
        val _tmp_comment = _result.getString("comment")
        val _tmp_cerejRelLanguageUid = _result.getLong("cerejRelLanguageUid")
        val _tmp_cerejLocalChangeSeqNum = _result.getLong("cerejLocalChangeSeqNum")
        val _tmp_cerejMasterChangeSeqNum = _result.getLong("cerejMasterChangeSeqNum")
        val _tmp_cerejLct = _result.getLong("cerejLct")
        ContentEntryRelatedEntryJoin().apply {
          this.cerejUid = _tmp_cerejUid
          this.cerejContentEntryUid = _tmp_cerejContentEntryUid
          this.cerejRelatedEntryUid = _tmp_cerejRelatedEntryUid
          this.cerejLastChangedBy = _tmp_cerejLastChangedBy
          this.relType = _tmp_relType
          this.comment = _tmp_comment
          this.cerejRelLanguageUid = _tmp_cerejRelLanguageUid
          this.cerejLocalChangeSeqNum = _tmp_cerejLocalChangeSeqNum
          this.cerejMasterChangeSeqNum = _tmp_cerejMasterChangeSeqNum
          this.cerejLct = _tmp_cerejLct
        }
      }
    }
  }

  override fun findPrimaryByTranslation(contentEntryUid: Long): ContentEntryRelatedEntryJoin? =
      _db.prepareAndUseStatement(PreparedStatementConfig(
    sql = "SELECT * FROM ContentEntryRelatedEntryJoin WHERE cerejRelatedEntryUid = ? LIMIT 1",
    readOnly = true,)
  ) { _stmt -> 
    _stmt.setLong(1,contentEntryUid)
    _stmt.executeQuery().useResults{ _result -> 
      _result.mapNextRow(null) {
        val _tmp_cerejUid = _result.getLong("cerejUid")
        val _tmp_cerejContentEntryUid = _result.getLong("cerejContentEntryUid")
        val _tmp_cerejRelatedEntryUid = _result.getLong("cerejRelatedEntryUid")
        val _tmp_cerejLastChangedBy = _result.getInt("cerejLastChangedBy")
        val _tmp_relType = _result.getInt("relType")
        val _tmp_comment = _result.getString("comment")
        val _tmp_cerejRelLanguageUid = _result.getLong("cerejRelLanguageUid")
        val _tmp_cerejLocalChangeSeqNum = _result.getLong("cerejLocalChangeSeqNum")
        val _tmp_cerejMasterChangeSeqNum = _result.getLong("cerejMasterChangeSeqNum")
        val _tmp_cerejLct = _result.getLong("cerejLct")
        ContentEntryRelatedEntryJoin().apply {
          this.cerejUid = _tmp_cerejUid
          this.cerejContentEntryUid = _tmp_cerejContentEntryUid
          this.cerejRelatedEntryUid = _tmp_cerejRelatedEntryUid
          this.cerejLastChangedBy = _tmp_cerejLastChangedBy
          this.relType = _tmp_relType
          this.comment = _tmp_comment
          this.cerejRelLanguageUid = _tmp_cerejRelLanguageUid
          this.cerejLocalChangeSeqNum = _tmp_cerejLocalChangeSeqNum
          this.cerejMasterChangeSeqNum = _tmp_cerejMasterChangeSeqNum
          this.cerejLct = _tmp_cerejLct
        }
      }
    }
  }

  override suspend fun findAllTranslationsForContentEntryAsync(contentEntryUid: Long):
      List<ContentEntryRelatedEntryJoinWithLangName> =
      _db.prepareAndUseStatementAsync(PreparedStatementConfig(
    sql =
        "SELECT ContentEntryRelatedEntryJoin.cerejContentEntryUid, ContentEntryRelatedEntryJoin.cerejRelatedEntryUid, CASE ContentEntryRelatedEntryJoin.cerejRelatedEntryUid WHEN ? THEN (SELECT name FROM Language WHERE langUid = (SELECT primaryLanguageUid FROM ContentEntry WHERE contentEntryUid = ContentEntryRelatedEntryJoin.cerejContentEntryUid)) ELSE Language.name END languageName FROM ContentEntryRelatedEntryJoin LEFT JOIN Language ON ContentEntryRelatedEntryJoin.cerejRelLanguageUid = Language.langUid WHERE (ContentEntryRelatedEntryJoin.cerejContentEntryUid = ? OR ContentEntryRelatedEntryJoin.cerejContentEntryUid IN (SELECT cerejContentEntryUid FROM ContentEntryRelatedEntryJoin WHERE cerejRelatedEntryUid = ?)) AND ContentEntryRelatedEntryJoin.relType = 1",
    readOnly = true,)
  ) { _stmt -> 
    _stmt.setLong(1,contentEntryUid)
    _stmt.setLong(2,contentEntryUid)
    _stmt.setLong(3,contentEntryUid)
    _stmt.executeQueryAsyncKmp().useResults{ _result -> 
      _result.mapRows {
        val _tmp_cerejContentEntryUid = _result.getLong("cerejContentEntryUid")
        val _tmp_cerejRelatedEntryUid = _result.getLong("cerejRelatedEntryUid")
        val _tmp_languageName = _result.getString("languageName")
        ContentEntryRelatedEntryJoinWithLangName().apply {
          this.cerejContentEntryUid = _tmp_cerejContentEntryUid
          this.cerejRelatedEntryUid = _tmp_cerejRelatedEntryUid
          this.languageName = _tmp_languageName
        }
      }
    }
  }

  override fun findAllTranslationsWithContentEntryUid(contentEntryUid: Long):
      PagingSource<Int, ContentEntryRelatedEntryJoinWithLanguage> = object :
      DoorLimitOffsetPagingSource<ContentEntryRelatedEntryJoinWithLanguage>(db = _db
  , tableNames = arrayOf("Language", "ContentEntryRelatedEntryJoin")
  ) {
    override suspend fun loadRows(_limit: Int, _offset: Int):
        List<ContentEntryRelatedEntryJoinWithLanguage> =
        _db.prepareAndUseStatementAsync(PreparedStatementConfig(
      sql = """
      |SELECT * FROM (SELECT ContentEntryRelatedEntryJoin.*, Language.* FROM ContentEntryRelatedEntryJoin
      |        LEFT JOIN Language ON ContentEntryRelatedEntryJoin.cerejRelLanguageUid = Language.langUid
      |        WHERE (ContentEntryRelatedEntryJoin.cerejContentEntryUid = ?
      |        OR ContentEntryRelatedEntryJoin.cerejContentEntryUid IN
      |        (SELECT cerejContentEntryUid FROM ContentEntryRelatedEntryJoin WHERE cerejRelatedEntryUid = ?))
      |        AND ContentEntryRelatedEntryJoin.relType = 1
      |        ORDER BY Language.name) AS _PagingData LIMIT ? OFFSET ?
      """.trimMargin(),
      readOnly = true,)
    ) { _stmt -> 
      _stmt.setLong(1,contentEntryUid)
      _stmt.setLong(2,contentEntryUid)
      _stmt.setInt(3,_limit)
      _stmt.setInt(4,_offset)
      _stmt.executeQueryAsyncKmp().useResults{ _result -> 
        _result.mapRows {
          val _tmp_cerejUid = _result.getLong("cerejUid")
          val _tmp_cerejContentEntryUid = _result.getLong("cerejContentEntryUid")
          val _tmp_cerejRelatedEntryUid = _result.getLong("cerejRelatedEntryUid")
          val _tmp_cerejLastChangedBy = _result.getInt("cerejLastChangedBy")
          val _tmp_relType = _result.getInt("relType")
          val _tmp_comment = _result.getString("comment")
          val _tmp_cerejRelLanguageUid = _result.getLong("cerejRelLanguageUid")
          val _tmp_cerejLocalChangeSeqNum = _result.getLong("cerejLocalChangeSeqNum")
          val _tmp_cerejMasterChangeSeqNum = _result.getLong("cerejMasterChangeSeqNum")
          val _tmp_cerejLct = _result.getLong("cerejLct")
          var _tmp_Language_nullCount = 0
          val _tmp_langUid = _result.getLong("langUid")
          if(_result.wasNull()) _tmp_Language_nullCount++
          val _tmp_name = _result.getString("name")
          if(_result.wasNull()) _tmp_Language_nullCount++
          val _tmp_iso_639_1_standard = _result.getString("iso_639_1_standard")
          if(_result.wasNull()) _tmp_Language_nullCount++
          val _tmp_iso_639_2_standard = _result.getString("iso_639_2_standard")
          if(_result.wasNull()) _tmp_Language_nullCount++
          val _tmp_iso_639_3_standard = _result.getString("iso_639_3_standard")
          if(_result.wasNull()) _tmp_Language_nullCount++
          val _tmp_Language_Type = _result.getString("Language_Type")
          if(_result.wasNull()) _tmp_Language_nullCount++
          val _tmp_languageActive = _result.getBoolean("languageActive")
          if(_result.wasNull()) _tmp_Language_nullCount++
          val _tmp_langLocalChangeSeqNum = _result.getLong("langLocalChangeSeqNum")
          if(_result.wasNull()) _tmp_Language_nullCount++
          val _tmp_langMasterChangeSeqNum = _result.getLong("langMasterChangeSeqNum")
          if(_result.wasNull()) _tmp_Language_nullCount++
          val _tmp_langLastChangedBy = _result.getInt("langLastChangedBy")
          if(_result.wasNull()) _tmp_Language_nullCount++
          val _tmp_langLct = _result.getLong("langLct")
          if(_result.wasNull()) _tmp_Language_nullCount++
          val _tmp_Language_isAllNull = _tmp_Language_nullCount == 11
          ContentEntryRelatedEntryJoinWithLanguage().apply {
            this.cerejUid = _tmp_cerejUid
            this.cerejContentEntryUid = _tmp_cerejContentEntryUid
            this.cerejRelatedEntryUid = _tmp_cerejRelatedEntryUid
            this.cerejLastChangedBy = _tmp_cerejLastChangedBy
            this.relType = _tmp_relType
            this.comment = _tmp_comment
            this.cerejRelLanguageUid = _tmp_cerejRelLanguageUid
            this.cerejLocalChangeSeqNum = _tmp_cerejLocalChangeSeqNum
            this.cerejMasterChangeSeqNum = _tmp_cerejMasterChangeSeqNum
            this.cerejLct = _tmp_cerejLct
            if(!_tmp_Language_isAllNull) {
              this.language = Language().apply {
                this.langUid = _tmp_langUid
                this.name = _tmp_name
                this.iso_639_1_standard = _tmp_iso_639_1_standard
                this.iso_639_2_standard = _tmp_iso_639_2_standard
                this.iso_639_3_standard = _tmp_iso_639_3_standard
                this.Language_Type = _tmp_Language_Type
                this.languageActive = _tmp_languageActive
                this.langLocalChangeSeqNum = _tmp_langLocalChangeSeqNum
                this.langMasterChangeSeqNum = _tmp_langMasterChangeSeqNum
                this.langLastChangedBy = _tmp_langLastChangedBy
                this.langLct = _tmp_langLct
              }
            }
          }
        }
      }
    }

    override suspend fun countRows(): Int = _db.prepareAndUseStatementAsync(PreparedStatementConfig(
      sql = """
      |SELECT COUNT(*) FROM (SELECT ContentEntryRelatedEntryJoin.*, Language.* FROM ContentEntryRelatedEntryJoin
      |        LEFT JOIN Language ON ContentEntryRelatedEntryJoin.cerejRelLanguageUid = Language.langUid
      |        WHERE (ContentEntryRelatedEntryJoin.cerejContentEntryUid = ?
      |        OR ContentEntryRelatedEntryJoin.cerejContentEntryUid IN
      |        (SELECT cerejContentEntryUid FROM ContentEntryRelatedEntryJoin WHERE cerejRelatedEntryUid = ?))
      |        AND ContentEntryRelatedEntryJoin.relType = 1
      |        ORDER BY Language.name) AS _PagingCount
      """.trimMargin(),
      readOnly = true,)
    ) { _stmt -> 
      _stmt.setLong(1,contentEntryUid)
      _stmt.setLong(2,contentEntryUid)
      _stmt.executeQueryAsyncKmp().useResults{ _result -> 
        _result.mapNextRow(0) {
          _result.getInt(1)
        }
      }
    }
  }
}
