package de.krisenvorrat.app.domain.usecase

import de.krisenvorrat.app.domain.model.SettingsKey.StringKey
import de.krisenvorrat.app.domain.model.UpdateCheckResult
import de.krisenvorrat.app.domain.model.VersionInfo
import de.krisenvorrat.app.domain.repository.SettingsRepository
import de.krisenvorrat.app.domain.repository.UpdateRepository
import io.mockk.coEvery
import io.mockk.coVerify
import io.mockk.mockk
import kotlinx.coroutines.test.runTest
import org.junit.Assert.assertEquals
import org.junit.Assert.assertTrue
import org.junit.Test
import java.net.ConnectException

class CheckForUpdateUseCaseTest {

    private val updateRepository: UpdateRepository = mockk()
    private val settingsRepository: SettingsRepository = mockk()
    private val useCase = CheckForUpdateUseCase(updateRepository, settingsRepository)

    private fun setupServerUrl(url: String) {
        coEvery { settingsRepository.getString(StringKey.ServerUrl) } returns url
    }

    @Test
    fun test_invoke_serverHasNewerVersion_returnsUpdateAvailable() = runTest {
        // Given
        val versionInfo = VersionInfo(versionCode = 5, versionName = "2.0", apkUrl = "https://example.com/app.apk")
        setupServerUrl("https://example.com")
        coEvery { updateRepository.checkForUpdate("https://example.com") } returns Result.success(versionInfo)

        // When
        val result = useCase(currentVersionCode = 3)

        // Then
        assertTrue(result is UpdateCheckResult.UpdateAvailable)
        assertEquals(versionInfo, (result as UpdateCheckResult.UpdateAvailable).versionInfo)
    }

    @Test
    fun test_invoke_serverHasSameVersion_returnsUpToDate() = runTest {
        // Given
        val versionInfo = VersionInfo(versionCode = 3, versionName = "1.2", apkUrl = "https://example.com/app.apk")
        setupServerUrl("https://example.com")
        coEvery { updateRepository.checkForUpdate("https://example.com") } returns Result.success(versionInfo)

        // When
        val result = useCase(currentVersionCode = 3)

        // Then
        assertTrue(result is UpdateCheckResult.UpToDate)
    }

    @Test
    fun test_invoke_serverHasOlderVersion_returnsUpToDate() = runTest {
        // Given
        val versionInfo = VersionInfo(versionCode = 2, versionName = "1.0", apkUrl = "https://example.com/app.apk")
        setupServerUrl("https://example.com")
        coEvery { updateRepository.checkForUpdate("https://example.com") } returns Result.success(versionInfo)

        // When
        val result = useCase(currentVersionCode = 3)

        // Then
        assertTrue(result is UpdateCheckResult.UpToDate)
    }

    @Test
    fun test_invoke_serverUrlIsEmpty_returnsNotConfigured() = runTest {
        // Given
        setupServerUrl("")

        // When
        val result = useCase(currentVersionCode = 3)

        // Then
        assertTrue(result is UpdateCheckResult.NotConfigured)
        coVerify(exactly = 0) { updateRepository.checkForUpdate(any()) }
    }

    @Test
    fun test_invoke_serverUrlIsBlank_returnsNotConfigured() = runTest {
        // Given
        setupServerUrl("   ")

        // When
        val result = useCase(currentVersionCode = 3)

        // Then
        assertTrue(result is UpdateCheckResult.NotConfigured)
    }

    @Test
    fun test_invoke_networkError_returnsError() = runTest {
        // Given
        setupServerUrl("https://example.com")
        val networkError = ConnectException("Connection refused")
        coEvery { updateRepository.checkForUpdate("https://example.com") } returns Result.failure(networkError)

        // When
        val result = useCase(currentVersionCode = 3)

        // Then
        assertTrue(result is UpdateCheckResult.Error)
        assertEquals(networkError, (result as UpdateCheckResult.Error).cause)
    }
}
