package thb.jeanluc.adventure.loader;

import org.junit.jupiter.api.Test;
import thb.jeanluc.adventure.loader.dto.GameDto;
import thb.jeanluc.adventure.model.Npc;
import thb.jeanluc.adventure.model.Room;
import thb.jeanluc.adventure.model.item.Item;
import thb.jeanluc.adventure.model.item.PlainItem;

import java.util.HashMap;
import java.util.Map;

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

class WorldValidatorTest {

    private Map<String, Item> items() {
        Map<String, Item> m = new HashMap<>();
        m.put("lamp", PlainItem.builder().id("lamp").name("Lamp").description("d").build());
        return m;
    }

    private Map<String, Room> rooms() {
        Map<String, Room> m = new HashMap<>();
        m.put("kitchen", new Room("kitchen", "K", "d"));
        return m;
    }

    private Map<String, Npc> npcs(String greeting) {
        Map<String, Npc> m = new HashMap<>();
        m.put("man", Npc.shell("man", "Man", "d", greeting));
        return m;
    }

    @Test
    void happyPath_doesNotThrow() {
        var v = new WorldValidator(items(), npcs("hi"), rooms(),
                new GameDto("t", "1", "kitchen", 0, "w"));
        assertThat(v).isNotNull();
        v.validate();
    }

    @Test
    void invalidId_throws() {
        Map<String, Room> r = new HashMap<>();
        r.put("Kitchen-1", new Room("Kitchen-1", "K", "d"));
        var v = new WorldValidator(items(), npcs("hi"), r,
                new GameDto("t", "1", "kitchen", 0, "w"));
        assertThatThrownBy(v::validate)
                .isInstanceOf(WorldLoadException.class)
                .hasMessageContaining("Invalid id");
    }

    @Test
    void unknownStartRoom_throws() {
        var v = new WorldValidator(items(), npcs("hi"), rooms(),
                new GameDto("t", "1", "ghost_room", 0, "w"));
        assertThatThrownBy(v::validate)
                .isInstanceOf(WorldLoadException.class)
                .hasMessageContaining("ghost_room");
    }

    @Test
    void emptyGreeting_throws() {
        var v = new WorldValidator(items(), npcs(""), rooms(),
                new GameDto("t", "1", "kitchen", 0, "w"));
        assertThatThrownBy(v::validate)
                .isInstanceOf(WorldLoadException.class)
                .hasMessageContaining("greeting");
    }

    @Test
    void missingStartRoomField_throws() {
        var v = new WorldValidator(items(), npcs("hi"), rooms(),
                new GameDto("t", "1", null, 0, "w"));
        assertThatThrownBy(v::validate)
                .isInstanceOf(WorldLoadException.class)
                .hasMessageContaining("startRoom");
    }
}
