package de.arxsilex.maptools.converter.core

import kotlin.test.Test
import kotlin.test.assertEquals
import kotlin.test.assertFailsWith
import kotlin.test.assertTrue

class NormalizedMapAreaTest {
    @Test
    fun normalizesReverseDragDirection() {
        val area = NormalizedMapArea.fromDrag(0.8f, 0.7f, 0.2f, 0.1f)

        assertEquals(NormalizedMapArea(0.2f, 0.1f, 0.8f, 0.7f), area)
    }

    @Test
    fun clampsDragToPreviewBounds() {
        val area = NormalizedMapArea.fromDrag(-1f, -0.5f, 1.5f, 2f)

        assertEquals(NormalizedMapArea.Full, area)
    }

    @Test
    fun keepsClickSelectionLargeEnough() {
        val area = NormalizedMapArea.fromDrag(1f, 1f, 1f, 1f)

        assertTrue(area.widthFraction >= 0.0099f)
        assertTrue(area.heightFraction >= 0.0099f)
    }

    @Test
    fun translatesSelectionWhilePreservingSizeAndClampsItToSourceBounds() {
        val area = NormalizedMapArea(0.2f, 0.3f, 0.5f, 0.7f)

        assertAreaEquals(
            NormalizedMapArea(0.35f, 0.2f, 0.65f, 0.6f),
            area.translated(0.15f, -0.1f),
        )
        assertAreaEquals(NormalizedMapArea(0.7f, 0.6f, 1f, 1f), area.translated(2f, 2f))
        assertAreaEquals(NormalizedMapArea(0f, 0f, 0.3f, 0.4f), area.translated(-2f, -2f))
    }

    @Test
    fun resizesSelectionFromCornerWhileKeepingOppositeCornerFixed() {
        val area = NormalizedMapArea(0.2f, 0.3f, 0.6f, 0.8f)

        assertEquals(
            NormalizedMapArea(0.1f, 0.15f, 0.6f, 0.8f),
            area.resizedFromCorner(SelectionCorner.TOP_LEFT, 0.1f, 0.15f),
        )
        assertEquals(
            NormalizedMapArea(0.2f, 0.3f, 0.75f, 0.9f),
            area.resizedFromCorner(SelectionCorner.BOTTOM_RIGHT, 0.75f, 0.9f),
        )
    }

    @Test
    fun rejectsInvalidDirectBounds() {
        assertFailsWith<IllegalArgumentException> {
            NormalizedMapArea(0.5f, 0f, 0.5f, 1f)
        }
    }

    private fun assertAreaEquals(expected: NormalizedMapArea, actual: NormalizedMapArea) {
        assertEquals(expected.left, actual.left, 0.000_001f)
        assertEquals(expected.top, actual.top, 0.000_001f)
        assertEquals(expected.right, actual.right, 0.000_001f)
        assertEquals(expected.bottom, actual.bottom, 0.000_001f)
    }
}
