package pl.firmatpp.kierowca.data.sync

import java.io.IOException
import kotlinx.coroutines.delay
import kotlinx.coroutines.test.runTest
import org.junit.Assert.assertEquals
import org.junit.Assert.assertTrue
import org.junit.Test

class StartupOfflineFallbackLoaderTest {
    @Test
    fun returnsServerDataBeforeTimeout() = runTest {
        val loader = StartupOfflineFallbackLoader(timeoutMillis = 1_000L)

        val result = loader.load(
            onlineLoad = { "server" },
            offlineLoad = { "cache" },
        )

        assertEquals("server", result)
    }

    @Test
    fun returnsCachedDataWhenServerExceedsTimeout() = runTest {
        val loader = StartupOfflineFallbackLoader(timeoutMillis = 1_000L)

        val result = loader.load(
            onlineLoad = {
                delay(2_000L)
                "server"
            },
            offlineLoad = { "cache" },
        )

        assertEquals("cache", result)
    }

    @Test
    fun reportsMissingOfflineDataAfterTimeout() = runTest {
        val loader = StartupOfflineFallbackLoader(timeoutMillis = 1_000L)

        val error = runCatching {
            loader.load(
                onlineLoad = {
                    delay(2_000L)
                    "server"
                },
                offlineLoad = { null },
            )
        }.exceptionOrNull()

        assertTrue(error is IOException)
    }

    @Test
    fun doesNotHideAuthenticationFailures() = runTest {
        val loader = StartupOfflineFallbackLoader(timeoutMillis = 1_000L)
        val authenticationFailure = IllegalStateException("401")

        val error = runCatching {
            loader.load(
                onlineLoad = { throw authenticationFailure },
                offlineLoad = { "cache" },
            )
        }.exceptionOrNull()

        assertTrue(error is IllegalStateException)
        assertEquals(authenticationFailure.message, error?.message)
    }
}
