/**
 * @fileoverview Animações da cena do Quebra-Cabeças.
 * Cada função recebe a cena Phaser e retorna uma Promise que resolve
 * quando a animação termina — permitindo await no game.js.
 *
 * @module games.puzzle.ui.animations
 */

import sfFont from "../../../../assets/fonts/SF Slapstick Comic Shaded.ttf";
import { registerFont } from "../../../../utils/loadFont.js";

registerFont("SFSlapstick", sfFont, "truetype");

/** Estilo base para textos de feedback (cartoon + contorno). */
const ESTILO_TEXTO = {
  fontFamily: '"SFSlapstick", cursive',
  fontSize: "60px",
  color: "#ffffff",
  stroke: "#302f2f",
  strokeThickness: 12,
  shadow: { offsetX: 2, offsetY: 2, color: "#302f2f", blur: 4, fill: false },
};

// ---------------------------------------------------------------------------
// Loop de animais durante a execução
// ---------------------------------------------------------------------------

/**
 * Inicia um loop que exibe todos os animais em sequência com efeito de pulsar.
 * Corre enquanto `scene._loopAnimaisAtivo` for true.
 * Chame `pararLoopAnimais(scene)` para parar e aguardar o fim da iteração atual.
 *
 * @param {Phaser.Scene} scene     - Cena Phaser activa
 * @param {string[]}     assetKeys - Array de chaves de assets já carregados
 * @param {number}       x         - Posição X central
 * @param {number}       y         - Posição Y central
 */
/** Embaralha um array usando Fisher-Yates (cópia). */
function _shuffle(arr) {
  const a = [...arr];
  for (let i = a.length - 1; i > 0; i--) {
    const j = Math.floor(Math.random() * (i + 1));
    [a[i], a[j]] = [a[j], a[i]];
  }
  return a;
}

export function iniciarLoopAnimais(scene, assetKeys, x, y) {
  scene._loopAnimaisAtivo = true;
  scene._imagemLoopAtual = null;
  scene._loopResolveIteracao = null;

  // Promise que resolve quando o ciclo sair do while
  scene._loopParadoPromessa = new Promise((stopResolve) => {
    async function ciclo() {
      let fila = [];
      while (scene._loopAnimaisAtivo) {
        // Repõe a fila embaralhada quando estiver vazia
        if (fila.length === 0) fila = _shuffle(assetKeys);
        const key = fila.shift();

        await new Promise((resolve) => {
          // Guarda o resolver para poder cancelar externamente
          scene._loopResolveIteracao = resolve;

          const img = scene.add
            .image(x, y, key)
            .setAlpha(0)
            .setScale(0)
            .setDepth(49)
            .setTintFill(0xffffff);
          scene._imagemLoopAtual = img;

          if (!scene._loopAnimaisAtivo) { img.destroy(); resolve(); return; }

          // Surgir
          scene.tweens.add({
            targets: img, alpha: 1, scale: 1.0,
            duration: 350, ease: "Back.easeOut",
            onComplete: () => {
              if (!scene._loopAnimaisAtivo) { img.destroy(); resolve(); return; }

              // Aguardar brevemente e sumir
              scene.time.delayedCall(300, () => {
                if (!scene._loopAnimaisAtivo) { img.destroy(); resolve(); return; }

                scene.tweens.add({
                  targets: img, alpha: 0, scale: 0.8,
                  duration: 250, ease: "Sine.easeIn",
                  onComplete: () => {
                    img.destroy();
                    scene._imagemLoopAtual = null;
                    resolve();
                  },
                });
              });
            },
          });
        });
      }
      stopResolve();
    }

    ciclo();
  });
}

/**
 * Para o loop de animais imediatamente (destrói a imagem actual)
 * e retorna uma Promise que resolve quando o ciclo encerrou por completo.
 *
 * @param {Phaser.Scene} scene
 * @returns {Promise<void>}
 */
export function pararLoopAnimais(scene) {
  if (!scene._loopAnimaisAtivo) return scene._loopParadoPromessa ?? Promise.resolve();

  scene._loopAnimaisAtivo = false;

  // Destrói imagem visível agora
  if (scene._imagemLoopAtual && !scene._imagemLoopAtual.destroyed) {
    scene.tweens.killTweensOf(scene._imagemLoopAtual);
    scene._imagemLoopAtual.destroy();
    scene._imagemLoopAtual = null;
  }

  // Desbloqueia o await interno do ciclo
  if (scene._loopResolveIteracao) {
    scene._loopResolveIteracao();
    scene._loopResolveIteracao = null;
  }

  return scene._loopParadoPromessa ?? Promise.resolve();
}

// ---------------------------------------------------------------------------
// Animações de resultado
// ---------------------------------------------------------------------------

/**
 * Exibe a imagem do animal com efeito de "Pulsar":
 *  1. Surge do centro (scale 0 → 1.15) com fade-in rápido
 *  2. Recua levemente (1.15 → 0.95)
 *  3. Assenta no tamanho final (0.95 → 1.0)
 * Resolve a Promise quando a sequência completa (~700ms).
 *
 * @param {Phaser.Scene} scene - Cena Phaser activa
 * @param {string} assetKey   - Chave do asset já carregado
 * @param {number} x          - Posição X central
 * @param {number} y          - Posição Y central
 * @returns {Promise<Phaser.GameObjects.Image>}
 */
export function pulsarImagem(scene, assetKey, x, y) {
  return new Promise((resolve) => {
    const img = scene.add
      .image(x, y, assetKey)
      .setAlpha(0)
      .setScale(0)
      .setDepth(50);

    scene.tweens.add({
      targets: img, alpha: 1, scale: 1.15,
      duration: 400, ease: "Back.easeOut",
      onComplete: () => {
        scene.tweens.add({
          targets: img, scale: 0.95,
          duration: 150, ease: "Sine.easeIn",
          onComplete: () => {
            scene.tweens.add({
              targets: img, scale: 1.0,
              duration: 150, ease: "Sine.easeOut",
              onComplete: () => resolve(img),
            });
          },
        });
      },
    });
  });
}

/**
 * Exibe a silhueta branca do animal (tintFill) com animação de tremor.
 * Resolve a Promise quando a sequência completa (~900ms).
 *
 * @param {Phaser.Scene} scene - Cena Phaser activa
 * @param {string} assetKey   - Chave do asset já carregado
 * @param {number} x          - Posição X central
 * @param {number} y          - Posição Y central
 * @returns {Promise<Phaser.GameObjects.Image>}
 */
export function silhuetaTremendo(scene, assetKey, x, y) {
  return new Promise((resolve) => {
    const img = scene.add
      .image(x, y, assetKey)
      .setAlpha(0)
      .setScale(0)
      .setDepth(50)
      .setTintFill(0xffffff);

    scene.tweens.add({
      targets: img, alpha: 1, scale: 1.0,
      duration: 300, ease: "Back.easeOut",
      onComplete: () => {
        scene.tweens.add({
          targets: img,
          x: { from: x - 12, to: x + 12 },
          duration: 60, ease: "Sine.easeInOut",
          yoyo: true, repeat: 5,
          onComplete: () => { img.setX(x); resolve(img); },
        });
      },
    });
  });
}

// ---------------------------------------------------------------------------
// Feedback de bloco (texto temporário)
// ---------------------------------------------------------------------------

/**
 * Exibe texto de feedback com fonte cartoon + contorno.
 * O texto some automaticamente (fade-out) após 700ms — total ~1000ms.
 * Substitui qualquer texto de feedback anterior.
 *
 * @param {Phaser.Scene} scene - Cena Phaser activa
 * @param {string}       texto - Conteúdo a exibir
 * @param {number}       x     - Posição X (centralizado)
 * @param {number}       y     - Posição Y
 * @returns {Promise<void>}
 */
export function mostrarFeedback(scene, texto, x, y) {
  return new Promise((resolve) => {
    if (scene._textoFeedback) {
      scene.tweens.killTweensOf(scene._textoFeedback);
      scene._textoFeedback.destroy();
      scene._textoFeedback = null;
    }

    // Garante que a fonte está carregada antes de renderizar o texto
    const fontLoad = document.fonts
      ? document.fonts.load(`normal normal 60px 'SFSlapstick'`).catch(() => {})
      : Promise.resolve();

    fontLoad.then(() => {
    const txt = scene.add
      .text(x, y, texto, ESTILO_TEXTO)
      .setOrigin(0.5, 0)
      .setDepth(100)
      .setAlpha(1);

    scene._textoFeedback = txt;

    scene.time.delayedCall(700, () => {
      scene.tweens.add({
        targets: txt, alpha: 0,
        duration: 300, ease: "Linear",
        onComplete: () => {
          txt.destroy();
          if (scene._textoFeedback === txt) scene._textoFeedback = null;
          resolve();
        },
      });
    });
    }); // fontLoad.then
  });
}
