package thb.jeanluc.adventure.game;

import org.junit.jupiter.api.Test;
import thb.jeanluc.adventure.command.CommandParser;
import thb.jeanluc.adventure.command.CommandRegistry;
import thb.jeanluc.adventure.command.impl.LookCommand;
import thb.jeanluc.adventure.io.TestIO;
import thb.jeanluc.adventure.model.Condition;
import thb.jeanluc.adventure.model.Ending;
import thb.jeanluc.adventure.model.Player;
import thb.jeanluc.adventure.model.Room;
import thb.jeanluc.adventure.model.Tutorial;
import thb.jeanluc.adventure.model.TutorialStep;
import thb.jeanluc.adventure.model.World;

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

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

class GameTutorialTest {

    @Test
    void guideBeginsAndAdvancesThenSkipEndsViaLoop() {
        Room kitchen = new Room("kitchen", "Kitchen", "d");
        World w = new World(Map.of("kitchen", kitchen), Map.of(), Map.of(), "t", "w");
        TestIO io = new TestIO();
        // scripted player input: a matching 'look', then 'skip'; then EOF (null) ends run()
        io.enqueue("look").enqueue("skip");
        GameContext ctx = new GameContext(new GameSession(w, new Player(kitchen, 0), "s"), io);

        CommandRegistry registry = new CommandRegistry();
        registry.register(new LookCommand(), "look", "l");

        Tutorial t = new Tutorial("INTRO",
                List.of(new TutorialStep("do look", "look", 0, "STEP1-OK", "hint"),
                        new TutorialStep("do look again", "look", 0, "STEP2-OK", "hint")),
                "TIPS");
        Game game = new Game(ctx, registry, new CommandParser());
        game.setTutorialGuide(new TutorialGuide(t, registry));

        game.run();

        String out = io.allOutput();
        assertThat(out).contains("INTRO");      // begin printed
        assertThat(out).contains("STEP1-OK");   // first 'look' advanced step 1
        assertThat(out).contains("Tutorial skipped"); // 'skip' ended it before step 2 finished
    }

    @Test
    void endingsAreSuppressedWhileTutorialActiveAndFireAfter() {
        Room kitchen = new Room("kitchen", "Kitchen", "d");
        Ending fled = new Ending("fled", "Fled", false,
                List.of(new Condition(Condition.Type.FLAG, "fled")), "ENDING-TEXT");
        World w = new World(Map.of("kitchen", kitchen), Map.of(), Map.of(),
                "t", "w", Map.of(), List.of(fled));
        TestIO io = new TestIO();
        io.enqueue("look"); // completes the 1-step tutorial; then EOF ends run()
        GameContext ctx = new GameContext(new GameSession(w, new Player(kitchen, 0), "s"), io);
        ctx.getState().set("fled"); // ending condition already met from the start

        CommandRegistry registry = new CommandRegistry();
        registry.register(new LookCommand(), "look", "l");

        Tutorial t = new Tutorial("INTRO",
                List.of(new TutorialStep("do look", "look", 0, "STEP1-OK", "hint")), "TIPS");
        Game game = new Game(ctx, registry, new CommandParser());
        game.setTutorialGuide(new TutorialGuide(t, registry));

        game.run();

        String out = io.allOutput();
        // The 'look' was processed -> the pre-loop ending did NOT stop the game first.
        assertThat(out).contains("STEP1-OK");
        // After the tutorial finished, the ending fired.
        assertThat(out).contains("ENDING-TEXT");
        assertThat(out.indexOf("STEP1-OK")).isLessThan(out.indexOf("ENDING-TEXT"));
    }
}
