# NetworkModule.kt

    /*
     * The MIT License
     *
     * Original work sponsored and donated by The Danish Health Data Authority (http://www.sundhedsdatastyrelsen.dk)
     *
     * Copyright (C) 2023 The Danish Health Data Authority (http://www.sundhedsdatastyrelsen.dk)
     *
     *
     * Permission is hereby granted, free of charge, to any person obtaining a copy of
     * this software and associated documentation files (the "Software"), to deal in
     * the Software without restriction, including without limitation the rights to
     * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
     * of the Software, and to permit persons to whom the Software is furnished to do
     * so, subject to the following conditions:
     *
     *
     * The above copyright notice and this permission notice shall be included in all
     * copies or substantial portions of the Software.
     *
     *
     * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
     * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
     * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
     * SOFTWARE.
     */
    package dk.nsp.mingraviditet.core.network.di

    import android.content.Context
    import com.jakewharton.retrofit2.converter.kotlinx.serialization.asConverterFactory
    import dagger.Module
    import dagger.Provides
    import dagger.hilt.InstallIn
    import dagger.hilt.android.qualifiers.ApplicationContext
    import dagger.hilt.components.SingletonComponent
    import dk.nsp.mingraviditet.core.network.BuildConfig
    import dk.nsp.mingraviditet.core.network.appointments.AppointmentsOfflineDataSource
    import dk.nsp.mingraviditet.core.network.appointments.AssetManager
    import dk.nsp.mingraviditet.core.network.cms.CMSDataSource
    import dk.nsp.mingraviditet.core.network.cms.RetrofitCMSDataSource
    import dk.nsp.mingraviditet.core.network.cms.mock.MockCMSDataSource
    import dk.nsp.mingraviditet.core.network.util.converters.LocalDateTimeSerializer
    import dk.nsp.mingraviditet.core.shared.network.Dispatcher
    import dk.nsp.mingraviditet.core.shared.network.MGDispatchers
    import kotlinx.coroutines.CoroutineDispatcher
    import kotlinx.serialization.ExperimentalSerializationApi
    import kotlinx.serialization.json.Json
    import kotlinx.serialization.modules.SerializersModule
    import okhttp3.Call
    import okhttp3.ConnectionSpec
    import okhttp3.MediaType.Companion.toMediaType
    import okhttp3.OkHttpClient
    import okhttp3.logging.HttpLoggingInterceptor
    import retrofit2.Retrofit
    import java.time.LocalDateTime
    import java.util.concurrent.TimeUnit
    import javax.inject.Singleton

    @Module
    @InstallIn(SingletonComponent::class)
    object NetworkModule {

        @Provides
        @Singleton
        fun provideOkHttpCallFactory(): Call.Factory = OkHttpClient.Builder()
            .connectTimeout(1, TimeUnit.MINUTES)
            .writeTimeout(1, TimeUnit.MINUTES)
            .readTimeout(30, TimeUnit.SECONDS)
            .connectionSpecs(listOf(ConnectionSpec.MODERN_TLS))
            .addNetworkInterceptor(
                HttpLoggingInterceptor().apply {
                    if (BuildConfig.AllowLogNetwork) {
                        level = HttpLoggingInterceptor.Level.BASIC
    //                    level = HttpLoggingInterceptor.Level.BODY
                    }
                },
            )
            .build()

        @OptIn(ExperimentalSerializationApi::class)
        @Provides
        @Singleton
        fun provideNetworkJson(): Json = Json {
            ignoreUnknownKeys = true
            explicitNulls = false
            serializersModule = SerializersModule {
                contextual(LocalDateTime::class, LocalDateTimeSerializer)
            }
        }

        @Provides
        @Singleton
        fun provideRetrofit(
            networkJson: Json,
            okHttpCallFactory: Call.Factory,
        ): Retrofit = Retrofit.Builder()
            .baseUrl(BuildConfig.cmsBackendUrl)
            .callFactory(okHttpCallFactory)
            .addConverterFactory(
                networkJson.asConverterFactory("application/json".toMediaType()),
            )
            .build()

        @Suppress("KotlinConstantConditions")
        @Provides
        @Singleton
        fun provideCMSDataSource(
            retrofit: Retrofit,
            @Dispatcher(MGDispatchers.IO) ioDispatcher: CoroutineDispatcher,
        ): CMSDataSource = if (BuildConfig.FLAVOR == "mock") {
            MockCMSDataSource()
        } else {
            RetrofitCMSDataSource(retrofit, ioDispatcher)
        }

        @Provides
        @Singleton
        fun providesLocalAssetsManager(
            @ApplicationContext context: Context,
        ): AssetManager = AssetManager(context.assets::open)

        @Provides
        @Singleton
        fun providesCareplanDataSource(
            json: Json,
            assets: AssetManager,
            @Dispatcher(MGDispatchers.IO) ioDispatcher: CoroutineDispatcher,
        ) = AppointmentsOfflineDataSource(
            json = json,
            assets = assets,
            ioDispatcher = ioDispatcher,
        )
    }