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.useResults
import com.ustadmobile.door.room.RoomDatabase
import com.ustadmobile.lib.db.entities.ExternalAppPermission
import kotlin.Boolean
import kotlin.IllegalArgumentException
import kotlin.Int
import kotlin.Long
import kotlin.String

public class ExternalAppPermissionDao_JdbcImpl(
  public val _db: RoomDatabase,
) : ExternalAppPermissionDao() {
  public val _insertAdapterExternalAppPermission_abort:
      EntityInsertionAdapter<ExternalAppPermission> = object :
      EntityInsertionAdapter<ExternalAppPermission>(_db) {
    override fun makeSql(returnsId: Boolean): String = when(dbType) {
      DoorDbType.SQLITE -> {
        "INSERT INTO ExternalAppPermission (eapUid, eapPersonUid, eapPackageId, eapStartTime, eapExpireTime, eapAuthToken, eapAndroidAccountName) VALUES(?, ?, ?, ?, ?, ?, ?)"
      }
      DoorDbType.POSTGRES ->  {
        "INSERT INTO ExternalAppPermission (eapUid, eapPersonUid, eapPackageId, eapStartTime, eapExpireTime, eapAuthToken, eapAndroidAccountName) VALUES(COALESCE(?,nextval('ExternalAppPermission_eapUid_seq')), ?, ?, ?, ?, ?, ?)" + if(returnsId) { " RETURNING eapUid" } else "" 
      }
      else -> {
        throw IllegalArgumentException("Unsupported db type")
      }
    }

    override fun bindPreparedStmtToEntity(stmt: PreparedStatement, entity: ExternalAppPermission) {
      if(entity.eapUid == 0) {
        stmt.setObject(1, null)
      } else {
        stmt.setInt(1, entity.eapUid)
      }
      stmt.setLong(2, entity.eapPersonUid)
      stmt.setString(3, entity.eapPackageId)
      stmt.setLong(4, entity.eapStartTime)
      stmt.setLong(5, entity.eapExpireTime)
      stmt.setString(6, entity.eapAuthToken)
      stmt.setString(7, entity.eapAndroidAccountName)
    }
  }

  override suspend fun insertAsync(externalAppPermission: ExternalAppPermission): Long {
    val _retVal =
        _insertAdapterExternalAppPermission_abort.insertAndReturnIdAsync(externalAppPermission)
    return _retVal
  }

  override suspend fun getGrantedAuthToken(
    packageId: String,
    personUid: Long,
    currentTime: Long,
  ): String? = _db.prepareAndUseStatementAsync(PreparedStatementConfig(
    sql = """
    |
    |        SELECT ExternalAppPermission.eapAuthToken
    |          FROM ExternalAppPermission
    |         WHERE ExternalAppPermission.eapPackageId = ?
    |           AND ExternalAppPermission.eapPersonUid = ?
    |           AND ? BETWEEN ExternalAppPermission.eapStartTime AND ExternalAppPermission.eapExpireTime
    |         LIMIT 1  
    |    
    """.trimMargin(),
    readOnly = true,)
  ) { _stmt -> 
    _stmt.setString(1,packageId)
    _stmt.setLong(2,personUid)
    _stmt.setLong(3,currentTime)
    _stmt.executeQueryAsyncKmp().useResults{ _result -> 
      _result.mapNextRow(null) {
        _result.getString(1)
      }
    }
  }

  override suspend fun getExternalAccessPermissionByUid(eapUid: Int): ExternalAppPermission? =
      _db.prepareAndUseStatementAsync(PreparedStatementConfig(
    sql = """
    |
    |        SELECT *
    |          FROM ExternalAppPermission
    |         WHERE eapUid = ? 
    |    
    """.trimMargin(),
    readOnly = true,)
  ) { _stmt -> 
    _stmt.setInt(1,eapUid)
    _stmt.executeQueryAsyncKmp().useResults{ _result -> 
      _result.mapNextRow(null) {
        val _tmp_eapUid = _result.getInt("eapUid")
        val _tmp_eapPersonUid = _result.getLong("eapPersonUid")
        val _tmp_eapPackageId = _result.getString("eapPackageId")
        val _tmp_eapStartTime = _result.getLong("eapStartTime")
        val _tmp_eapExpireTime = _result.getLong("eapExpireTime")
        val _tmp_eapAuthToken = _result.getString("eapAuthToken")
        val _tmp_eapAndroidAccountName = _result.getString("eapAndroidAccountName")
        ExternalAppPermission().apply {
          this.eapUid = _tmp_eapUid
          this.eapPersonUid = _tmp_eapPersonUid
          this.eapPackageId = _tmp_eapPackageId
          this.eapStartTime = _tmp_eapStartTime
          this.eapExpireTime = _tmp_eapExpireTime
          this.eapAuthToken = _tmp_eapAuthToken
          this.eapAndroidAccountName = _tmp_eapAndroidAccountName
        }
      }
    }
  }

  override suspend fun getPersonUidByAuthToken(token: String, currentTime: Long): Long =
      _db.prepareAndUseStatementAsync(PreparedStatementConfig(
    sql = """
    |
    |        SELECT COALESCE(
    |               (SELECT eapPersonUid
    |                  FROM ExternalAppPermission
    |                 WHERE eapAuthToken = ?
    |                   AND ? BETWEEN eapStartTime AND eapExpireTime
    |               ),
    |               0)    
    |    
    """.trimMargin(),
    readOnly = true,)
  ) { _stmt -> 
    _stmt.setString(1,token)
    _stmt.setLong(2,currentTime)
    _stmt.executeQueryAsyncKmp().useResults{ _result -> 
      _result.mapNextRow(0L) {
        _result.getLong(1)
      }
    }
  }
}
