/**
 * @fileoverview Validações base para as várias fases dos jogos.
 *
 * `BaseGameValidator` implementa checks genéricos (sanity, sequência) e um
 * contrato para validações específicas de fase via `validatePhase` que deve
 * ser implementado por validadores concretos de cada jogo.
 *
 * @module shared.BaseGameValidator
 */

export class BaseGameValidator {
  /**
   * Valida a solução do aluno aplicando checks genéricos e delegando para
   * `validatePhase` para validações específicas do jogo.
   *
   * @param {Array<Object>} history - Histórico de ações do aluno
   * @param {Object} configFase - Configuração da fase atual
   * @param {Object} gameConfig - Configuração global do jogo
   * @param {Object} [sceneRef] - Referência à cena (opcional)
   * @returns {{success: boolean, reason?: string}}
   */
  validate(history, configFase, gameConfig, sceneRef) {
    // 1. Fail-Safe Técnico: A config da fase chegou?
    if (!configFase || Object.keys(configFase).length === 0) {
      console.error("Validação falhou: Configuração da fase não encontrada.");
      return this.failure("Erro Técnico: Fase não configurada.");
    }

    // 2. Sanity Check: O histórico está vazio? (Genérico para qualquer jogo)
    const sanityCheck = this.checkSanity(history, gameConfig);
    if (!sanityCheck.success) return sanityCheck;

    // 3. Validação de Sequência (Opcional, ativado via config)
    // Muitos jogos usam "siga estes passos exatos", então vale manter na base.
    if (configFase.expectedSequence) {
      const sequenceCheck = this.checkSequence(
        history,
        configFase.expectedSequence,
        gameConfig,
      );
      if (!sequenceCheck.success) return sequenceCheck;
    }

    // 4. Validação Específica (Polimorfismo)
    // Aqui entra a lógica de Negócio do Jogo (Limites, Regras, etc)
    return this.validatePhase(history, configFase, gameConfig, sceneRef);
  }

  /**
   * Validação específica de fase a ser implementada por cada jogo.
   * Deve retornar um objeto `{ success: boolean, reason?: string }`.
   *
   * @abstract
   * @param {Array<Object>} history
   * @param {Object} configFase
   * @param {Object} gameConfig
   * @param {Object} [sceneRef] - Referência à cena (opcional)
   * @returns {{success: boolean, reason?: string}}
   */
  validatePhase(history, configFase, gameConfig, sceneRef) {
    console.warn("BaseGameValidator: validatePhase não implementado.");
    return this.success();
  }

  // --- Verificações Genéricas ---

  /**
   * Verifica se o histórico contém movimentos.
   * @param {Array<Object>} history
   * @param {Object} gameConfig
    * @returns {{success: boolean, reason?: string}}
   */
  checkSanity(history, gameConfig) {
    if (!history || history.length === 0) {
      return this.failure(
        gameConfig?.mensagens?.semMovimento || "Nenhum movimento detectado.",
      );
    }
    return this.success();
  }

  /**
   * Compara o `history` com a sequência esperada definida na config.
   * @param {Array<Object>} history
   * @param {Array<Object>} expected
   * @param {Object} gameConfig
    * @returns {{success: boolean, reason?: string}}
   */
  checkSequence(history, expected, gameConfig) {
    // Compara se o histórico bate com a sequência esperada, propriedade por propriedade
    const match = expected.every((step, i) => {
      const action = history[i];
      if (!action) return false;
      // Verifica se todas as chaves do passo esperado estão presentes e iguais na ação
      return Object.keys(step).every((key) => step[key] === action[key]);
    });

    return match
      ? this.success()
      : this.failure(
          gameConfig?.mensagens?.caminhoErrado || "Sequência incorreta.",
        );
  }

  // --- Helpers de Retorno (Syntax Sugar) ---

  /**
   * Helper que representa sucesso de validação.
   * @returns {{success: boolean}}
   */
  success() {
    return { success: true };
  }

  /**
   * Helper que representa falha de validação.
   * @param {string} reason - Mensagem explicando a falha
   * @returns {{success: boolean, reason: string}}
   */
  failure(reason) {
    return { success: false, reason };
  }
}
