package com.ustadmobile.core.db.dao

import androidx.room.Dao
import androidx.room.Insert
import androidx.room.Query
import androidx.room.Update
import com.ustadmobile.lib.db.entities.NetworkNode
import kotlin.Array
import kotlin.Int
import kotlin.Long
import kotlin.String
import kotlin.Unit
import kotlin.collections.List

@Dao
public actual abstract class NetworkNodeDao {
  @Query(`value` = "SELECT * FROM NetworkNode")
  public actual abstract fun all(): List<NetworkNode>

  @Query(`value` = "SELECT * From NetworkNode WHERE ipAddress = :ipAddress")
  public actual abstract fun findNodeByIpAddress(ipAddress: String): NetworkNode?

  @Query(`value` = "SELECT * From NetworkNode WHERE nodeId = :nodeId")
  public actual abstract fun findNodeById(nodeId: Long): NetworkNode?

  @Query(`value` =
      "Select * From NetworkNode Where ((ipAddress = :ipAddress AND ipAddress IS NOT NULL) OR (wifiDirectMacAddress = :wifiDirectMacAddress AND wifiDirectMacAddress IS NOT NULL))")
  public actual abstract fun findNodeByIpOrWifiDirectMacAddress(ipAddress: String,
      wifiDirectMacAddress: String): NetworkNode?

  @Query(`value` = "SELECT * from NetworkNode WHERE bluetoothMacAddress = :bluetoothAddress")
  public actual abstract fun findNodeByBluetoothAddress(bluetoothAddress: String): NetworkNode?

  @Insert(onConflict = 1)
  public actual abstract fun replace(node: NetworkNode): Long

  @Insert(onConflict = 1)
  public actual abstract suspend fun insertAsync(node: NetworkNode): Long

  @Insert(onConflict = 1)
  public actual abstract fun insertList(nodeList: List<NetworkNode>): Array<Long>

  @Update(onConflict = 3)
  public actual abstract fun update(node: NetworkNode): Unit

  @Query(`value` = "DELETE FROM NetworkNode WHERE bluetoothMacAddress = :bluetoothAddress")
  public actual abstract fun deleteByBluetoothAddress(bluetoothAddress: String): Unit

  @Query(`value` = "DELETE FROM NetworkNode")
  public actual abstract suspend fun deleteAllAsync(): Unit

  @Query(`value` =
      "UPDATE NetworkNode SET numFailureCount = numFailureCount + 1 WHERE nodeId = :nodeId")
  public actual abstract suspend fun updateRetryCountAsync(nodeId: Long): Unit

  @Query(`value` =
      "Select * From NetworkNode WHERE lastUpdateTimeStamp >= :lastUpdatedTime AND numFailureCount <= :maxNumFailure")
  public actual abstract fun findAllActiveNodes(lastUpdatedTime: Long, maxNumFailure: Int):
      List<NetworkNode>

  @Query(`value` =
      "UPDATE NetworkNode set lastUpdateTimeStamp = :lastUpdateTimeStamp, numFailureCount = 0 WHERE bluetoothMacAddress = :bluetoothAddress")
  public actual abstract suspend fun updateLastSeenAsync(bluetoothAddress: String,
      lastUpdateTimeStamp: Long): Int

  @Query(`value` =
      "DELETE FROM NetworkNode WHERE NetworkNode.lastUpdateTimeStamp < :minLastSeenTimestamp OR NetworkNode.numFailureCount >= :maxFailuresInPeriod")
  public actual abstract fun deleteOldAndBadNode(minLastSeenTimestamp: Long,
      maxFailuresInPeriod: Int): Unit

  @Query(`value` =
      "UPDATE NetworkNode SET groupSsid = :groupSsid, endpointUrl = :endpointUrl  WHERE nodeId = :nodeId")
  public actual abstract fun updateNetworkNodeGroupSsid(
    nodeId: Long,
    groupSsid: String,
    endpointUrl: String,
  ): Unit

  @Query(`value` = "SELECT endpointUrl FROM NetworkNode WHERE groupSsid = :ssid")
  public actual abstract fun getEndpointUrlByGroupSsid(ssid: String): String?
}
