package ca.recrown.islandsurvivalcraft.utilities;

import static org.junit.jupiter.api.Assertions.assertEquals;

import java.util.ArrayList;
import java.util.HashMap;

import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestInstance;
import org.junit.jupiter.api.TestInstance.Lifecycle;

import ca.recrown.islandsurvivalcraft.utilities.datatypes.Point2;

/**
 * Unit test for simple App.
 */
@TestInstance(Lifecycle.PER_CLASS)
public class GeneralUtilitiesTest {
    /**
     * Basic hashmap inversion test.
     */
    @Test
    public void testInvertHashMap()
    {
        HashMap<String, Integer> hashMap = new HashMap<>();
        hashMap.put("a", 1);
        hashMap.put("b", 1);
        hashMap.put("c", 2);
        hashMap.put("d", 2);

        HashMap<Integer, ArrayList<String>> res = GeneralUtilities.invertHashMap(hashMap);
        ArrayList<String> first = res.get(1);
        ArrayList<String> expectedFirst = new ArrayList<>();
        expectedFirst.add("a");
        expectedFirst.add("b");

        ArrayList<String> second = res.get(2);
        ArrayList<String> expectedSecond = new ArrayList<>();
        expectedSecond.add("c");
        expectedSecond.add("d");
        assertEquals(first, expectedFirst);
        assertEquals(second, expectedSecond);
    }

    @Test
    public void testMagnitudeAddPositive() {
        assertEquals(2, GeneralUtilities.addMagnitude(1, 1));
    }
    @Test
    public void testMagnitudeAddNegative() {
        assertEquals(-2, GeneralUtilities.addMagnitude(-1, 1));
    }

    @Test
    public void testWorldToChunkCoordinatesNegativePerfect() {
        assertEquals(new Point2(-4, -3), GeneralUtilities.worldToChunkCoordinates(-64, -48));
    }

    @Test
    public void testWorldToChunkCoordinatesNegativeOff() {
        assertEquals(new Point2(-4, -3), GeneralUtilities.worldToChunkCoordinates(-55, -33));
    }

    @Test
    public void testWorldToChunkCoordinatesNegativeOffClose() {
        assertEquals(new Point2(15, -15), GeneralUtilities.worldToChunkCoordinates(255, -227));
    }

    @Test
    public void testWorldToChunkCoordinatesPositivePerfect() {
        assertEquals(new Point2(4, 5), GeneralUtilities.worldToChunkCoordinates(64, 80));
    }

    @Test
    public void testWorldToChunkCoordinatesPositiveOff() {
        assertEquals(new Point2(4, 5), GeneralUtilities.worldToChunkCoordinates(67, 84));
    }

    @Test
    public void testWorldToLocalCoordinatesNegative() {
        assertEquals(new Point2(2, 5), GeneralUtilities.worldToLocalChunkCoordinates(-62, -27));
        assertEquals(new Point2(2, 5), GeneralUtilities.worldToLocalChunkCoordinates(new Point2(-62, -27)));
    }
    
    @Test
    public void testWorldToLocalCoordinatesNegativePerfect() {
        assertEquals(new Point2(0, 0), GeneralUtilities.worldToLocalChunkCoordinates(-128, -32));
        assertEquals(new Point2(0, 0), GeneralUtilities.worldToLocalChunkCoordinates(new Point2(-256, -16)));
    }

    @Test
    public void testWorldToLocalCoordinatesPositive() {
        assertEquals(new Point2(7, 3), GeneralUtilities.worldToLocalChunkCoordinates(39, 83));
        assertEquals(new Point2(7, 3), GeneralUtilities.worldToLocalChunkCoordinates(new Point2(39, 83)));    
    }

    @Test
    public void testWorldToLocalCoordinatesPositivePerfect() {
        assertEquals(new Point2(0, 0), GeneralUtilities.worldToLocalChunkCoordinates(1024, 32));
        assertEquals(new Point2(0, 0), GeneralUtilities.worldToLocalChunkCoordinates(new Point2(16, 80)));    
    }

    @Test
    public void testWorldToLocalCoordinatesPositiveEntirety() {
        int chunkX = 4;
        int chunkZ = 3;
        for (int x = 0; x < GeneralUtilities.CHUNK_SIZE; x++) {
            for (int z = 0; z < GeneralUtilities.CHUNK_SIZE; z++) {
                int worldX = GeneralUtilities.CHUNK_SIZE * chunkX + x;
                int worldZ = GeneralUtilities.CHUNK_SIZE * chunkZ + z;
                assertEquals(new Point2(x, z), GeneralUtilities.worldToLocalChunkCoordinates(new Point2(worldX, worldZ)));
            }
        }
    }

    @Test
    public void testWorldToLocalCoordinatesNegativeEntirety() {
        int chunkX = -42;
        int chunkZ = -3;
        for (int x = 0; x < GeneralUtilities.CHUNK_SIZE; x++) {
            for (int z = 0; z < GeneralUtilities.CHUNK_SIZE; z++) {
                int worldX = GeneralUtilities.CHUNK_SIZE * chunkX + x;
                int worldZ = GeneralUtilities.CHUNK_SIZE * chunkZ + z;
                assertEquals(new Point2(x, z), GeneralUtilities.worldToLocalChunkCoordinates(new Point2(worldX, worldZ)));
            }
        }
    }
}

