package pl.firmatpp.kierowca.data

import java.io.IOException
import java.net.UnknownHostException
import kotlin.coroutines.cancellation.CancellationException
import org.junit.Assert.assertEquals
import org.junit.Assert.assertFalse
import org.junit.Assert.assertSame
import org.junit.Assert.assertTrue
import org.junit.Assert.fail
import org.junit.Test

class ApiErrorMapperTest {
    @Test
    fun rethrowsWorkerCancellationInsteadOfMappingItAsApplicationFailure() {
        val cancellation = CancellationException("Job was cancelled")

        try {
            cancellation.rethrowIfCancellation()
            fail("CancellationException should be rethrown")
        } catch (thrown: CancellationException) {
            assertSame(cancellation, thrown)
        }
    }

    @Test
    fun mapsNetworkFailuresToRetryableOfflineMessage() {
        val error = ApiErrorMapper.map(IOException("timeout"))

        assertEquals(ApiErrorKind.Network, error.kind)
        assertTrue(error.retryable)
        assertEquals("Nie udało się połączyć z serwerem. Operacja nie została potwierdzona.", error.message)
    }

    @Test
    fun mapsUnknownHostToActionableOfflineMessage() {
        val error = ApiErrorMapper.map(UnknownHostException("api-intranet.firmatpp.pl"))

        assertEquals(ApiErrorKind.Network, error.kind)
        assertTrue(error.retryable)
        assertEquals(
            "Brak internetu lub połączenia z serwerem. Sprawdź zasięg i spróbuj ponownie.",
            error.message,
        )
    }

    @Test
    fun doesNotReportExpectedNetworkFailuresAsNonFatal() {
        assertFalse(ApiErrorMapper.shouldReportNonFatal(UnknownHostException("api-intranet.firmatpp.pl")))
    }

    @Test
    fun mapsMobileApiProblemCodes() {
        val error = ApiErrorMapper.mapProblem(
            statusCode = 422,
            code = "PHOTO_IDEMPOTENCY_CONFLICT",
            message = "Ten upload został już użyty dla innego zdjęcia.",
            retryable = false,
        )

        assertEquals(ApiErrorKind.Validation, error.kind)
        assertFalse(error.retryable)
        assertEquals("PHOTO_IDEMPOTENCY_CONFLICT", error.code)
        assertEquals("Ten upload został już użyty dla innego zdjęcia.", error.message)
    }

    @Test
    fun mapsServerErrorsToRetryableUnconfirmedMessage() {
        val error = ApiErrorMapper.mapHttpStatus(503, null)

        assertEquals(ApiErrorKind.Server, error.kind)
        assertTrue(error.retryable)
        assertEquals("Serwer nie potwierdził operacji. Aplikacja spróbuje ponownie.", error.message)
    }

    @Test
    fun keepsRawServerResponseForTroubleshooting() {
        val body = """{"code":"PHOTO_SERVER_UNAVAILABLE","message":"Storage timeout","retryable":true}"""
        val error = ApiErrorMapper.mapHttpStatus(503, body)

        assertEquals(ApiErrorKind.Server, error.kind)
        assertEquals(503, error.statusCode)
        assertEquals("PHOTO_SERVER_UNAVAILABLE", error.code)
        assertEquals("Storage timeout", error.message)
        assertEquals(body, error.responseBody)
    }
}
