import Phaser from "phaser";
import { BaseGameScene } from "../../../shared/BaseGameScene.js";
import { setupAspiradorAPI } from "./hooks/setupAspiradorAPI.js";
import { validationSolution } from "./validation/validators.js";
import { gameConfig } from "./config/config.js";
import { ConstantesJogo, ConstantesAssets } from "./ui/constants.js";
import { inicializarLayout } from "./ui/layout.js";

export class AspiradorScene extends BaseGameScene {
  constructor() {
    super("AspiradorScene");
    this.matrizAtiva = [];
    this.totalSujeiras = 0;
    this.sujeirasSprites = {};
    this.roboLogico = { col: 0, lin: 0, angulo: 0 };
    this.obstaculos = [];
    this.shouldValidate = false; // Flag para validação manual
    this.executionStopped = false; // Flag separada para parar loops
  }

  create() {
    this.validatorFunc = (historico) => validationSolution(historico, this.configFase, gameConfig, this);
    
    this.setupStandardController(
      () => setupAspiradorAPI(this, { animationSpeed: 250 }),
      this.validatorFunc
    );

    inicializarLayout(this);
    this.montarFase();
  }

  preload() {
    this.preloadGlobalAssets(); // Som global (BaseGameScene)

    const chaves = ConstantesAssets.CHAVES;
    const paths = ConstantesAssets.PATHS;

    this.load.image(chaves.PISO, paths.PISO);
    this.load.image(chaves.ASPIRADOR, paths.ASPIRADOR);
    this.load.image(chaves.SUJEIRA, paths.SUJEIRA);
    this.load.image(chaves.OBSTACULO1, paths.OBSTACULO1);
    this.load.image(chaves.OBSTACULO2, paths.OBSTACULO2);
    
    // Carregar sons
    this.load.audio(chaves.SOM_POP, paths.SOM_POP);
    this.load.audio(chaves.SOM_BG, paths.SOM_BG);
  }

  onReset() {
    this.isRunning = false;
    this.executionStopped = true; // Para qualquer execução pendente
    this.shouldValidate = false; // Limpa flag de validação pendente
    
    // Para o som do aspirador imediatamente
    this.stopAudio(ConstantesAssets.CHAVES.SOM_BG);
    
    if (this._timerTimeout) {
      clearTimeout(this._timerTimeout);
      this._timerTimeout = null;
    }
    this.montarFase();
  }

  /**
   * Hook Assíncrono de Sucesso: O robô comemora.
   */
  async onSuccess() {
    if (this._timerTimeout) clearTimeout(this._timerTimeout);
    this.isRunning = false;
    
    // Para o som do aspirador ao completar
    this.stopAudio(ConstantesAssets.CHAVES.SOM_BG);

    return new Promise(resolve => {
      this.tweens.add({
        targets: this.aspiradorSprite,
        angle: '+=360',
        scale: 1,
        duration: 300,
        yoyo: true,
        ease: 'Back.easeOut',
        onComplete: resolve
      });
    });
  }

  /**
   * Hook Assíncrono de Falha: O robô treme em pane.
   */
  async onFailure() {
    if (this._timerTimeout) clearTimeout(this._timerTimeout);
    this.isRunning = false;
    
    // Para o som do aspirador ao falhar
    this.stopAudio(ConstantesAssets.CHAVES.SOM_BG);

    return new Promise(resolve => {
      this.aspiradorSprite.setTint(0xff0000); // Fica vermelho de erro
      this.tweens.add({
        targets: this.aspiradorSprite,
        x: '+=5',
        yoyo: true,
        repeat: 10,
        duration: 50,
        onComplete: () => {
          this.aspiradorSprite.clearTint();
          resolve();
        }
      });
    });
  }

  onBeforeRun() {
    this.isRunning = true;
    this.historico = [];
    this.shouldValidate = false; // Reset flag de validação manual
    this.executionStopped = false; // Reset flag de parada

    // Som do aspirador em loop durante execução
    this.playAudio(ConstantesAssets.CHAVES.SOM_BG, { loop: true, volume: 0.5 });

    // 1. Limpa resquícios de execuções anteriores
    if (this._timerTimeout) clearTimeout(this._timerTimeout);

    // 2. Inicia o Cronômetro (Timeout)
    const limiteSegundos = this.configFase?.timeout || 30;

    this._timerTimeout = setTimeout(() => {
      if (this.isRunning) {
        this.isRunning = false;

        // Força a falha por tempo
        const msg = this.gameConfig?.mensagens?.timeoutExcedido || "Tempo esgotado!";
        this.handleFailure(msg);
      }
    }, limiteSegundos * 1000);
  }

  montarFase() {
    if (this.aspiradorSprite) this.aspiradorSprite.destroy();

    Object.values(this.sujeirasSprites).forEach(s => s.destroy());
    this.obstaculos.forEach(o => o.destroy());

    this.sujeirasSprites = {};
    this.obstaculos = [];
    this.totalSujeiras = 0;

    const cfg = this.configFase;
    this.matrizAtiva = JSON.parse(JSON.stringify(cfg.matriz));

    for (let lin = 0; lin < this.matrizAtiva.length; lin++) {
      for (let col = 0; col < this.matrizAtiva[lin].length; col++) {
        let v = this.matrizAtiva[lin][col];
        let pX = col * 80 + 40;
        let pY = lin * 80 + 40;

        if (v === 1) {
          // Aspirador
          this.aspiradorSprite = this.add.image(pX, pY, ConstantesAssets.CHAVES.ASPIRADOR).setDisplaySize(80, 80).setDepth(10);
          this.aspiradorSprite.angle = cfg.direcao || 0;
          this.roboLogico = { col, lin, angulo: cfg.direcao || 0 };
        } 
        else if (v === 2) {
          // Sujeira
          this.sujeirasSprites[`${lin}-${col}`] = this.add.image(pX, pY, ConstantesAssets.CHAVES.SUJEIRA).setDisplaySize(64, 64).setDepth(5);
          this.totalSujeiras++;
        }
        else if (v === 3 || v === 4) {
          // Obstáculos normais (1x1) - Vasos ou Sofás
          const chave = v === 3 ? ConstantesAssets.CHAVES.OBSTACULO1 : ConstantesAssets.CHAVES.OBSTACULO2;
          this.obstaculos.push(this.add.image(pX, pY, chave).setDisplaySize(80, 80).setDepth(6));
        }
      }
    }
  }

  // --- API para o Interpretador (Usado via ApiHelpers) ---

  mover() {
    if (this.executionStopped) {
      return Promise.resolve();
    }

    // 1. Mapeamento estrito de direção (Sem trigonometria)
    const angNorm = ((this.roboLogico.angulo % 360) + 360) % 360;
    let dc = 0, dl = 0;

    if (angNorm === 0) dl = -1; // Olhando para Cima (Subindo linha)
    else if (angNorm === 90) dc = 1;  // Olhando para Direita (Avançando coluna)
    else if (angNorm === 180) dl = 1;  // Olhando para Baixo (Descendo linha)
    else if (angNorm === 270) dc = -1; // Olhando para Esquerda (Voltando coluna)

    let nC = this.roboLogico.col + dc;
    let nL = this.roboLogico.lin + dl;

    // 2. Proteção: Se a frente está bloqueada, cancela o movimento (NÃO registra no histórico)
    if (this.checarBloqueio('FRENTE')) {
      return Promise.resolve();
    }

    // Só registra movimento no histórico se efetivamente vai se mover
    this.historico.push({ tipo: "mover", l: nL, c: nC });

    // 3. Atualiza posição lógica e limpa sujeira ANTES da animação
    // Corrige condição de corrida com aindaTemSujeira()
    this.roboLogico.col = nC;
    this.roboLogico.lin = nL;

    // Limpa a matriz IMEDIATAMENTE para que aindaTemSujeira() veja o estado correto
    if (this.matrizAtiva[nL] && this.matrizAtiva[nL][nC] === 2) {
      this.matrizAtiva[nL][nC] = 0;
      this.totalSujeiras--;
      
      // Toca som pop ao coletar sujeira
      this.playAudio(ConstantesAssets.CHAVES.SOM_POP, { volume: 0.7 });
      
      // INTERRUPÇÃO AUTOMÁTICA: Se limpou a última sujeira, para imediatamente
      if (this.totalSujeiras === 0) {
        this.executionStopped = true; // Para loops imediatamente
        this.shouldValidate = true;
        
        this.stopAudio(ConstantesAssets.CHAVES.SOM_BG);
        
        // Para o interpretador imediatamente mas sem marcar como parado pelo utilizador,
        // para que o fluxo de validação em handleValidation() não seja abortado.
        if (this.gameInterpreter) {
          this.gameInterpreter.stopInternal();
        }
        
        // Agenda validação (deixa um tempo para tweens existentes terminarem)
        this.time.delayedCall(300, () => {
          if (this.shouldValidate && this.validatorFunc) {
            this.handleValidation(this.validatorFunc);
            this.shouldValidate = false;
          }
        });
      }
    }

    return new Promise(res => {
      this.tweens.add({
        targets: this.aspiradorSprite,
        x: nC * 80 + 40,
        y: nL * 80 + 40,
        duration: 100, // 2x mais rápido (do 200ms para 100ms) para compensar som de 1s
        onComplete: () => {
          // Remove sprite visual após animação
          let key = `${nL}-${nC}`;
          if (this.sujeirasSprites[key]) {
            this.sujeirasSprites[key].destroy();
            delete this.sujeirasSprites[key];
          }
          res();
        }
      });
    });
  }

  virar(dir) {
    if (this.executionStopped) {
      return Promise.resolve();
    }
    const incremento = (dir === 'DIREITA' ? 90 : -90);
    this.roboLogico.angulo += incremento;
    this.historico.push({ tipo: "virar", valor: dir });
    return new Promise(res => {
      this.tweens.add({ targets: this.aspiradorSprite, angle: this.roboLogico.angulo, duration: 100, onComplete: res });
    });
  }

  checarBloqueio(sentido) {
    // Se execução parou, sempre retorna true (bloqueado) para evitar mais movimentos
    if (this.executionStopped) {
      return true;
    }
    
    // 1. Calcula o ângulo que o sensor quer olhar
    let anguloBase = ((this.roboLogico.angulo % 360) + 360) % 360;
    let anguloTeste = anguloBase;

    if (sentido === 'DIREITA') anguloTeste += 90;
    else if (sentido === 'ESQUERDA') anguloTeste -= 90;

    const angNorm = ((anguloTeste % 360) + 360) % 360;

    // 2. Projeta onde o sensor está "batendo"
    let dc = 0, dl = 0;
    if (angNorm === 0) dl = -1;
    else if (angNorm === 90) dc = 1;
    else if (angNorm === 180) dl = 1;
    else if (angNorm === 270) dc = -1;

    const nC = this.roboLogico.col + dc;
    const nL = this.roboLogico.lin + dl;

    // 3. Leitura DINÂMICA do tamanho real da sua fase atual
    const maxLinhas = this.matrizAtiva.length;
    const maxCols = this.matrizAtiva[0]?.length || 0;

    let bloqueado = false;

    // Se saiu dos limites da matriz, é parede invisível!
    if (nC < 0 || nC >= maxCols || nL < 0 || nL >= maxLinhas) {
      bloqueado = true;
    }
    // Se encontrou um obstáculo interno (vaso, sofá, etc)
    else if (this.matrizAtiva[nL] && this.matrizAtiva[nL][nC] >= 3) {
      bloqueado = true;
    }

    this.historico.push({ tipo: "sensor", sentido, resultado: bloqueado });
    return bloqueado;
  }

  aindaTemSujeira() {
    // Se já paramos a execução, sempre retorna false para sair dos loops
    if (this.executionStopped) {
      return false;
    }
    
    // Usa o contador otimizado
    const tem = this.totalSujeiras > 0;

    this.historico.push({ tipo: "sensor", acao: "check_sujeira", resultado: tem });
    return tem;
  }
}

/**
 * Factory para criar a configuração do Phaser para o jogo Aspirador.
 * @param {HTMLElement} elementoPai - Container DOM
 * @param {Object} configFaseAtual - Dados da fase selecionada
 * @returns {Object} Configuração do Phaser
 */
export const createGame = (elementoPai, configFaseAtual) => {
  const scene = new AspiradorScene();

  return {
    type: Phaser.AUTO,
    width: ConstantesJogo.LARGURA_TELA || 800,
    height: ConstantesJogo.ALTURA_TELA || 560,
    backgroundColor: "#2d2d2d",
    parent: elementoPai,
    scale: { mode: Phaser.Scale.FIT, autoCenter: Phaser.Scale.CENTER_BOTH },
    scene: scene,
    callbacks: {
      preBoot: function (game) {
        game.registry.set("configFase", configFaseAtual);
        game.registry.set("gameConfig", gameConfig);
      },
    },
  };
};