import { FileStorage } from "@/managers/FileReader.js";
import { WordDisplay } from "../custom/WordDisplay/index.js";
import { ProgressBar } from "../custom/ProgressBar.js";
import { CounterContainer } from "../custom/CounterContainer.js";
import {Clue} from "@/components/custom/Clue";
import {MILLISECONDS_IN_SECOND} from "@/constants";
import {Component} from "@/components/base/Component";
import {createElement, debounce} from "@/utils/index.js";
import {Attempts} from "@/components/custom/Attempts";
import {getRandomUnopenedIndex} from "@/utils/letter-utils.js";
import localization from "@/localization/index.js";

export class Game extends Component {
  #word = '';
  #revealingInterval = null;
  #fileStorage = null;

  async onMounted() {
    await this.#initializeFileStorage();
    this.#setupEventListeners();
    this.#startNewWord();
  }

  #setupEventListeners() {
    const handleEnterKey = debounce(this.#handleEnterKey.bind(this), 100);
    document.addEventListener('keydown',handleEnterKey);
  }

  #handleAttempt() {
    this.attempts.add(1);
    this.#reloadRevealLoop();
    this.wordDisplay.openInputLetters();
  }

  #handleEnterKey = (event) => {
    if(event.key !== 'Enter') return;

    const inputValue = this.wordDisplay.inputValue;

    if(!inputValue) {
      this.wordDisplay.animateError();
      return;
    }

    this.#handleAttempt();

    if(inputValue === this.#word){
      this.#onWordMatch();
    }
  };

  async #initializeFileStorage() {
    this.#fileStorage = new FileStorage();
    await this.#fileStorage.read('./words.json');
  }

  #updateWordComponents(word){
    this.wordDisplay.update(word);
    this.clue.setWord(word);
  }

  #startNewWord(){
    this.#word = this.#fileStorage.getRandomWord(localization.language);
    this.#updateWordComponents(this.#word);
    this.#startRevealLoop();
  }

  #onWordMatch() {
    this.guessCounter.add(1);
    this.attempts.add(1);
    this.#stopRevealLoop();
    this.#startNewWord();
  }

  #stopRevealLoop() {
    if(!this.#revealingInterval) return;

    clearInterval(this.#revealingInterval);
    this.#revealingInterval = null;
    this.progressBar.interrupt();
  }

  async #startRevealLoop() {
    const seconds = 1;
    const revealInterval = MILLISECONDS_IN_SECOND * seconds;

    while (true){
      await this.#revealLetter(revealInterval);
    }
  }

  async #revealLetter(revealInterval){
    const idx = getRandomUnopenedIndex(this.wordDisplay.letters);
    if (idx === -1) {
      this.#stopRevealLoop();
      return;
    }

    const {isFinished} = await this.progressBar.start(revealInterval);
    if (isFinished) {
      await this.wordDisplay.revealLetter(idx);
      this.attempts.add(1);
    }
  }

  #reloadRevealLoop(){
    requestAnimationFrame(() => {
      this.#stopRevealLoop();
      this.#startRevealLoop();
    });
  }

  setupElement() {
    this.guessCounter = new CounterContainer(0);
    this.attempts = new Attempts(0);
    this.clue = new Clue('');
    this.wordDisplay = new WordDisplay('',() => this.#onWordMatch());
    this.progressBar = new ProgressBar();

    return createElement({
      tag: 'div',
      attributes: {className: 'page'},
      children: [
        this.clue,
        {
          tag: 'div', attributes: {className: 'info-container'},
          children: [this.guessCounter, this.attempts]
        },
        this.wordDisplay,
        this.progressBar
      ]
    });
  }
}import {createElement} from "@/utils/index.js";
import {Component} from "../base/Component.js";

export class ProgressBar extends Component{
  #currentResolve = null;
  #progressBar = null;

  start(duration){
    this.interrupt();

    return new Promise((resolve) => {
      this.#currentResolve = resolve;
      this.#progressBar.style.animationDuration = `${duration}ms`;
      this.#progressBar.classList.add('fill-animation');

      this.#progressBar.addEventListener('animationend', () => this.#resolve(true), {once: true});
    });
  }

  #resolve(isFinished){
    if(this.#currentResolve){
      this.#currentResolve({isFinished: isFinished});
      this.#currentResolve = null;
      this.reset();
    }
  }

  interrupt(){
    this.#resolve(false);
  }

  update(percentage){
    this.#progressBar.style.width = `${percentage}%`;
  }

  reset(){
    this.update(0);
    this.#progressBar.classList.remove('fill-animation');
    this.#progressBar.style.animationDuration = '';
    this.element.offsetWidth;
  }

  onMounted() {
    this.#progressBar = this.element.querySelector('.progress-bar');
  }

  setupElement(){
    return createElement({
      tag: 'div', attributes: {className: 'progress-container'}, children: [
        {tag: 'div', attributes: {className: 'progress-bar'}}
      ]
    });
  }
} исправь цикл