/*
  game_manager.js
  fffadedev
  08/23/25

  Manages the entire game state for a standard singleplayer game
 */

const GameState =
{
  Menu: 0,
  Playing: 1,
  End: 2
}

const MAX_ATTEMPTS = 6;

const Difficulty =
{
  Easy: 'Easy',
  Normal: 'Normal',
  Hard: 'Hard'
}

const DifficultyToGuessTime =
{
  [Difficulty.Easy]: 5 * 60,
  [Difficulty.Normal]: 3 * 60,
  [Difficulty.Hard]: 1 * 60
}

const DifficultyToPoints =
{
  [Difficulty.Easy]: 10,
  [Difficulty.Normal]: 15,
  [Difficulty.Hard]: 30
}

const EndGameMessages =
[
  "Better luck next time.",
  "Give it another shot.",
  "Smarty pants.",
  "How about one more?",
  "Good job!",
  "Excellent work!",
  "You killed it.",
  "Impressive!"
];


class Game
{
  constructor() {
    this.state = GameState.Menu;

    this.guesses = new Guesses();
    this.header = new Header();
    this.sidebar = new Sidebar();

    this.highscore = localStorage.getItem('highscore') || 0; // Fetch score from cache
    this.sidebar.updateHighscore(this.highscore);

    this.difficultySelect = new DifficultySelect();
    this.difficultySelect.onChooseDifficulty = ((difficulty) => {
      this.difficulty = difficulty;
      localStorage.setItem('difficulty', this.difficulty) // Cache difficulty upon select
      this.guessTime = DifficultyToGuessTime[this.difficulty];
      this.timer.resetTime = this.guessTime;
    }).bind(this);


    this.difficulty = localStorage.getItem('difficulty') || Difficulty.Easy; // Fetch cached difficulty, default is EASY
    this.difficultySelect.el.value = this.difficulty;

    this.guessTime = DifficultyToGuessTime[this.difficulty];

    console.log("Cached difficulty: " + this.difficulty);

    this.popup = new Popup();
    this.popup.buttons.onReplayClick = () => {
      this.startNewGame();
      this.popup.hide();
    };

    this.input = new Input(this);

    this.timer = new Timer(this.guessTime);
    this.timer.onChange = this.sidebar.updateTimer.bind(this.sidebar);
    this.timer.onEnd = this.endGame.bind(this);

    this.startNewGame();

    console.log("New game instantiated.");
  }

  // Begins a new game
  startNewGame()
  {
    this.state = GameState.Playing;

    this.input.reset();
    this.input.guessInput.show();
    this.input.isInputActive = true;
    this.difficultySelect.disable();
    this.sidebar.hidePlayButton();
    this.sidebar.hideClearHighscoreButton();

    this.roundsCompleted = 0;
    this.points = 0;

    // Start a new round / new word
    this.nextWord();
  }

  // Ends the current game once player is out
  endGame()
  {
    this.state = GameState.End;
    this.input.guessInput.hide();
    this.input.isInputActive = false;
    this.timer.pause();
    this.difficultySelect.enable();
    this.sidebar.showPlayButton(this.startNewGame.bind(this));
    this.sidebar.showClearHighscoreButton(this.saveNewHighscore.bind(this, 0));

    // New top score saving method
    let isNewTopScore = this.points > this.highscore;
    if(isNewTopScore) {
      this.saveNewHighscore(this.points);
    }

    // Stats displayed
    // If new highscore, display such as text
    this.header.showRealWord(this.wordle);
    this.popup.show(`${isNewTopScore ? "New highscore!" : EndGameMessages[Math.floor(Math.random() * EndGameMessages.length)]} <br><br><b>Words Solved:&ensp;</b>${this.roundsCompleted}<br><br><b>Your Score:&ensp;</b>${this.points}`, true);
  }

  // Picks a new word and resets attempts
  nextWord()
  {
    this.header.updateRoundNumber(this.roundsCompleted + 1);
    this.header.hideRealWord();

    this.sidebar.updateScore(this.points);

    this.attempts = 0;
    this.guesses.reset();
    this.timer.reset();
    this.timer.start();
    this.pickNewWord();
  }

  // Checks the inputted guess to determine whether success or fail
  checkGuess(input)
  {
    // WRONG
    if(input !== this.wordle) {
      this.attempts++;
      if(this.attempts >= MAX_ATTEMPTS) {
        console.log("Max attempts reached. Wordle failed.");
        // GAME OVER
        this.endGame();
      }
      return;
    }
    // RIGHT

    // Immediately pause timer
    this.timer.pause();

    // Award points and move to next word
    this.points += DifficultyToPoints[this.difficulty];
    this.sidebar.updateScore(this.points);
    this.roundsCompleted++;

    console.log("Wordle guessed. Points have been awarded.");

    this.popup.showTimed('Good job!', false, 2000).then(() => {
      this.nextWord();
    });
  }

  // Sets a new random word for this round
  pickNewWord() {
    this.wordle = Wordles[Math.floor(Math.random() * Wordles.length)].toUpperCase();
    console.log("New wordle: ", this.wordle);
  }

  // Validates the given input and if it can be submitted as a valid word
  verifyInput(input) {
    if(!ValidWords.includes(input.toLowerCase())) {
      console.log("Invalid input: " + input);
      // Send a short popup to show it is not a good word for feedback
      this.popup.showTimed("Not a real word!", false, 1000);
      return false;
    }
    return true;
  }

  // Saves a new highscore amount of points to cache and reupdates display
  saveNewHighscore(points) {
    localStorage.setItem('highscore', points);
    this.highscore = points;
    this.sidebar.updateHighscore(this.highscore);

    console.log("New highscore saved: " + this.highscore);
  }
}
