package world.respect.datalayer.http.school.opds

import io.ktor.client.HttpClient
import io.ktor.client.request.post
import io.ktor.client.request.setBody
import io.ktor.http.ContentType
import io.ktor.http.Url
import io.ktor.http.contentType
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.map
import world.respect.datalayer.AuthTokenProvider
import world.respect.datalayer.DataLoadParams
import world.respect.datalayer.DataLoadState
import world.respect.datalayer.ext.getAsDataLoadState
import world.respect.datalayer.ext.getDataLoadResultAsFlow
import world.respect.datalayer.ext.map
import world.respect.datalayer.ext.useTokenProvider
import world.respect.datalayer.networkvalidation.BaseDataSourceValidationHelper
import world.respect.datalayer.school.opds.OpdsFeedDataSource
import world.respect.datalayer.school.opds.ext.requireSelfUrl
import world.respect.datalayer.school.opds.ext.withAbsoluteSelfUrl
import world.respect.lib.opds.model.OpdsFeed

class OpdsFeedDataSourceHttp(
    private val httpClient: HttpClient,
    private val opdsFeedValidationHelper: BaseDataSourceValidationHelper? = null,
    private val tokenProvider: AuthTokenProvider,
): OpdsFeedDataSource {

    override fun getByUrlAsFlow(
        url: Url,
        params: DataLoadParams
    ): Flow<DataLoadState<OpdsFeed>> {
        return httpClient.getDataLoadResultAsFlow<OpdsFeed>(
            url = url,
            dataLoadParams = params,
            validationHelper = opdsFeedValidationHelper,
        ).map { loadResult ->
            /*
             * When the OpdsFeed is persisted to the database, the self url is used to determine the
             * url. The Url is hashed to make the primary key.
             */
            loadResult.map { it.withAbsoluteSelfUrl(url) }
        }
    }

    override suspend fun getByUrl(
        url: Url,
        params: DataLoadParams
    ): DataLoadState<OpdsFeed> {
        return httpClient.getAsDataLoadState<OpdsFeed>(
            url = url,
            validationHelper = opdsFeedValidationHelper,
        ).map {
            it.withAbsoluteSelfUrl(url)
        }
    }

    override suspend fun store(list: List<OpdsFeed>) {
        list.forEach { feed ->
            val url = feed.requireSelfUrl()

            httpClient.post(url) {
                useTokenProvider(tokenProvider)
                contentType(ContentType.Application.Json)
                setBody(feed)
            }
        }
    }

}