package backend.academy.service;

import backend.academy.model.Complexity;
import backend.academy.model.GameStatus;
import backend.academy.model.Word;
import backend.academy.repository.WordRepository;
import backend.academy.repository.WordsWordRepositoryImpl;
import backend.academy.service.cliParams.GuessParams;
import backend.academy.service.cliParams.HelpParams;
import backend.academy.service.cliParams.HintParam;
import backend.academy.service.cliParams.StartParams;
import backend.academy.util.GetRandomEnum;
import backend.academy.util.Properties;
import backend.academy.util.impl.CsvWordsReader;
import com.beust.jcommander.JCommander;
import com.beust.jcommander.ParameterException;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import lombok.extern.slf4j.Slf4j;

@Slf4j
public class GameSession {
    private final HangmanInterface hangmanInterface;
    private final WordRepository wordRepository;

    private Game game;
    private boolean gameSessionIsActive = true;

    public GameSession() {
        String path = Properties.getResourcesFilePath() + Properties.getWordsFileName();
        wordRepository = new WordsWordRepositoryImpl(new CsvWordsReader(), path);
        hangmanInterface = new HangmanInterface();
    }

    private void startGame(Complexity complexity) {
        Word word = wordRepository.getRandomWordByComplexity(complexity);
        game = new Game(word, complexity.attemptsCount());
    }

    public void startGameSession() throws IOException {
        BufferedReader reader = new BufferedReader(new InputStreamReader(System.in, StandardCharsets.UTF_8));
        log.info("Starting game session. \nWelcome to HangMan Game! Please review the commands \"help\"");
        while (gameSessionIsActive) {

            if (!reader.ready()) {
                continue;
            }

            StartParams startParams = new StartParams();
            HintParam hintParam = new HintParam();
            GuessParams guessParams = new GuessParams();
            HelpParams helpParams = new HelpParams();

            JCommander jCommander = JCommander.newBuilder()
                .addCommand(startParams.command(), startParams)
                .addCommand(hintParam.command(), hintParam)
                .addCommand(helpParams.command(), helpParams)
                .addCommand(guessParams.command(), guessParams)
                .build();

            String line = reader.readLine();
            if (line == null) {
                continue;
            }

            String[] cmds = line.split(" ");

            try {
                jCommander.parse(cmds);
            } catch (ParameterException e) {
                log.error("Something went wrong, try again or type \"help\"");
                continue;
            }

            if (jCommander.getParsedCommand().equals(startParams.command())) {

                Complexity complexity;
                if (startParams.complexity() == null) {
                    complexity = GetRandomEnum.random(Complexity.class);
                } else {
                    complexity = startParams.complexity();
                }

                startGame(complexity);
                printGameInterface();
            } else {

                if (game == null) {
                    log.error("Cannot call command while game is not running");
                    continue;
                }

                if (jCommander.getParsedCommand().equals(hintParam.command())) {

                    if (game.getGameStatus() == GameStatus.GOING) {
                        log.info("Hint: {}", game.getHint());
                    } else {
                        log.error("First you need to start the game");
                    }

                } else if (jCommander.getParsedCommand().equals(guessParams.command())) {
                    handleGuessLetterCommand(guessParams);
                } else if (jCommander.getParsedCommand().equals(helpParams.command())) {
                    jCommander.usage();
                } else {
                    log.error("Unknown command");
                }
            }
        }
    }

    private void handleGuessLetterCommand(GuessParams guessParams) {
        if (game.getGameStatus() == GameStatus.NOT_STARTED) {
            log.error("First you need to start the game. Type \"help\" to get more details");
        } else if (game.getGameStatus() == GameStatus.WON || game.getGameStatus() == GameStatus.LOST) {
            log.error("Game over. To start the game type"
                + " \"start (complexity)\". \"help\" to get more details");
        } else {

            game.guessLetter(guessParams.letter());
            printGameInterface();

            if (game.getGameStatus() == GameStatus.WON) {
                log.warn("Congratulations! You have won the game!");
            } else if (game.getGameStatus() == GameStatus.LOST) {
                log.warn("Game over. You have lost");
                log.warn("Hidden word: {}", game.getWord());
            }

        }
    }

    private void printGameInterface() {
        int imageIndex = (int) (
            (((float) game.getCurrentAttempt()) / game.getMaxAttempts())
            * (hangmanInterface.imagesCount() - 1)
        );
        log.info("\nImage\n{}", hangmanInterface.getCurrentImage(imageIndex));
        log.info("Word: {}", game.getCurrentWord());
        log.info("Attempts left: {}", game.getAttemptsLeft());
        log.info("Used letters: {}", game.usedCharacters());
    }
}


сделай mock system.in