package pl.firmatpp.kierowca.ui

import java.time.LocalDate
import org.junit.Assert.assertEquals
import org.junit.Assert.assertFalse
import org.junit.Assert.assertTrue
import org.junit.Test
import pl.firmatpp.kierowca.data.model.DriverRouteDto
import pl.firmatpp.kierowca.data.upload.PhotoUploadEntity

class DriverUiRulesTest {
    private val today = LocalDate.parse("2026-06-30")

    @Test
    fun allowsPhotoActionsOnlyForTodayRouteDate() {
        assertTrue(canManageRoutePhotos("2026-06-30", today))
        assertFalse(canManageRoutePhotos("2026-06-29", today))
        assertFalse(canManageRoutePhotos("2026-07-01", today))
    }

    @Test
    fun blocksPhotoActionsWhenDateIsInvalid() {
        assertFalse(canManageRoutePhotos("", today))
        assertFalse(canManageRoutePhotos("not-a-date", today))
    }

    @Test
    fun allowsRouteCompletionOnlyForTodayPlannedOrInProgressRoutes() {
        assertTrue(canCompleteRouteFromDriverApp(route(status = "ZAPLANOWANA"), "2026-06-30", today))
        assertTrue(canCompleteRouteFromDriverApp(route(status = "W TRAKCIE"), "2026-06-30", today))
        assertFalse(canCompleteRouteFromDriverApp(route(status = "ZAKOŃCZONA"), "2026-06-30", today))
        assertFalse(canCompleteRouteFromDriverApp(route(status = "NIEROZPOZNANA"), "2026-06-30", today))
        assertFalse(canCompleteRouteFromDriverApp(route(status = "ZAPLANOWANA"), "2026-07-01", today))
        assertFalse(canCompleteRouteFromDriverApp(route(status = "ZAPLANOWANA"), "2026-06-29", today))
    }

    @Test
    fun calculatesPhotoGridRowsForTwoColumnInlineGallery() {
        assertEquals(0, inlinePhotoGridRows(0))
        assertEquals(1, inlinePhotoGridRows(1))
        assertEquals(1, inlinePhotoGridRows(2))
        assertEquals(2, inlinePhotoGridRows(3))
        assertEquals(3, inlinePhotoGridRows(5))
    }

    @Test
    fun countsServerPhotosAndLocalUploadsAsVisibleAttachments() {
        assertEquals(0, visiblePhotoAttachmentCount(serverPhotoCount = 0, localUploadCount = 0))
        assertEquals(1, visiblePhotoAttachmentCount(serverPhotoCount = 0, localUploadCount = 1))
        assertEquals(3, visiblePhotoAttachmentCount(serverPhotoCount = 1, localUploadCount = 2))
    }

    @Test
    fun countsOnlyUnconfirmedNonCancelledUploadsInQueue() {
        assertEquals(0, queuedPhotoUploadCount(emptyList()))
        assertEquals(
            4,
            queuedPhotoUploadCount(
                listOf(
                    "PENDING",
                    "UPLOADING",
                    "VERIFYING",
                    "FAILED_RETRYABLE",
                    "CONFIRMED",
                    "CANCELLED",
                ),
            ),
        )
        assertEquals(1, queuedPhotoUploadCount(listOf("FAILED_PERMANENT")))
    }

    @Test
    fun usesCreatedAtBeforeTakenAtForNewestFirstPhotoSorting() {
        val fallback = 100L

        assertEquals(
            1_782_892_800_000L,
            routePhotoSortEpochMillis(
                createdAt = "2026-07-01T10:00:00+02:00",
                takenAt = "2026-07-01T08:00:00+02:00",
                fallback = fallback,
            ),
        )
        assertEquals(
            1_782_885_600_000L,
            routePhotoSortEpochMillis(
                createdAt = null,
                takenAt = "2026-07-01T08:00:00+02:00",
                fallback = fallback,
            ),
        )
        assertEquals(fallback, routePhotoSortEpochMillis(createdAt = null, takenAt = null, fallback = fallback))
    }

    @Test
    fun allowsDeleteIconForConfirmedLocalUploadWithServerPhotoId() {
        assertEquals("42", confirmedUploadServerPhotoId("CONFIRMED", "42"))
        assertEquals(null, confirmedUploadServerPhotoId("CONFIRMED", ""))
        assertEquals(null, confirmedUploadServerPhotoId("UPLOADING", "42"))
        assertEquals(null, confirmedUploadServerPhotoId("FAILED_RETRYABLE", "42"))
    }

    @Test
    fun allowsRetryActionOnlyForRetryableFailedUploads() {
        assertTrue(canRetryPhotoUpload("FAILED_RETRYABLE"))
        assertFalse(canRetryPhotoUpload("PENDING"))
        assertFalse(canRetryPhotoUpload("UPLOADING"))
        assertFalse(canRetryPhotoUpload("VERIFYING"))
        assertFalse(canRetryPhotoUpload("CONFIRMED"))
        assertFalse(canRetryPhotoUpload("FAILED_PERMANENT"))
        assertFalse(canRetryPhotoUpload("CANCELLED"))
    }

    @Test
    fun showsFailureDetailsOnlyForFailedUploadsWithErrorMessage() {
        assertTrue(canShowPhotoUploadFailureDetails("FAILED_RETRYABLE", "Typ: błąd serwera"))
        assertTrue(canShowPhotoUploadFailureDetails("FAILED_PERMANENT", "Typ: błąd aplikacji"))
        assertFalse(canShowPhotoUploadFailureDetails("FAILED_RETRYABLE", null))
        assertFalse(canShowPhotoUploadFailureDetails("FAILED_RETRYABLE", ""))
        assertFalse(canShowPhotoUploadFailureDetails("UPLOADING", "Typ: błąd serwera"))
        assertFalse(canShowPhotoUploadFailureDetails("CONFIRMED", "Typ: błąd serwera"))
    }

    @Test
    fun createsFullScreenPreviewForLocalUploadBeforeRouteRefresh() {
        val photo = localUploadPreviewPhoto(upload(status = "CONFIRMED", serverPhotoId = "55"))

        requireNotNull(photo)
        assertEquals("local-upload-123", photo.id)
        assertEquals("10", photo.routeId)
        assertEquals("file:/tmp/photo.jpg", photo.url)
        assertEquals("2026-07-01T08:00:00Z", photo.takenAt)
        assertEquals(50.1, photo.latitude ?: 0.0, 0.0)
        assertEquals(true, photo.canDelete)
    }

    @Test
    fun preciseLocationRequirementAllowsCameraOnlyWithFineLocation() {
        assertTrue(canLaunchCameraWithLocationPolicy(requirePreciseLocation = false, hasFineLocation = false))
        assertTrue(canLaunchCameraWithLocationPolicy(requirePreciseLocation = true, hasFineLocation = true))
        assertFalse(canLaunchCameraWithLocationPolicy(requirePreciseLocation = true, hasFineLocation = false))
    }

    private fun route(status: String): DriverRouteDto =
        DriverRouteDto(
            id = "1",
            startsAt = "",
            originName = "Baza",
            destinationName = "Instalacja",
            contractorName = "TPP",
            contractName = "Kontrakt",
            contractCode = "TPP-1",
            relationLabel = "Baza -> Instalacja",
            status = status,
            distanceKm = 1.0,
            notes = null,
            truck = null,
        )

    private fun upload(status: String, serverPhotoId: String? = null): PhotoUploadEntity =
        PhotoUploadEntity(
            clientRequestId = "local-upload-123",
            routeId = "10",
            localPath = "/tmp/photo.jpg",
            source = "camera",
            takenAt = "2026-07-01T08:00:00Z",
            latitude = 50.1,
            longitude = 19.9,
            locationAccuracyMeters = 8.0,
            mimeType = "image/jpeg",
            size = 1200,
            contentSha256 = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
            status = status,
            serverPhotoId = serverPhotoId,
        )
}
