package thb.jeanluc.adventure.game;

import org.junit.jupiter.api.Test;
import thb.jeanluc.adventure.io.TestIO;
import thb.jeanluc.adventure.io.text.QuestView;
import thb.jeanluc.adventure.model.Condition;
import thb.jeanluc.adventure.model.Effect;
import thb.jeanluc.adventure.model.Player;
import thb.jeanluc.adventure.model.Quest;
import thb.jeanluc.adventure.model.QuestStage;
import thb.jeanluc.adventure.model.Room;
import thb.jeanluc.adventure.model.World;

import java.util.List;
import java.util.Map;

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

class QuestEngineTest {
    private GameContext ctx(Quest quest) {
        Player p = new Player(new Room("k", "K", "d"), 0);
        World w = new World(Map.of(), Map.of(), Map.of(), "t", "w", Map.of(quest.id(), quest));
        return new GameContext(w, p, new TestIO());
    }

    private Quest twoStage() {
        return new Quest("q", "Quest", true, List.of(
                new QuestStage("Stage one", List.of(new Condition(Condition.Type.FLAG, "a")), List.of()),
                new QuestStage("Stage two", List.of(new Condition(Condition.Type.FLAG, "b")),
                        List.of(new Effect(Effect.Type.SET_FLAG, "done")))), List.of());
    }

    @Test
    void autoStartsAndShowsFirstObjective() {
        GameContext ctx = ctx(twoStage());
        QuestEngine.tick(ctx);
        QuestView v = QuestEngine.viewOf(ctx);
        assertThat(v.active()).hasSize(1);
        assertThat(v.active().getFirst().objective()).isEqualTo("Stage one");
    }

    @Test
    void advancesWhenConditionHolds() {
        GameContext ctx = ctx(twoStage());
        QuestEngine.tick(ctx);
        ctx.getState().set("a");
        QuestEngine.tick(ctx);
        assertThat(QuestEngine.viewOf(ctx).active().getFirst().objective()).isEqualTo("Stage two");
        assertThat(((TestIO) ctx.getIo()).allOutput()).contains("Objective complete");
    }

    @Test
    void completesAfterLastStageAndAppliesReward() {
        GameContext ctx = ctx(twoStage());
        ctx.getState().set("a");
        ctx.getState().set("b");
        QuestEngine.tick(ctx); // cascades through both stages in one tick
        QuestView v = QuestEngine.viewOf(ctx);
        assertThat(v.active()).isEmpty();
        assertThat(v.completed()).containsExactly("Quest");
        assertThat(ctx.getState().isSet("done")).isTrue();
    }
}
