/**
 * @fileoverview Utility module for game.js
 * 
 * @module games.turtle.game
 */

import Phaser from "phaser";
import { BaseGameScene } from "../../../shared/BaseGameScene.js";
import { GameInterpreter } from "../../../interpreters/GameInterpreter.js";
import { setupTurtleAPI } from "./hooks/interpreterSetup.js";
import { validateSolution } from "./validation/validators.js";
import turtleImg1 from "./assets/1.png";
import turtleImg2 from "./assets/2.png";
import win from "./assets/win.mp3";
import fail from "./assets/fail.mp3";

const ASSETS = {
  IMG: { TURTLE1: "turtle1", TURTLE2: "turtle2" },
  AUDIO: { WIN: "win", FAIL: "fail" },
};

const CONSTANTES = {
  LARGURA: 640,
  ALTURA: 480,
};

class TurtleScene extends BaseGameScene {
  constructor() {
    super("TurtleScene");

    this.turtleState = null;
    this.turtleSprite = null;
    this.solutionGraphics = null;
    this.playerGraphics = null;
    this.validationGraphics = null;
    this.activeGraphics = null;
    this.backgroundRect = null;
    this.playerColors = [];
    this.solutionColors = [];
    this.executionSpeed = 50;
    this.sliderWidth = 0;
    this.sliderFill = null;
    this.sliderHandle = null;
    this.speedText = null;
    this.playerRT = null;
    this.validationRT = null;
    this.resultadoJogada = "em_andamento";
  }

  preload() {
    this.preloadGlobalAssets();
    this.load.image(ASSETS.IMG.TURTLE1, turtleImg1);
    this.load.image(ASSETS.IMG.TURTLE2, turtleImg2);
    this.load.audio(ASSETS.AUDIO.WIN, win);
    this.load.audio(ASSETS.AUDIO.FAIL, fail);
  }

  /**
   * Preload de recursos (imagens e áudios) usados pela cena `TurtleScene`.
   * @returns {void}
   */

  init(data) {
    super.init(data);
    this.executionSpeed = 50;
    this.turtleState = {
      x: 0,
      y: 0,
      angle: 0,
      penDown: true,
      penColour: 0xffffff,
    };
    this.playerColors = [];
    this.solutionColors = [];
    this.resultadoJogada = "em_andamento";
  }

  /**
   * Inicializa o estado da tartaruga e configurações padrão da cena.
   * @param {Object} data - Dados da cena (opcional)
   * @returns {void}
   */

  setExecutionSpeed(speed) {
    this.executionSpeed = Math.max(1, Math.min(100, speed));

    if (typeof this.updateSpeedUI === "function") {
      this.updateSpeedUI();
    }
  }

  /**
   * Ajusta a velocidade de execução (percentual) e atualiza UI.
   * @param {number} speed - Valor entre 1 e 100 representando a velocidade
   * @returns {void}
   */

  updateSpeedUI() {
    if (this.speedText) {
      this.speedText.setText(`Velocidade: ${this.executionSpeed}%`);
    }
    if (this.sliderFill) {
      this.sliderFill.setSize(
        (this.executionSpeed / 100) * this.sliderWidth,
        12,
      );
    }
    if (this.sliderHandle) {
      this.sliderHandle.x =
        (this.executionSpeed / 100 - 0.5) * this.sliderWidth;
    }
  }

  createSpeedControl() {
    const gameWidth = this.game.config.width;
    const gameHeight = this.game.config.height;

    this.sliderWidth = Math.min(gameWidth - 40, 300);
    const controlHeight = 50;
    const centerX = gameWidth / 2;
    const bottomY = gameHeight - 35;

    const controlsContainer = this.add.container(centerX, bottomY);

    const bg = this.add.rectangle(
      0,
      0,
      this.sliderWidth + 80,
      controlHeight,
      0x000000,
      0.85,
    );
    bg.setOrigin(0.5, 0.5);
    controlsContainer.add(bg);

    const sliderBg = this.add.rectangle(0, 8, this.sliderWidth, 12, 0x444444);
    controlsContainer.add(sliderBg);

    this.sliderFill = this.add.rectangle(
      -this.sliderWidth / 2,
      8,
      (this.executionSpeed / 100) * this.sliderWidth,
      28,
      0x00ff88,
    );
    this.sliderFill.setOrigin(0, 0.5);
    controlsContainer.add(this.sliderFill);

    this.sliderHandle = this.add.circle(
      (this.executionSpeed / 100 - 0.5) * this.sliderWidth,
      8,
      16,
      0xffffff,
    );
    this.sliderHandle.setInteractive({ useHandCursor: true });
    this.sliderHandle.setStrokeStyle(2, 0x333333);
    controlsContainer.add(this.sliderHandle);

    this.speedText = this.add.text(
      0,
      -12,
      `Velocidade: ${this.executionSpeed}%`,
      {
        fontSize: "14px",
        fill: "#ffffff",
        fontFamily: "Arial",
      },
    );
    this.speedText.setOrigin(0.5, 0.5);
    controlsContainer.add(this.speedText);

    let isDragging = false;

    this.sliderHandle.on("pointerdown", () => {
      isDragging = true;
    });

    this.input.on("pointermove", (pointer) => {
      if (isDragging) {
        const localX = pointer.x - centerX;
        const clampedX = Math.max(
          -this.sliderWidth / 2,
          Math.min(this.sliderWidth / 2, localX),
        );
        const newSpeed = Math.round(
          ((clampedX + this.sliderWidth / 2) / this.sliderWidth) * 100,
        );
        this.setExecutionSpeed(newSpeed);
      }
    });

    this.input.on("pointerup", () => {
      isDragging = false;
    });

    sliderBg.setInteractive();
    sliderBg.on("pointerdown", (pointer) => {
      const localX = pointer.x - centerX;
      const clampedX = Math.max(
        -this.sliderWidth / 2,
        Math.min(this.sliderWidth / 2, localX),
      );
      const newSpeed = Math.round(
        ((clampedX + this.sliderWidth / 2) / this.sliderWidth) * 100,
      );
      this.setExecutionSpeed(newSpeed);
    });

    controlsContainer.setDepth(9999);
  }

  /**
   * Cria controles de UI para ajustar a velocidade de execução.
   * @returns {void}
   */

  calcDuration() {
    return 500 + ((1 - 500) / (100 - 1)) * (this.executionSpeed - 1);
  }

  /**
   * Calcula a duração de animações baseado na velocidade de execução.
   * @returns {number} Duração em milissegundos
   */

  resetTurtle() {
    this.turtleState.x = this.game.config.width / 2;
    this.turtleState.y = this.game.config.height / 2;
    this.turtleState.angle = 0;
    this.turtleState.penDown = true;
    this.turtleState.penColour = 0xffffff;

    if (this.turtleSprite) {
      this.turtleSprite.setPosition(this.turtleState.x, this.turtleState.y);
      this.turtleSprite.setAngle(0);
      this.turtleSprite.stop();
      this.turtleSprite.setTexture(ASSETS.IMG.TURTLE1);
    }
  }

  /**
   * Restaura a tartaruga para a posição/estado inicial do canvas.
   * @returns {void}
   */

  pintarFundo(color) {
    let colorValue;

    if (typeof color === "string") {
      if (color.startsWith("#")) {
        colorValue = parseInt(color.substring(1), 16);
      } else {
        const colorMap = {
          vermelho: 0xff0000,
          azul: 0x0000ff,
          verde: 0x00ff00,
          amarelo: 0xffff00,
          branco: 0xffffff,
          preto: 0x000000,
        };
        colorValue = colorMap[color.toLowerCase()] || 0x000000;
      }
    } else {
      colorValue = color;
    }

    if (this.backgroundRect) {
      this.backgroundRect.destroy();
    }

    this.backgroundRect = this.add.rectangle(
      this.game.config.width / 2,
      this.game.config.height / 2,
      this.game.config.width,
      this.game.config.height,
      colorValue,
    );
    this.backgroundRect.setDepth(-1000);
  }

  /**
   * Pinta o fundo da cena com a cor especificada.
   * Aceita valores numéricos ou nomes/hex strings.
   * @param {string|number} color - Cor a ser aplicada
   * @returns {void}
   */

  addColorToActiveGraphics() {
    const colorArray =
      this.activeGraphics === this.playerGraphics
        ? this.playerColors
        : this.solutionColors;

    if (!colorArray.includes(this.turtleState.penColour)) {
      colorArray.push(this.turtleState.penColour);
    }
  }

  /**
   * Adiciona a cor atual da caneta à lista de cores usadas no gráfico ativo.
   * @returns {void}
   */

  _moveInstant(distance) {
    const lastX = this.turtleState.x;
    const lastY = this.turtleState.y;
    const angleRad = Phaser.Math.DegToRad(this.turtleState.angle);

    this.turtleState.x += Math.cos(angleRad) * distance;
    this.turtleState.y -= Math.sin(angleRad) * distance;

    if (this.turtleState.penDown && this.activeGraphics) {
      this.activeGraphics.lineStyle(4, this.turtleState.penColour, 1);
      this.activeGraphics.lineBetween(
        lastX,
        lastY,
        this.turtleState.x,
        this.turtleState.y,
      );
      this.addColorToActiveGraphics();
    }
  }

  /**
   * Move a tartaruga instantaneamente sem animação (utilitário interno).
   * @param {number} distance - Distância a percorrer
   * @returns {void}
   */

  _turnInstant(angle) {
    this.turtleState.angle += angle;
    this.turtleState.angle = this.turtleState.angle % 360;
    if (this.turtleState.angle < 0) {
      this.turtleState.angle += 360;
    }
  }

  /**
   * Rotaciona a tartaruga instantaneamente (utilitário interno).
   * @param {number} angle - Ângulo em graus a ser somado
   * @returns {void}
   */

  highlightBlock(id) {
    if (this.workspace) this.workspace.highlightBlock(id);
    this.highlightPause = true;
  }

  /**
   * Destaca um bloco do workspace e pausa o destaque automático.
   * @param {string} id - Id do bloco a destacar
   * @returns {void}
   */

  move(distance) {
    this.historico.push({ tipo: "move", distancia: distance });

    return new Promise((resolve) => {
      const duration = this.calcDuration();
      const startX = this.turtleState.x;
      const startY = this.turtleState.y;
      const angleRad = Phaser.Math.DegToRad(this.turtleState.angle);
      const targetX = this.turtleState.x + Math.cos(angleRad) * distance;
      const targetY = this.turtleState.y - Math.sin(angleRad) * distance;

      this.turtleState.x = targetX;
      this.turtleState.y = targetY;

      this.turtleSprite.play("turtle_walk");

      this.tweens.add({
        targets: this.turtleSprite,
        x: targetX,
        y: targetY,
        duration: duration,
        ease: "Linear",
        onComplete: () => {
          this.turtleSprite.stop();
          this.turtleSprite.setTexture(ASSETS.IMG.TURTLE1);

          if (this.turtleState.penDown && this.activeGraphics) {
            this.activeGraphics.lineStyle(4, this.turtleState.penColour, 1);
            this.activeGraphics.lineBetween(
              startX,
              startY,
              this.turtleState.x,
              this.turtleState.y,
            );
            this.addColorToActiveGraphics();
          }

          resolve();
        },
      });
    });
  }

  /**
   * Move a tartaruga com animação e desenha a linha se a caneta estiver para baixo.
   * Retorna uma Promise que resolve quando a animação termina.
   * @param {number} distance - Distância a percorrer
   * @returns {Promise<void>}
   */

  turn(angle) {
    this.historico.push({ tipo: "turn", angulo: angle });

    return new Promise((resolve) => {
      const duration = this.calcDuration();
      this._turnInstant(angle);

      const currentSpriteAngle = this.turtleSprite.angle;
      const targetSpriteAngle = -this.turtleState.angle;

      let angleDiff = targetSpriteAngle - currentSpriteAngle;

      while (angleDiff > 180) angleDiff -= 360;
      while (angleDiff < -180) angleDiff += 360;

      const finalAngle = currentSpriteAngle + angleDiff;

      this.tweens.add({
        targets: this.turtleSprite,
        angle: finalAngle,
        duration: duration,
        ease: "Linear",
        onComplete: () => {
          resolve();
        },
      });
    });
  }

  /**
   * Rotaciona a tartaruga com animação e ajusta o sprite.
   * Retorna uma Promise que resolve quando a rotação termina.
   * @param {number} angle - Ângulo em graus
   * @returns {Promise<void>}
   */

  penDown(isDown) {
    this.historico.push({ tipo: "penDown", valor: isDown });
    this.turtleState.penDown = isDown;
  }

  /**
   * Seta o estado da caneta (para desenhar ou não).
   * @param {boolean} isDown - true para caneta para baixo
   * @returns {void}
   */

  penColour(color) {
    this.historico.push({ tipo: "penColour", cor: color });

    if (typeof color === "string") {
      if (color.startsWith("#")) {
        this.turtleState.penColour = parseInt(color.substring(1), 16);
      } else {
        const colorMap = {
          vermelho: 0xff0000,
          azul: 0x0000ff,
          verde: 0x00ff00,
          amarelo: 0xffff00,
          branco: 0xffffff,
          preto: 0x000000,
        };
        this.turtleState.penColour = colorMap[color.toLowerCase()] || 0xffffff;
      }
    } else {
      this.turtleState.penColour = color;
    }

    this.addColorToActiveGraphics();
  }

  /**
   * Ajusta a cor da caneta; aceita nome, hex string ou valor numérico.
   * @param {string|number} color - Cor a ser aplicada
   * @returns {void}
   */

  extractPointsFromGraphics(graphics) {
    const points = [];
    let i = 0;

    while (i < graphics.commandBuffer.length) {
      const cmd = graphics.commandBuffer[i];
      if (
        cmd === 6 &&
        i + 11 < graphics.commandBuffer.length &&
        graphics.commandBuffer[i + 1] === 4 &&
        graphics.commandBuffer[i + 5] === 5 &&
        graphics.commandBuffer[i + 8] === 4 &&
        graphics.commandBuffer[i + 11] === 9
      ) {
        const x1 = graphics.commandBuffer[i + 6];
        const y1 = graphics.commandBuffer[i + 7];
        const x2 = graphics.commandBuffer[i + 9];
        const y2 = graphics.commandBuffer[i + 10];

        points.push({ x: x1, y: y1 });
        points.push({ x: x2, y: y2 });
        i += 12;
      } else {
        i++;
      }
    }

    return points;
  }

  /**
   * Extrai pontos relevantes do buffer de comandos de um objeto Graphics.
   * Usado para gerar assinaturas de desenho para comparação.
   * @param {Phaser.GameObjects.Graphics} graphics
   * @returns {Array<{x:number,y:number}>}
   */

  getDrawingSignature(graphics) {
    if (!graphics.commandBuffer || graphics.commandBuffer.length === 0) {
      return null;
    }

    const points = this.extractPointsFromGraphics(graphics);
    if (points.length === 0) {
      return null;
    }

    let sumX = 0,
      sumY = 0;
    let minX = Infinity,
      minY = Infinity;
    let maxX = -Infinity,
      maxY = -Infinity;

    points.forEach((p) => {
      sumX += p.x;
      sumY += p.y;
      minX = Math.min(minX, p.x);
      minY = Math.min(minY, p.y);
      maxX = Math.max(maxX, p.x);
      maxY = Math.max(maxY, p.y);
    });

    const pointCount = points.length;
    const centroid = { x: sumX / pointCount, y: sumY / pointCount };
    const normalizedCentroid = {
      x: centroid.x - minX,
      y: centroid.y - minY,
    };

    return {
      bounds: { x: minX, y: minY, width: maxX - minX, height: maxY - minY },
      centroid: normalizedCentroid,
    };
  }

  /**
   * Calcula uma assinatura geométrica (bounds e centróide) do desenho.
   * Retorna `null` se não houver comandos suficientes.
   * @param {Phaser.GameObjects.Graphics} graphics
   * @returns {Object|null}
   */

  compareColors(playerColors, solutionColors) {
    if (playerColors.length !== solutionColors.length) return false;

    const sortedPlayer = [...playerColors].sort();
    const sortedSolution = [...solutionColors].sort();

    return sortedSolution.every(
      (color, index) => sortedPlayer[index] === color,
    );
  }

  /**
   * Compara paletas de cores usadas pelo jogador e pela solução.
   * @param {Array<number>} playerColors - Cores usadas pelo jogador
   * @param {Array<number>} solutionColors - Cores esperadas na solução
   * @returns {boolean} true se as paletas coincidirem
   */

  /**
   * Calcula uma assinatura topológica do desenho (curvatura, pontoCount, sentido).
   * Retorna null ou objeto com propriedades para comparação.
   * @param {Phaser.GameObjects.Graphics} graphics
   * @returns {Object|null}
   */
  getTopologicalSignature(graphics) {
    if (!graphics.commandBuffer || graphics.commandBuffer.length === 0) {
      return null;
    }

    const points = this.extractPointsFromGraphics(graphics);

    if (points.length < 3) {
      return { curvatureSum: 0, pointCount: points.length };
    }

    let curvatureSum = 0;
    for (let j = 1; j < points.length - 1; j++) {
      const p0 = points[j - 1];
      const p1 = points[j];
      const p2 = points[j + 1];

      const v1 = { x: p1.x - p0.x, y: p1.y - p0.y };
      const v2 = { x: p2.x - p1.x, y: p2.y - p1.y };

      const crossProduct = v1.x * v2.y - v1.y * v2.x;
      curvatureSum += crossProduct;
    }

    return {
      curvatureSum: curvatureSum,
      pointCount: points.length,
      isClockwise: curvatureSum < 0,
      absoluteCurvature: Math.abs(curvatureSum),
    };
  }

  /**
   * Compara o desenho do jogador com o desenho de referência.
   * Leva em conta cores, dimensões, posição e topologia.
   * @returns {boolean} true se os desenhos forem considerados equivalentes
   */
  compareDrawings() {
    if (!this.compareColors(this.playerColors, this.solutionColors)) {
      return false;
    }

    const playerSig = this.getDrawingSignature(this.playerGraphics);
    const solutionSig = this.getDrawingSignature(this.validationGraphics);

    if (!playerSig || !solutionSig) {
      return false;
    }

    const pb = playerSig.bounds;
    const sb = solutionSig.bounds;

    const dimensionTolerance = Math.max(sb.width, sb.height, 1) * 0.05;
    if (
      Math.abs(pb.width - sb.width) > dimensionTolerance ||
      Math.abs(pb.height - sb.height) > dimensionTolerance
    ) {
      return false;
    }

    const posX_diff = Math.abs(pb.x - sb.x);
    const posY_diff = Math.abs(pb.y - sb.y);
    if (posX_diff > 1.5 || posY_diff > 1.5) {
      return false;
    }

    const centroidTolerance = 1.5;
    const centroidDeltaX = Math.abs(
      playerSig.centroid.x - solutionSig.centroid.x,
    );
    const centroidDeltaY = Math.abs(
      playerSig.centroid.y - solutionSig.centroid.y,
    );

    if (
      centroidDeltaX > centroidTolerance ||
      centroidDeltaY > centroidTolerance
    ) {
      return false;
    }

    const playerTopo = this.getTopologicalSignature(this.playerGraphics);
    const solutionTopo = this.getTopologicalSignature(this.validationGraphics);

    if (!playerTopo || !solutionTopo) {
      return false;
    }

    if (
      playerTopo.isClockwise !== solutionTopo.isClockwise &&
      Math.abs(playerTopo.absoluteCurvature) > 10
    ) {
      return false;
    }

    return true;
  }

  /**
   * Compara o desenho do jogador com o desenho de referência.
   * Leva em conta cores, dimensões, posição e topologia.
   * @returns {boolean} true se os desenhos forem considerados equivalentes
   */

  /**
   * Desenha a solução esperada usando o código presente em `configFase.solutionCode`.
   * Não lança erros para não interromper a cena se a solução estiver inválida.
   * @returns {void}
   */
  drawSolution() {
    const configFase = this.registry.get("configFase");
    if (!configFase || !configFase.solutionCode) {
      return;
    }

    this.solutionColors = [];
    this.activeGraphics = this.solutionGraphics;
    this.resetTurtle();
    this.turtleState.penColour = 0xffffff;

    const move = this._moveInstant.bind(this);
    const turn = this._turnInstant.bind(this);
    const penDown = this.penDown.bind(this);
    const penColour = this.penColour.bind(this);

    try {
      const fn = new Function(
        "move",
        "turn",
        "penDown",
        "penColour",
        configFase.solutionCode,
      );
      fn(move, turn, penDown, penColour);
    } catch (e) {
      // Erro silencioso - desenho de solução não é crítico
    }
  }

  /**
   * Gera o desenho de validação (internal) a partir de `configFase.solutionCode`.
   * @returns {void}
   */
  generateValidationDrawing() {
    const configFase = this.registry.get("configFase");
    if (!configFase || !configFase.solutionCode) {
      return;
    }

    this.validationGraphics.clear();
    this.solutionColors = [];
    this.activeGraphics = this.validationGraphics;
    this.resetTurtle();
    this.turtleState.penColour = 0xffffff;

    const move = this._moveInstant.bind(this);
    const turn = this._turnInstant.bind(this);
    const penDown = this.penDown.bind(this);
    const penColour = this.penColour.bind(this);

    try {
      const fn = new Function(
        "move",
        "turn",
        "penDown",
        "penColour",
        configFase.solutionCode,
      );
      fn(move, turn, penDown, penColour);
    } catch (e) {
      // Erro silencioso - desenho de validação não é crítico
    }
  }

    /**
     * Gera o desenho de validação (usado para comparar com o desenho do jogador).
     * @returns {void}
     */

  onBeforeRun() {
    this.playerGraphics.clear();
    this.activeGraphics = this.playerGraphics;
    this.resetTurtle();
    this.playerColors = [];
    this.resultadoJogada = "em_andamento";
    this.solutionGraphics.clear();
    this.drawSolution();
    this.generateValidationDrawing();
    this.activeGraphics = this.playerGraphics;
    this.resetTurtle();
  }

  /**
   * Hook executado antes da execução do código do aluno; prepara gráficos e estado.
   * @returns {void}
   */

  onReset() {
    this.playerGraphics.clear();
    this.solutionGraphics.clear();
    this.resetTurtle();
    this.activeGraphics = this.playerGraphics;
    this.drawSolution();
    this.playerColors = [];
    this.solutionColors = [];
    this.resultadoJogada = "em_andamento";
  }

  /**
   * Hook executado quando o usuário reseta a cena; restaura estados visuais.
   * @returns {void}
   */

  onSuccess() {
    const configFase = this.registry.get("configFase");
    if (configFase && configFase.id === 10) return;
    this.playAudio(ASSETS.AUDIO.WIN);
  }

  /**
   * Chamado quando a solução é considerada correta; executa som de vitória.
   * @returns {void}
   */

  onFailure() {
    this.playAudio(ASSETS.AUDIO.FAIL);
  }

  /**
   * Chamado quando a solução é considerada incorreta; executa som de falha.
   * @returns {void}
   */

  create() {
    this.createSpeedControl();

    this.anims.create({
      key: "turtle_walk",
      frames: [{ key: ASSETS.IMG.TURTLE1 }, { key: ASSETS.IMG.TURTLE2 }],
      frameRate: 8,
      repeat: -1,
    });

    this.solutionGraphics = this.add.graphics();
    this.playerGraphics = this.add.graphics();
    this.solutionGraphics.setAlpha(0.3);
    this.validationGraphics = this.add.graphics().setVisible(false);
    this.playerRT = this.add
      .renderTexture(0, 0, CONSTANTES.LARGURA, CONSTANTES.ALTURA)
      .setVisible(false);
    this.validationRT = this.add
      .renderTexture(0, 0, CONSTANTES.LARGURA, CONSTANTES.ALTURA)
      .setVisible(false);
    this.activeGraphics = this.playerGraphics;

    this.turtleSprite = this.add.sprite(
      CONSTANTES.LARGURA / 2,
      CONSTANTES.ALTURA / 2,
      ASSETS.IMG.TURTLE1,
    );
    this.turtleSprite.setOrigin(0.5, 0.5);
    this.turtleSprite.setAngle(0);
    this.turtleSprite.setDepth(1000);

    this.gameInterpreter = new GameInterpreter({ stepDelay: 500 });
    this.setExecutionSpeed(this.executionSpeed);
    this.drawSolution();

    this.setupStandardController(
      setupTurtleAPI,
      (history, config, gameConfig) =>
        validateSolution(history, config, gameConfig, this),
    );
  }

  /**
   * Cria elementos iniciais da cena: sprites, gráficos, intérprete e controlador.
   * @returns {void}
   */
}

export const createGame = (
  parentElement,
  configFaseAtual,
  customFailureHandler = null,
  idFaseAtual = null,
  gameConfig = null,
) => {
  const config =
    idFaseAtual && gameConfig
      ? gameConfig.fases[idFaseAtual - 1]
      : configFaseAtual;

  return {
    type: Phaser.AUTO,
    width: CONSTANTES.LARGURA,
    height: CONSTANTES.ALTURA,
    backgroundColor: "#242527",
    antialias: true,
    roundPixels: true,
    pixelArt: false,
    parent: parentElement,
    scale: {
      mode: Phaser.Scale.FIT,
      autoCenter: Phaser.Scale.CENTER_BOTH,
      zoom: 5,
    },
    scene: [TurtleScene],
    callbacks: {
      preBoot: (game) => {
        game.registry.merge({
          configFase: config,
          gameConfig: gameConfig,
          customFailureHandler: customFailureHandler,
          stepDelay: 500,
        });
      },
    },
  };
};
