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

import androidx.paging.PagingSource
import com.ustadmobile.door.DoorDatabaseRepository
import com.ustadmobile.door.DoorQuery
import com.ustadmobile.door.ext.doorNodeIdHeader
import com.ustadmobile.door.ext.pagingSourceLoadParameters
import com.ustadmobile.door.ext.setRepoUrl
import com.ustadmobile.door.http.RepoDaoFlowHelper
import com.ustadmobile.door.http.RepositoryDaoWithFlowHelper
import com.ustadmobile.door.http.replicateHttpRequestCatchAndLog
import com.ustadmobile.door.http.replicateHttpRequestOrThrow
import com.ustadmobile.door.paging.DoorRepositoryReplicatePullPagingSource
import com.ustadmobile.door.paging.endOfPaginationReached
import com.ustadmobile.door.replication.onClientRepoDoorMessageHttpResponse
import com.ustadmobile.door.replication.withRepoChangeMonitorAsync
import com.ustadmobile.door.room.RoomDatabase
import com.ustadmobile.lib.db.composites.BlockStatus
import com.ustadmobile.lib.db.composites.PersonAndPictureAndNumAttempts
import com.ustadmobile.lib.db.composites.xapi.SessionTimeAndProgressInfo
import com.ustadmobile.lib.db.composites.xapi.StatementAndActivity
import com.ustadmobile.lib.db.composites.xapi.StatementEntityAndRelated
import com.ustadmobile.lib.db.composites.xapi.StatementEntityAndVerb
import com.ustadmobile.lib.db.composites.xapi.VerbEntityAndName
import com.ustadmobile.lib.db.entities.Person
import com.ustadmobile.lib.db.entities.StatementEntityAndDisplayDetails
import com.ustadmobile.lib.db.entities.StatementReportData
import com.ustadmobile.lib.db.entities.xapi.ActivityLangMapEntry
import com.ustadmobile.lib.db.entities.xapi.ActorEntity
import com.ustadmobile.lib.db.entities.xapi.StatementEntity
import io.ktor.client.HttpClient
import io.ktor.client.request.`get`
import io.ktor.client.request.`header`
import io.ktor.client.request.parameter
import kotlin.Boolean
import kotlin.Int
import kotlin.Long
import kotlin.String
import kotlin.Suppress
import kotlin.collections.List
import kotlinx.coroutines.flow.Flow
import kotlinx.serialization.builtins.ListSerializer
import kotlinx.serialization.builtins.nullable
import kotlinx.serialization.builtins.serializer

@Suppress("REDUNDANT_PROJECTION", "LocalVariableName", "ClassName")
public class StatementDao_Repo(
  public val _db: RoomDatabase,
  public val _repo: DoorDatabaseRepository,
  public val _dao: StatementDao,
  public val _httpClient: HttpClient,
  public val _clientId: Long,
  public val _endpoint: String,
) : StatementDao(), RepositoryDaoWithFlowHelper {
  override val repoDaoFlowHelper: RepoDaoFlowHelper = RepoDaoFlowHelper(_repo)


  override suspend fun insertOrIgnoreListAsync(entityList: List<StatementEntity>) {
    _repo.withRepoChangeMonitorAsync("StatementEntity") {
      _dao.insertOrIgnoreListAsync(entityList)
    }
  }

  override fun getOneStatement(): Flow<StatementEntity?> {
    val _result = _dao.getOneStatement()
    return _result
  }

  override suspend fun getResults(query: DoorQuery): List<StatementReportData> {
    val _result = _dao.getResults(query)
    return _result
  }

  override fun getListResults(query: DoorQuery):
      PagingSource<Int, StatementEntityAndDisplayDetails> {
    val _result = _dao.getListResults(query)
    return _result
  }

  override fun getPerson(): Person? {
    val _result = _dao.getPerson()
    return _result
  }

  override suspend fun getStatements(statementIdHi: Long, statementIdLo: Long):
      List<StatementEntity> {
    val _result = _dao.getStatements(statementIdHi, statementIdLo)
    return _result
  }

  override suspend fun findById(statementIdHi: Long, statementIdLo: Long): StatementEntity? {
    val _result = _dao.findById(statementIdHi, statementIdLo)
    return _result
  }

  override suspend fun findStatusStatementsByContentEntryUid(
    contentEntryUid: Long,
    courseBlockUid: Long,
    accountPersonUid: Long,
  ): List<StatementEntity> {
    val _result = _dao.findStatusStatementsByContentEntryUid(contentEntryUid, courseBlockUid,
        accountPersonUid)
    return _result
  }

  override suspend fun findStatusStatementByParentContentEntryUid(parentUid: Long,
      accountPersonUid: Long): List<StatementEntity> {
    val _result = _dao.findStatusStatementByParentContentEntryUid(parentUid, accountPersonUid)
    return _result
  }

  override suspend fun findStatusStatementsForStudentByClazzUid(clazzUid: Long,
      accountPersonUid: Long): List<StatementEntity> {
    val _result = _dao.findStatusStatementsForStudentByClazzUid(clazzUid, accountPersonUid)
    return _result
  }

  override suspend fun findStatusForStudentsInClazzStatements(
    clazzUid: Long,
    roleId: Int,
    sortOrder: Int,
    searchText: String?,
    filter: Int,
    accountPersonUid: Long,
    currentTime: Long,
    studentsLimit: Int,
    studentsOffset: Int,
    completionOrProgressTrueVal: Boolean,
  ): List<StatementEntityAndRelated> {
    val _result = _dao.findStatusForStudentsInClazzStatements(clazzUid, roleId, sortOrder,
        searchText, filter, accountPersonUid, currentTime, studentsLimit, studentsOffset,
        completionOrProgressTrueVal)
    return _result
  }

  override suspend fun findStatusForStudentsInClazzByUidList(
    clazzUid: Long,
    studentPersonUids: List<Long>,
    completionOrProgressTrueVal: Boolean,
  ): List<StatementEntityAndRelated> {
    val _result = _dao.findStatusForStudentsInClazzByUidList(clazzUid, studentPersonUids,
        completionOrProgressTrueVal)
    return _result
  }

  override suspend fun findActorEntitiesForStudentInClazzByUidList(
    clazzUid: Long,
    studentPersonUids: List<Long>,
    accountPersonUid: Long,
  ): List<ActorEntity> {
    val _result = _dao.findActorEntitiesForStudentInClazzByUidList(clazzUid, studentPersonUids,
        accountPersonUid)
    return _result
  }

  override suspend fun findStatusForStudentsInClazz(
    clazzUid: Long,
    studentPersonUids: List<Long>,
    accountPersonUid: Long,
  ): List<BlockStatus> {
    val _result = _dao.findStatusForStudentsInClazz(clazzUid, studentPersonUids, accountPersonUid)
    return _result
  }

  override fun findStatusForStudentsInClazzAsFlow(
    clazzUid: Long,
    studentPersonUids: List<Long>,
    accountPersonUid: Long,
  ): Flow<List<BlockStatus>> = repoDaoFlowHelper.asRepoFlow(
    dbFlow = _dao.findStatusForStudentsInClazzAsFlow(clazzUid, studentPersonUids, accountPersonUid),
    onMakeHttpRequest =  {
      _repo.replicateHttpRequestCatchAndLog(repoPath =
          "StatementDao/findStatusForStudentsInClazzAsFlow") {
        val _response = _httpClient.`get` {
          setRepoUrl(_repo.config, "StatementDao/findStatusForStudentsInClazzAsFlow")
          doorNodeIdHeader(_repo)
          `header`("cache-control", "no-store")
          parameter("clazzUid", _repo.config.json.encodeToString(Long.serializer(), clazzUid))
          parameter("studentPersonUids",
              _repo.config.json.encodeToString(ListSerializer(Long.serializer()),
              studentPersonUids))
          parameter("accountPersonUid", _repo.config.json.encodeToString(Long.serializer(),
              accountPersonUid))
        }

        _db.onClientRepoDoorMessageHttpResponse(_response, _repo.config.json)
      }
    },
  )

  override suspend fun findResumableRegistration(
    activityUid: Long,
    accountPersonUid: Long,
    actorUid: Long,
  ): StatementEntity? {
    val _result = _dao.findResumableRegistration(activityUid, accountPersonUid, actorUid)
    return _result
  }

  override suspend fun findPersonsWithAttemptsStatements(
    contentEntryUid: Long,
    accountPersonUid: Long,
    searchText: String?,
  ): List<StatementEntity> {
    val _result = _dao.findPersonsWithAttemptsStatements(contentEntryUid, accountPersonUid,
        searchText)
    return _result
  }

  override fun findPersonsWithAttempts(
    contentEntryUid: Long,
    accountPersonUid: Long,
    searchText: String?,
    sortOrder: Int,
  ): PagingSource<Int, PersonAndPictureAndNumAttempts> = DoorRepositoryReplicatePullPagingSource(
    repo = _repo,
    repoPath = "StatementDao/findPersonsWithAttempts",
    dbPagingSource = _dao.findPersonsWithAttempts(contentEntryUid, accountPersonUid, searchText,
        sortOrder),
    onLoadHttp =  {
      _pagingParams -> 
      _repo.replicateHttpRequestOrThrow(repoPath = "StatementDao/findPersonsWithAttempts") {
        val _response = _httpClient.`get` {
          setRepoUrl(_repo.config, "StatementDao/findPersonsWithAttempts")
          doorNodeIdHeader(_repo)
          `header`("cache-control", "no-store")
          parameter("contentEntryUid", _repo.config.json.encodeToString(Long.serializer(),
              contentEntryUid))
          parameter("accountPersonUid", _repo.config.json.encodeToString(Long.serializer(),
              accountPersonUid))
          parameter("searchText", _repo.config.json.encodeToString(String.serializer().nullable,
              searchText))
          parameter("sortOrder", _repo.config.json.encodeToString(Int.serializer(), sortOrder))
          pagingSourceLoadParameters(
            json = _repo.config.json, 
            keySerializer = Int.serializer().nullable,
            loadParams = _pagingParams
          )
        }

        _db.onClientRepoDoorMessageHttpResponse(_response, _repo.config.json)
        _response.endOfPaginationReached()
      }
    },
  )

  override suspend fun findSessionsByPersonAndContentStatements(
    contentEntryUid: Long,
    personUid: Long,
    accountPersonUid: Long,
  ): List<StatementEntity> {
    val _result = _dao.findSessionsByPersonAndContentStatements(contentEntryUid, personUid,
        accountPersonUid)
    return _result
  }

  override fun findSessionsByPersonAndContent(
    contentEntryUid: Long,
    personUid: Long,
    accountPersonUid: Long,
    sortOrder: Int,
  ): PagingSource<Int, SessionTimeAndProgressInfo> = DoorRepositoryReplicatePullPagingSource(
    repo = _repo,
    repoPath = "StatementDao/findSessionsByPersonAndContent",
    dbPagingSource = _dao.findSessionsByPersonAndContent(contentEntryUid, personUid,
        accountPersonUid, sortOrder),
    onLoadHttp =  {
      _pagingParams -> 
      _repo.replicateHttpRequestOrThrow(repoPath = "StatementDao/findSessionsByPersonAndContent") {
        val _response = _httpClient.`get` {
          setRepoUrl(_repo.config, "StatementDao/findSessionsByPersonAndContent")
          doorNodeIdHeader(_repo)
          `header`("cache-control", "no-store")
          parameter("contentEntryUid", _repo.config.json.encodeToString(Long.serializer(),
              contentEntryUid))
          parameter("personUid", _repo.config.json.encodeToString(Long.serializer(), personUid))
          parameter("accountPersonUid", _repo.config.json.encodeToString(Long.serializer(),
              accountPersonUid))
          parameter("sortOrder", _repo.config.json.encodeToString(Int.serializer(), sortOrder))
          pagingSourceLoadParameters(
            json = _repo.config.json, 
            keySerializer = Int.serializer().nullable,
            loadParams = _pagingParams
          )
        }

        _db.onClientRepoDoorMessageHttpResponse(_response, _repo.config.json)
        _response.endOfPaginationReached()
      }
    },
  )

  override suspend fun findActivityEntryLangMapsForStatementsBySession(registrationHi: Long,
      registrationLo: Long): List<ActivityLangMapEntry> {
    val _result = _dao.findActivityEntryLangMapsForStatementsBySession(registrationHi,
        registrationLo)
    return _result
  }

  override fun findStatementsBySession(
    registrationHi: Long,
    registrationLo: Long,
    accountPersonUid: Long,
    selectedPersonUid: Long,
    contentEntryUid: Long,
    searchText: String,
    sortOrder: Int,
    deSelectedVerbUids: List<Long>,
  ): PagingSource<Int, StatementEntityAndVerb> = DoorRepositoryReplicatePullPagingSource(
    repo = _repo,
    repoPath = "StatementDao/findStatementsBySession",
    dbPagingSource = _dao.findStatementsBySession(registrationHi, registrationLo, accountPersonUid,
        selectedPersonUid, contentEntryUid, searchText, sortOrder, deSelectedVerbUids),
    onLoadHttp =  {
      _pagingParams -> 
      _repo.replicateHttpRequestOrThrow(repoPath = "StatementDao/findStatementsBySession") {
        val _response = _httpClient.`get` {
          setRepoUrl(_repo.config, "StatementDao/findStatementsBySession")
          doorNodeIdHeader(_repo)
          `header`("cache-control", "no-store")
          parameter("registrationHi", _repo.config.json.encodeToString(Long.serializer(),
              registrationHi))
          parameter("registrationLo", _repo.config.json.encodeToString(Long.serializer(),
              registrationLo))
          parameter("accountPersonUid", _repo.config.json.encodeToString(Long.serializer(),
              accountPersonUid))
          parameter("selectedPersonUid", _repo.config.json.encodeToString(Long.serializer(),
              selectedPersonUid))
          parameter("contentEntryUid", _repo.config.json.encodeToString(Long.serializer(),
              contentEntryUid))
          parameter("searchText", _repo.config.json.encodeToString(String.serializer(), searchText))
          parameter("sortOrder", _repo.config.json.encodeToString(Int.serializer(), sortOrder))
          parameter("deSelectedVerbUids",
              _repo.config.json.encodeToString(ListSerializer(Long.serializer()),
              deSelectedVerbUids))
          pagingSourceLoadParameters(
            json = _repo.config.json, 
            keySerializer = Int.serializer().nullable,
            loadParams = _pagingParams
          )
        }

        _db.onClientRepoDoorMessageHttpResponse(_response, _repo.config.json)
        _response.endOfPaginationReached()
      }
    },
  )

  override fun getUniqueVerbsForSession(
    registrationHi: Long,
    registrationLo: Long,
    selectedPersonUid: Long,
    contentEntryUid: Long,
  ): Flow<List<VerbEntityAndName>> = repoDaoFlowHelper.asRepoFlow(
    dbFlow = _dao.getUniqueVerbsForSession(registrationHi, registrationLo, selectedPersonUid,
        contentEntryUid),
    onMakeHttpRequest =  {
      _repo.replicateHttpRequestCatchAndLog(repoPath = "StatementDao/getUniqueVerbsForSession") {
        val _response = _httpClient.`get` {
          setRepoUrl(_repo.config, "StatementDao/getUniqueVerbsForSession")
          doorNodeIdHeader(_repo)
          `header`("cache-control", "no-store")
          parameter("registrationHi", _repo.config.json.encodeToString(Long.serializer(),
              registrationHi))
          parameter("registrationLo", _repo.config.json.encodeToString(Long.serializer(),
              registrationLo))
          parameter("selectedPersonUid", _repo.config.json.encodeToString(Long.serializer(),
              selectedPersonUid))
          parameter("contentEntryUid", _repo.config.json.encodeToString(Long.serializer(),
              contentEntryUid))
        }

        _db.onClientRepoDoorMessageHttpResponse(_response, _repo.config.json)
      }
    },
  )

  override suspend fun scoreOrProgressDataExistsForContent(contentEntryUid: Long,
      accountPersonUid: Long): List<StatementEntity> {
    _repo.replicateHttpRequestCatchAndLog(repoPath =
        "StatementDao/scoreOrProgressDataExistsForContent") {
      val _response = _httpClient.`get` {
        setRepoUrl(_repo.config, "StatementDao/scoreOrProgressDataExistsForContent")
        doorNodeIdHeader(_repo)
        `header`("cache-control", "no-store")
        parameter("contentEntryUid", _repo.config.json.encodeToString(Long.serializer(),
            contentEntryUid))
        parameter("accountPersonUid", _repo.config.json.encodeToString(Long.serializer(),
            accountPersonUid))
      }

      _db.onClientRepoDoorMessageHttpResponse(_response, _repo.config.json)
    }
    val _result = _dao.scoreOrProgressDataExistsForContent(contentEntryUid, accountPersonUid)
    return _result
  }

  override suspend fun findByUidWithActivityAsync(statementIdHi: Long, statementIdLo: Long):
      StatementAndActivity? {
    val _result = _dao.findByUidWithActivityAsync(statementIdHi, statementIdLo)
    return _result
  }
}
