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

import {
  ConstantesJogo,
  ConstantesLayout,
  ConstantesTexto,
  ConstantesAnimacao,
} from "./constants.js";
import GridBackground from "./GridBackground.js";
import CRTMonitor from "./CRTMonitor.js";
import MatrixEffect from "./MatrixEffect.js";

/**
 * Calcula as dimensões dos quadros do layout
 * @returns {Object} Objeto contendo as dimensões dos quadros esquerdo, superior direito e inferior direito
 */
export function calcularDimensoesLayout() {
  const margemX =
    ConstantesJogo.LARGURA_TELA * ConstantesLayout.MARGEM_PERCENTUAL;
  const margemY =
    ConstantesJogo.ALTURA_TELA * ConstantesLayout.MARGEM_PERCENTUAL;

  // Quadro esquerdo
  const quadroEsq = {
    x: margemX,
    y: margemY,
    largura:
      ConstantesJogo.LARGURA_TELA *
      ConstantesLayout.LARGURA_QUADRO_ESQ_PERCENTUAL,
    altura:
      ConstantesJogo.ALTURA_TELA * (1 - 2 * ConstantesLayout.MARGEM_PERCENTUAL),
  };

  // Quadros direitos
  const espacoEntreQuadros = margemY;
  const xQuadrosDir = quadroEsq.x + quadroEsq.largura + margemX;
  const larguraQuadrosDir = ConstantesJogo.LARGURA_TELA - xQuadrosDir - margemX;
  const alturaQuadrosDir = (quadroEsq.altura - espacoEntreQuadros) / 2;

  const quadroSupDir = {
    x: xQuadrosDir,
    y: margemY,
    largura: larguraQuadrosDir,
    altura: alturaQuadrosDir,
  };

  const quadroInfDir = {
    x: xQuadrosDir,
    y: quadroSupDir.y + quadroSupDir.altura + espacoEntreQuadros,
    largura: larguraQuadrosDir,
    altura: alturaQuadrosDir,
  };

  return {
    quadroEsquerdo: quadroEsq,
    quadroSuperiorDireito: quadroSupDir,
    quadroInferiorDireito: quadroInfDir,
  };
}

/**
 * Desenha as bordas dos quadros do layout
 * @param {Phaser.Scene} scene - A cena do Phaser
 * @param {Object} dimensoes - Dimensões dos quadros retornadas por calcularDimensoesLayout()
 * @param {Phaser.GameObjects.Container} container - Container opcional onde adicionar os gráficos
 * @returns {Phaser.GameObjects.Graphics} O objeto gráfico criado
 */
export function desenharBordasQuadros(scene, dimensoes, container = null) {
  const graphics = scene.add.graphics();
  graphics.lineStyle(
    ConstantesLayout.ESPESSURA_BORDA,
    ConstantesLayout.COR_BORDA,
    1,
  );

  const raio = ConstantesLayout.RAIO_ARREDONDAMENTO;

  // Quadro esquerdo
  graphics.strokeRoundedRect(
    dimensoes.quadroEsquerdo.x,
    dimensoes.quadroEsquerdo.y,
    dimensoes.quadroEsquerdo.largura,
    dimensoes.quadroEsquerdo.altura,
    raio,
  );

  // Quadro superior direito (Entrada)
  graphics.strokeRoundedRect(
    dimensoes.quadroSuperiorDireito.x,
    dimensoes.quadroSuperiorDireito.y,
    dimensoes.quadroSuperiorDireito.largura,
    dimensoes.quadroSuperiorDireito.altura,
    raio,
  );

  // Quadro inferior direito (Saída)
  graphics.strokeRoundedRect(
    dimensoes.quadroInferiorDireito.x,
    dimensoes.quadroInferiorDireito.y,
    dimensoes.quadroInferiorDireito.largura,
    dimensoes.quadroInferiorDireito.altura,
    raio,
  );

  if (container) {
    container.add(graphics);
  }

  return graphics;
}

/**
 * Cria os textos de entrada e saída dentro dos quadros
 * @param {Phaser.Scene} scene - A cena do Phaser
 * @param {Object} dimensoes - Dimensões dos quadros retornadas por calcularDimensoesLayout()
 * @param {Phaser.GameObjects.Container} container - Container opcional onde adicionar os textos
 * @returns {Object} Objeto contendo as referências aos textos de entrada e saída
 */
export function criarTextosVisuais(scene, dimensoes, container = null) {
  const padding = ConstantesLayout.PADDING_TEXTO;

  const textoEntrada = scene.add
    .text(
      dimensoes.quadroSuperiorDireito.x + padding,
      dimensoes.quadroSuperiorDireito.y + padding,
      "",
      {
        fontSize: ConstantesTexto.ENTRADA.TAMANHO_FONTE,
        fontStyle: ConstantesTexto.ENTRADA.PESO_FONTE,
        fill: ConstantesTexto.ENTRADA.COR,
        align: ConstantesTexto.ENTRADA.ALINHAMENTO,
        wordWrap: {
          width: dimensoes.quadroSuperiorDireito.largura - padding * 2,
          useAdvancedWrap: true,
        },
      },
    )
    .setOrigin(0, 0);

  const textoSaida = scene.add
    .text(
      dimensoes.quadroInferiorDireito.x + padding,
      dimensoes.quadroInferiorDireito.y + padding,
      "",
      {
        fontSize: ConstantesTexto.SAIDA.TAMANHO_FONTE,
        fontStyle: ConstantesTexto.SAIDA.PESO_FONTE,
        fill: ConstantesTexto.SAIDA.COR,
        align: ConstantesTexto.SAIDA.ALINHAMENTO,
        wordWrap: {
          width: dimensoes.quadroInferiorDireito.largura - padding * 2,
          useAdvancedWrap: true,
        },
      },
    )
    .setOrigin(0, 0);

  if (container) {
    container.add([textoEntrada, textoSaida]);
  }

  return {
    textoEntrada,
    textoSaida,
  };
}

/**
 * Cria as colunas de texto para animação Matrix
 * @param {Phaser.Scene} scene - A cena do Phaser
 * @param {Object} dimensoes - Dimensões dos quadros
 * @param {Phaser.GameObjects.Container} container - Container opcional onde adicionar as colunas
 * @returns {Array} Array de objetos de texto para as colunas
 */
export function criarColunasMatrix(scene, dimensoes, container = null) {
  const padding = ConstantesLayout.PADDING_TEXTO + 5;
  const numColunas = ConstantesAnimacao.MATRIX.NUMERO_COLUNAS;
  const larguraDisponivel = dimensoes.quadroEsquerdo.largura - padding * 2;
  const espacoEntreColunas = larguraDisponivel / numColunas;

  const colunas = [];

  for (let i = 0; i < numColunas; i++) {
    const x = dimensoes.quadroEsquerdo.x + padding + i * espacoEntreColunas + 5;
    const y = dimensoes.quadroEsquerdo.y + padding;

    const coluna = scene.add
      .text(x, y, "", {
        fontSize: ConstantesAnimacao.MATRIX.TAMANHO_FONTE,
        fill: ConstantesAnimacao.MATRIX.COR_TEXTO,
        align: "center",
        lineSpacing: 6,
      })
      .setOrigin(0.6, 0);

    colunas.push(coluna);
  }

  if (container) {
    container.add(colunas);
  }

  return colunas;
}

/**
 * Inicializa o layout completo do jogo
 * @param {Phaser.Scene} scene - A cena do Phaser
 * @returns {Object} Objeto contendo as referências aos textos criados
 */
export function inicializarLayout(scene) {
  const crtMonitor = new CRTMonitor(
    scene,
    scene.scale.width,
    scene.scale.height,
  );
  const contentLayer = crtMonitor.getContentLayer();

  const gridBackground = new GridBackground(scene, contentLayer);
  gridBackground.draw();

  const dimensoes = calcularDimensoesLayout();
  desenharBordasQuadros(scene, dimensoes, contentLayer);
  const textos = criarTextosVisuais(scene, dimensoes, contentLayer);
  const colunasMatrix = criarColunasMatrix(scene, dimensoes, contentLayer);

  const matrixEffect = new MatrixEffect(scene, colunasMatrix);

  return {
    ...textos,
    colunasMatrix,
    gridBackground,
    matrixEffect,
    crtMonitor,
    dimensoes,
  };
}
