/**
 * @fileoverview Utility module for animations.js
 * 
 * @module games.cripto.ui.animations
 */

import { ConstantesAnimacao } from "./constants.js";

export function iniciarAnimacaoMatrix(scene, colunas) {
  const caracteres = ConstantesAnimacao.MATRIX.CARACTERES_HEX;
  const numCaracteres = ConstantesAnimacao.MATRIX.CARACTERES_POR_COLUNA;
  const intervalo = ConstantesAnimacao.MATRIX.INTERVALO_ATUALIZACAO;

  const gerarCaractereAleatorio = () => {
    return caracteres[Math.floor(Math.random() * caracteres.length)];
  };

  const atualizarColuna = (coluna) => {
    if (!scene.isRunning) return;

    const textoColuna = [];
    for (let i = 0; i < numCaracteres; i++) {
      textoColuna.push(gerarCaractereAleatorio());
    }
    coluna.setText(textoColuna.join("\n"));
  };

  colunas.forEach((coluna) => atualizarColuna(coluna));

  const timer = scene.time.addEvent({
    delay: intervalo,
    callback: () => {
      if (scene.isRunning) {
        colunas.forEach((coluna) => atualizarColuna(coluna));
      }
    },
    loop: true,
  });

  return timer;
}

export function pararAnimacaoMatrix(colunas, timer) {
  if (timer) {
    timer.remove();
  }
  colunas.forEach((coluna) => coluna.setText(""));
}

/**
 * Anima a entrada de texto caractere por caractere com cursor piscando
 * @param {Phaser.Scene} scene - A cena do Phaser
 * @param {Phaser.GameObjects.Text} textoEntrada - O objeto de texto da entrada
 * @param {string} textoFinal - O texto final a ser exibido
 * @returns {Promise} Promise que resolve quando a animação termina
 */
export function animarEntradaCaractere(scene, textoEntrada, textoFinal) {
  return new Promise((resolve) => {
    const cursor = ConstantesAnimacao.CURSOR;
    const velocidade = ConstantesAnimacao.ENTRADA.VELOCIDADE_DIGITACAO;
    const intervaloPiscar = ConstantesAnimacao.ENTRADA.INTERVALO_PISCAR_CURSOR;

    let posicaoAtual = 0;
    let cursorVisivel = true;
    let timerPiscar = null;

    const piscarCursor = () => {
      if (!scene.isRunning) return;

      cursorVisivel = !cursorVisivel;
      const textoAtual = textoFinal.substring(0, posicaoAtual);
      textoEntrada.setText(textoAtual + (cursorVisivel ? cursor : ""));

      timerPiscar = scene.time.delayedCall(intervaloPiscar, piscarCursor);
    };

    const digitarProximoCaractere = () => {
      if (!scene.isRunning) {
        if (timerPiscar) timerPiscar.remove();
        textoEntrada.setText(textoFinal);
        resolve(textoFinal);
        return;
      }

      if (posicaoAtual >= textoFinal.length) {
        if (timerPiscar) timerPiscar.remove();
        textoEntrada.setText(textoFinal);
        resolve(textoFinal);
        return;
      }

      posicaoAtual++;
      const textoAtual = textoFinal.substring(0, posicaoAtual);
      textoEntrada.setText(textoAtual + cursor);
      cursorVisivel = true;

      scene.time.delayedCall(velocidade, digitarProximoCaractere);
    };

    textoEntrada.setText(cursor);
    cursorVisivel = true;

    timerPiscar = scene.time.delayedCall(intervaloPiscar, piscarCursor);

    scene.time.delayedCall(velocidade, digitarProximoCaractere);
  });
}

/**
 * Anima a saída de texto completa com embaralhamento
 * @param {Phaser.Scene} scene - A cena do Phaser
 * @param {Phaser.GameObjects.Text} textoSaida - O objeto de texto da saída
 * @param {string} textoFinal - O texto final a ser exibido
 * @returns {Promise} Promise que resolve quando a animação termina
 */
export function animarSaidaCaractere(scene, textoSaida, textoFinal) {
  return new Promise((resolve) => {
    const caracteres = ConstantesAnimacao.CARACTERES_EMBARALHAMENTO;
    const ultimaPosicao = textoFinal.length;
    let posicaoAtual = 0;
    const duracaoEmbaralhamento =
      ConstantesAnimacao.SAIDA.DURACAO_EMBARALHAMENTO;
    const repeticoesEmbaralhamento =
      ConstantesAnimacao.SAIDA.REPETICOES_EMBARALHAMENTO;

    const proximoCaractere = () => {
      if (!scene.isRunning) {
        textoSaida.setText(textoFinal);
        resolve();
        return;
      }

      if (posicaoAtual >= ultimaPosicao) {
        resolve();
        return;
      }

      let repeticao = 0;
      const embaralhar = () => {
        if (!scene.isRunning) {
          textoSaida.setText(textoFinal);
          resolve();
          return;
        }

        if (repeticao < repeticoesEmbaralhamento) {
          const charAleatorio =
            caracteres[Math.floor(Math.random() * caracteres.length)];
          const textoAtual =
            textoFinal.substring(0, posicaoAtual) + charAleatorio;
          textoSaida.setText(textoAtual);

          repeticao++;
          scene.time.delayedCall(duracaoEmbaralhamento, embaralhar);
        } else {
          posicaoAtual++;
          textoSaida.setText(textoFinal.substring(0, posicaoAtual));
          scene.time.delayedCall(
            ConstantesAnimacao.SAIDA.PAUSA_ENTRE_CARACTERES,
            proximoCaractere,
          );
        }
      };

      embaralhar();
    };

    proximoCaractere();
  });
}

/**
 * Anima apenas um novo caractere adicionado à saída (para concatenação)
 * @param {Phaser.Scene} scene - A cena do Phaser
 * @param {Phaser.GameObjects.Text} textoSaida - O objeto de texto da saída
 * @param {string} textoAnterior - O texto antes da concatenação
 * @param {string} textoFinal - O texto após a concatenação
 * @returns {Promise} Promise que resolve quando a animação termina
 */
export function animarNovoCaractereSaida(
  scene,
  textoSaida,
  textoAnterior,
  textoFinal,
) {
  return new Promise((resolve) => {
    const caracteres = ConstantesAnimacao.CARACTERES_EMBARALHAMENTO;
    const duracaoEmbaralhamento =
      ConstantesAnimacao.CONCATENACAO.DURACAO_EMBARALHAMENTO;
    const repeticoesEmbaralhamento =
      ConstantesAnimacao.CONCATENACAO.REPETICOES_EMBARALHAMENTO;
    let repeticao = 0;

    const embaralhar = () => {
      if (!scene.isRunning) {
        textoSaida.setText(textoFinal);
        resolve();
        return;
      }

      if (repeticao < repeticoesEmbaralhamento) {
        const charAleatorio =
          caracteres[Math.floor(Math.random() * caracteres.length)];
        textoSaida.setText(textoAnterior + charAleatorio);
        repeticao++;
        scene.time.delayedCall(duracaoEmbaralhamento, embaralhar);
      } else {
        textoSaida.setText(textoFinal);
        resolve();
      }
    };

    embaralhar();
  });
}
