package thb.jeanluc.adventure.menu;

import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.TempDir;
import thb.jeanluc.adventure.game.GameSession;
import thb.jeanluc.adventure.io.TestIO;
import thb.jeanluc.adventure.loader.WorldLoader;
import thb.jeanluc.adventure.save.SaveService;
import thb.jeanluc.adventure.save.SaveSlotInfo;
import thb.jeanluc.adventure.save.Settings;
import thb.jeanluc.adventure.save.SettingsStore;
import thb.jeanluc.adventure.io.ConsoleIO;
import thb.jeanluc.adventure.io.MusicLevel;

import java.nio.file.Path;

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

class MenuTest {

    @Test
    void mainMenuMapsChoiceToAction() {
        // options order: New Game(1) / Load(2) / Settings(3) / Quit(4)
        assertThat(MainMenu.show(new TestIO().enqueue("1"))).isEqualTo(MenuAction.NEW_GAME);
        assertThat(MainMenu.show(new TestIO().enqueue("2"))).isEqualTo(MenuAction.LOAD);
        assertThat(MainMenu.show(new TestIO().enqueue("3"))).isEqualTo(MenuAction.SETTINGS);
        assertThat(MainMenu.show(new TestIO().enqueue("4"))).isEqualTo(MenuAction.QUIT);
    }

    @Test
    void promptNameUsesDefaultOnBlank() {
        assertThat(MainMenu.promptName(new TestIO().enqueue(""), "Manor")).isEqualTo("Manor");
        assertThat(MainMenu.promptName(new TestIO().enqueue("Spooky"), "Manor")).isEqualTo("Spooky");
    }

    @Test
    void pickSlotReturnsNullWhenEmpty(@TempDir Path dir) {
        TestIO io = new TestIO();
        assertThat(MainMenu.pickSlot(io, new SaveService(dir))).isNull();
        assertThat(io.allOutput()).contains("No saved games");
    }

    private void saveSlot(Path dir, String name) {
        var r = new WorldLoader().load();
        new SaveService(dir).save(new GameSession(r.world(), r.player(), name));
    }

    @Test
    void pickSlotReturnsChosenSlot(@TempDir Path dir) {
        saveSlot(dir, "Alpha");
        TestIO io = new TestIO().enqueue("1");
        SaveSlotInfo result = MainMenu.pickSlot(io, new SaveService(dir));
        assertThat(result).isNotNull();
        assertThat(result.slotName()).isEqualTo("Alpha");
    }

    @Test
    void pickSlotReturnsNullOnBack(@TempDir Path dir) {
        saveSlot(dir, "Alpha");
        // one slot → options are [1: Alpha, 2: Back]
        TestIO io = new TestIO().enqueue("2");
        assertThat(MainMenu.pickSlot(io, new SaveService(dir))).isNull();
    }

    @Test
    void settingsMenuTogglesGlyphAndPersists(@TempDir Path dir) {
        SettingsStore store = new SettingsStore(dir.resolve("settings.json"));
        TestIO io = new TestIO().enqueue("2").enqueue("4"); // toggle Glyphs, then Back
        Settings result = SettingsMenu.show(io, Settings.defaults(), store);
        assertThat(result.glyphMode()).isEqualTo(ConsoleIO.GlyphMode.ASCII);
        assertThat(store.load().glyphMode()).isEqualTo(ConsoleIO.GlyphMode.ASCII);
    }

    @Test
    void settingsMenuCyclesMusicLevelAndPersists(@TempDir Path dir) {
        SettingsStore store = new SettingsStore(dir.resolve("settings.json"));
        TestIO io = new TestIO().enqueue("3").enqueue("4"); // cycle Music once, then Back
        Settings result = SettingsMenu.show(io, Settings.defaults(), store);
        assertThat(result.musicLevel()).isEqualTo(MusicLevel.MEDIUM.next()); // HIGH
        assertThat(store.load().musicLevel()).isEqualTo(MusicLevel.MEDIUM.next());
    }
}
