package com.garfiec.librechat

import com.garfiec.librechat.core.common.di.commonModule
import com.garfiec.librechat.core.common.network.ConnectivityObserver
import com.garfiec.librechat.core.data.datastore.ConfigCacheDataStore
import com.garfiec.librechat.core.data.datastore.ServerDataStore
import com.garfiec.librechat.core.data.datastore.SettingsDataStore
import com.garfiec.librechat.core.data.datastore.ThemeDataStore
import com.garfiec.librechat.core.data.di.dataModule
import com.garfiec.librechat.core.data.repository.AgentRepository
import com.garfiec.librechat.core.data.repository.ApiKeyRepository
import com.garfiec.librechat.core.data.repository.AuthRepository
import com.garfiec.librechat.core.data.repository.BalanceRepository
import com.garfiec.librechat.core.data.repository.BannerRepository
import com.garfiec.librechat.core.data.repository.ChatRepository
import com.garfiec.librechat.core.data.repository.ConfigRepository
import com.garfiec.librechat.core.data.repository.ConversationRepository
import com.garfiec.librechat.core.data.repository.DraftRepository
import com.garfiec.librechat.core.data.repository.FileRepository
import com.garfiec.librechat.core.data.repository.KeyRepository
import com.garfiec.librechat.core.data.repository.McpRepository
import com.garfiec.librechat.core.data.repository.MemoryRepository
import com.garfiec.librechat.core.data.repository.MessageRepository
import com.garfiec.librechat.core.data.repository.PresetRepository
import com.garfiec.librechat.core.data.repository.PromptRepository
import com.garfiec.librechat.core.data.repository.SearchRepository
import com.garfiec.librechat.core.data.repository.ShareRepository
import com.garfiec.librechat.core.data.repository.SpeechRepository
import com.garfiec.librechat.core.data.repository.TagRepository
import com.garfiec.librechat.core.data.repository.UserRepository
import com.garfiec.librechat.core.network.api.AgentsApi
import com.garfiec.librechat.core.network.api.ApiKeysApi
import com.garfiec.librechat.core.network.api.AuthApi
import com.garfiec.librechat.core.network.api.BalanceApi
import com.garfiec.librechat.core.network.api.BannerApi
import com.garfiec.librechat.core.network.api.ChatApi
import com.garfiec.librechat.core.network.api.ConfigApi
import com.garfiec.librechat.core.network.api.ConversationsApi
import com.garfiec.librechat.core.network.api.FilesApi
import com.garfiec.librechat.core.network.api.FilesExtApi
import com.garfiec.librechat.core.network.api.KeysApi
import com.garfiec.librechat.core.network.api.McpApi
import com.garfiec.librechat.core.network.api.MemoriesApi
import com.garfiec.librechat.core.network.api.MessagesApi
import com.garfiec.librechat.core.network.api.PresetsApi
import com.garfiec.librechat.core.network.api.PromptsApi
import com.garfiec.librechat.core.network.api.SearchApi
import com.garfiec.librechat.core.network.api.ShareApi
import com.garfiec.librechat.core.network.api.SpeechApi
import com.garfiec.librechat.core.network.api.TagsApi
import com.garfiec.librechat.core.network.api.UserApi
import com.garfiec.librechat.core.network.client.SecureTokenStorage
import com.garfiec.librechat.core.network.client.ServerUrlProvider
import com.garfiec.librechat.core.network.client.TokenManager
import com.garfiec.librechat.core.network.di.networkModule
import com.garfiec.librechat.core.network.sse.SseClient
import com.garfiec.librechat.feature.agents.di.agentsModule
import com.garfiec.librechat.feature.auth.di.authModule
import com.garfiec.librechat.feature.auth.oauth.OAuthLauncher
import com.garfiec.librechat.feature.chat.di.chatModule
import com.garfiec.librechat.feature.conversations.di.conversationsModule
import com.garfiec.librechat.feature.files.di.filesModule
import com.garfiec.librechat.feature.files.platform.FileReader
import com.garfiec.librechat.feature.settings.di.settingsModule
import com.garfiec.librechat.shared.navigation.sharedAppModule
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.CoroutineScope
import org.junit.Test
import org.koin.core.module.Module
import org.koin.test.verify.verify
import kotlin.reflect.KClass

class KoinGraphVerificationTest {

    private val allModules: List<Module> = listOf(
        commonModule,
        networkModule,
        dataModule,
        sharedAppModule,
        authModule,
        chatModule,
        conversationsModule,
        settingsModule,
        agentsModule,
        filesModule,
    )

    /**
     * Integration-level Koin graph verification.
     *
     * Koin's verify() operates per-module and cannot resolve definitions
     * from other modules. This test whitelists all cross-module and
     * framework types so every module is verified in a single test class.
     * If a type is renamed or removed, this test will catch it.
     */
    @OptIn(org.koin.core.annotation.KoinExperimentalAPI::class)
    @Test
    fun verifyFullKoinGraph() {
        val extraTypes = mutableListOf<KClass<*>>(
            // Android framework
            android.content.Context::class,
            android.app.Application::class,
            androidx.lifecycle.SavedStateHandle::class,
            // core:common provides
            CoroutineDispatcher::class,
            CoroutineScope::class,
            ConnectivityObserver::class,
            // core:network provides
            TokenManager::class,
            SecureTokenStorage::class,
            ServerUrlProvider::class,
            SseClient::class,
            AgentsApi::class,
            ApiKeysApi::class,
            AuthApi::class,
            BalanceApi::class,
            BannerApi::class,
            ChatApi::class,
            ConfigApi::class,
            ConversationsApi::class,
            FilesApi::class,
            FilesExtApi::class,
            KeysApi::class,
            McpApi::class,
            MemoriesApi::class,
            MessagesApi::class,
            PresetsApi::class,
            PromptsApi::class,
            SearchApi::class,
            ShareApi::class,
            SpeechApi::class,
            TagsApi::class,
            UserApi::class,
            // core:data provides
            ConfigCacheDataStore::class,
            ServerDataStore::class,
            SettingsDataStore::class,
            ThemeDataStore::class,
            AgentRepository::class,
            ApiKeyRepository::class,
            AuthRepository::class,
            BalanceRepository::class,
            BannerRepository::class,
            ChatRepository::class,
            ConfigRepository::class,
            ConversationRepository::class,
            DraftRepository::class,
            FileRepository::class,
            KeyRepository::class,
            McpRepository::class,
            MemoryRepository::class,
            MessageRepository::class,
            PresetRepository::class,
            PromptRepository::class,
            SearchRepository::class,
            ShareRepository::class,
            SpeechRepository::class,
            TagRepository::class,
            UserRepository::class,
            // feature:auth platform provides
            OAuthLauncher::class,
            // feature:files platform provides
            FileReader::class,
            // Wrappers/DSL types that verify can't resolve via constructor
            kotlin.Lazy::class,
            java.io.File::class,
        )

        // Types whose libraries aren't on the app test classpath (transitive
        // implementation deps). Resolve via reflection at runtime.
        val reflectionTypes = listOf(
            "io.ktor.client.HttpClient",
            "io.ktor.client.engine.HttpClientEngine",
            "io.ktor.client.engine.HttpClientEngineConfig",
            "kotlinx.serialization.json.Json",
            "androidx.datastore.core.DataStore",
        )
        reflectionTypes.forEach { className ->
            extraTypes.add(Class.forName(className).kotlin)
        }

        allModules.forEach { module ->
            module.verify(extraTypes = extraTypes)
        }
    }
}
