package thb.jeanluc.adventure.map;

import org.junit.jupiter.api.Test;
import thb.jeanluc.adventure.io.text.CellState;
import thb.jeanluc.adventure.io.text.MapView;
import thb.jeanluc.adventure.io.text.RoomCell;
import thb.jeanluc.adventure.model.Direction;
import thb.jeanluc.adventure.model.Room;
import thb.jeanluc.adventure.model.World;

import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Optional;

import static org.assertj.core.api.Assertions.assertThat;

class MapLayoutTest {

    private World worldOf(Room... rooms) {
        Map<String, Room> byId = new java.util.LinkedHashMap<>();
        for (Room r : rooms) {
            byId.put(r.getId(), r);
        }
        return new World(byId, Map.of(), Map.of(), "t", "w");
    }

    private Optional<RoomCell> cell(MapView v, String id) {
        return v.cells().stream().filter(c -> c.id().equals(id)).findFirst();
    }

    @Test
    void placesNeighbourByDirectionAndMarksCurrent() {
        Room kitchen = new Room("kitchen", "Kitchen", "d");
        Room hallway = new Room("hallway", "Hallway", "d");
        kitchen.addExit(Direction.NORTH, hallway);
        hallway.addExit(Direction.SOUTH, kitchen);
        World w = worldOf(kitchen, hallway);

        MapView v = MapLayout.compute(w, new LinkedHashSet<>(java.util.List.of("kitchen", "hallway")), hallway);

        RoomCell k = cell(v, "kitchen").orElseThrow();
        RoomCell h = cell(v, "hallway").orElseThrow();
        // hallway is north of kitchen -> smaller y
        assertThat(h.y()).isLessThan(k.y());
        assertThat(h.state()).isEqualTo(CellState.CURRENT);
        assertThat(k.state()).isEqualTo(CellState.VISITED);
    }

    @Test
    void unexploredNeighbourIsKnownStub() {
        Room kitchen = new Room("kitchen", "Kitchen", "d");
        Room cellar = new Room("cellar", "Cellar", "d");
        kitchen.addExit(Direction.EAST, cellar);
        cellar.addExit(Direction.WEST, kitchen);
        World w = worldOf(kitchen, cellar);

        MapView v = MapLayout.compute(w, new LinkedHashSet<>(java.util.List.of("kitchen")), kitchen);

        RoomCell c = cell(v, "cellar").orElseThrow();
        assertThat(c.state()).isEqualTo(CellState.KNOWN);
        assertThat(c.name()).isEqualTo("?");
        assertThat(v.connections()).hasSize(1);
    }

    @Test
    void coordsAreNormalisedToNonNegative() {
        Room kitchen = new Room("kitchen", "Kitchen", "d");
        Room west = new Room("west", "West", "d");
        kitchen.addExit(Direction.WEST, west);
        west.addExit(Direction.EAST, kitchen);
        World w = worldOf(kitchen, west);

        MapView v = MapLayout.compute(w, new LinkedHashSet<>(java.util.List.of("kitchen", "west")), kitchen);
        assertThat(v.cells()).allSatisfy(c -> {
            assertThat(c.x()).isGreaterThanOrEqualTo(0);
            assertThat(c.y()).isGreaterThanOrEqualTo(0);
        });
    }

    @Test
    void emptyVisitedYieldsEmptyMap() {
        World w = worldOf(new Room("kitchen", "Kitchen", "d"));
        MapView v = MapLayout.compute(w, new LinkedHashSet<>(), null);
        assertThat(v.cells()).isEmpty();
    }
}
