const channelToken = new URLSearchParams(window.location.hash.slice(1)).get('channelToken');

function notify(type, payload = {}) {
  window.parent.postMessage({ type, token: channelToken, ...payload }, '*');
}

const SINGLE_CHARACTER_POOL = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*()-=+_'.split('');
const TOKEN_POOLS_BY_LENGTH = {
  2: [
    'ab', 'cd', 'ef', 'hj', 'mn', 'pq', '44', '17', '29', '80',
    'GG', 'HJ', 'KL', 'MN', 'PR', 'TV', 'WW', 'XX', 'YY', 'ZZ',
  ],
  3: [
    'sol', 'mar', 'ceu', 'rio', 'lua', 'dia', 'som', 'mel', 'paz', 'voz',
    'bom', 'fim', 'cor', 'lar', 'giz', 'asa', 'luz', 'rei', 'nuv', 'fio',
  ],
  4: [
    'casa', 'mesa', 'jogo', 'foco', 'dado', 'bola', 'pato', 'gato', 'rede', 'nave',
    'copo', 'lago', 'tela', 'nota', 'rima', 'sapo', 'coro', 'vela', 'pulo', 'pipa',
  ],
};
const STAGES = [
  { goal: 5, speedMultiplier: 1, mode: 'single' },
  { goal: 5, speedMultiplier: 1.45, mode: 'single' },
  { goal: 5, speedMultiplier: 1.75, mode: 'single' },
  { goal: 5, speedMultiplier: 1, mode: 'token', tokenLength: 2 },
  { goal: 5, speedMultiplier: 1, mode: 'token', tokenLength: 3 },
  { goal: 5, speedMultiplier: 1, mode: 'token', tokenLength: 4 },
];

let stageIndex = 0;
let score = 0;
let gameActive = true;
let falling = [];
let spawnTimer = null;
let totalInputs = 0;
let correctInputs = 0;
let inputBuffer = '';
let tokenCycle = [];

notify('started');

const arena = document.getElementById('arena');
const scoreEl = document.getElementById('score');
const goalEl = document.getElementById('goal');
const stageLabelEl = document.getElementById('stageLabel');
const accuracyLabel = document.getElementById('accuracyLabel');
const progressFill = document.getElementById('progressFill');
const feedbackEl = document.getElementById('feedback');
const successBanner = document.getElementById('successBanner');
const gameoverBanner = document.getElementById('gameoverBanner');
const gameoverStageLabel = document.getElementById('gameoverStageLabel');
const retryStageBtn = document.getElementById('retryStageBtn');

const COLORS = [
  ['bg-cyan-500 text-white border-cyan-300', 'cyan'],
  ['bg-violet-500 text-white border-violet-300', 'violet'],
  ['bg-orange-500 text-white border-orange-300', 'orange'],
  ['bg-pink-500 text-white border-pink-300', 'pink'],
];

function getCurrentStage() {
  return STAGES[stageIndex];
}

function getAccuracy() {
  if (totalInputs === 0) return 100;
  return (correctInputs / totalInputs) * 100;
}

function updateStageUi() {
  const stage = getCurrentStage();
  scoreEl.textContent = score;
  goalEl.textContent = stage.goal;
  stageLabelEl.textContent = `${stageIndex + 1} de ${STAGES.length}`;
  accuracyLabel.textContent = `${Math.round(getAccuracy())}%`;
  progressFill.style.width = `${(score / stage.goal) * 100}%`;
}

function showFeedback(message, kind) {
  feedbackEl.textContent = message;
  feedbackEl.className = `text-2xl font-bold py-1 text-center ${kind === 'error' ? 'text-red-500' : 'text-green-600'}`;
  feedbackEl.classList.remove('hidden');
}

function clearFeedback() {
  feedbackEl.classList.add('hidden');
}

function restartCurrentStage() {
  gameActive = true;
  score = 0;
  totalInputs = 0;
  correctInputs = 0;
  inputBuffer = '';
  tokenCycle = [];
  falling.forEach((item) => item.el.remove());
  falling = [];
  lastTime = null;
  gameoverBanner.classList.add('hidden');
  clearFeedback();
  updateStageUi();
  startSpawnLoop();
  spawnCharacter();
  requestAnimationFrame(gameLoop);
}

function finishFailure() {
  gameActive = false;
  if (spawnTimer) clearInterval(spawnTimer);
  arena.innerHTML = '';
  falling = [];
  gameoverStageLabel.textContent = `Etapa ${stageIndex + 1}: você não atingiu 60% de precisão.`;
  gameoverBanner.classList.remove('hidden');
  lucide.createIcons();
  // Não notifica 'failure' ao host para evitar que o modal externo cause reload do iframe.
  // O retry é gerenciado internamente pelo botão desta tela.
}

function finishSuccess() {
  gameActive = false;
  if (spawnTimer) clearInterval(spawnTimer);
  arena.innerHTML = '';
  successBanner.classList.remove('hidden');
  lucide.createIcons();
  notify('success', { score: 100 });
  notify('completed', { score: 100 });
}

function shuffle(list) {
  const copy = [...list];
  for (let index = copy.length - 1; index > 0; index -= 1) {
    const swapIndex = Math.floor(Math.random() * (index + 1));
    [copy[index], copy[swapIndex]] = [copy[swapIndex], copy[index]];
  }
  return copy;
}

function refillTokenCycle(length) {
  const pool = TOKEN_POOLS_BY_LENGTH[length] ?? [];
  tokenCycle = shuffle(pool);
}

function pickRandomToken(length) {
  if (tokenCycle.length === 0) {
    refillTokenCycle(length);
  }

  return tokenCycle.pop();
}

function makeEntityForStage(stage) {
  if (stage.mode === 'single') {
    return SINGLE_CHARACTER_POOL[Math.floor(Math.random() * SINGLE_CHARACTER_POOL.length)];
  }

  return pickRandomToken(stage.tokenLength);
}

function getEntityFontClass(entity) {
  if (entity.length >= 4) return 'text-xl';
  if (entity.length === 3) return 'text-2xl';
  return 'text-3xl';
}

function evaluateStageAndAdvance() {
  const accuracy = getAccuracy();
  if (accuracy < 60) {
    showFeedback('Precisão abaixo de 60%. Tente novamente.', 'error');
    finishFailure();
    return;
  }

  stageIndex += 1;
  score = 0;
  falling.forEach((item) => item.el.remove());
  falling = [];
  inputBuffer = '';
  tokenCycle = [];

  if (stageIndex >= STAGES.length) {
    finishSuccess();
    return;
  }

  updateStageUi();
  showFeedback(`Etapa ${stageIndex + 1} liberada!`, 'success');
  notify('running', { step: stageIndex + 1 });
  spawnCharacter();
}

function spawnCharacter() {
  if (!gameActive) return;
  const stage = getCurrentStage();
  const character = makeEntityForStage(stage);
  const color = COLORS[Math.floor(Math.random() * COLORS.length)];
  const arenaW = arena.clientWidth - 140;
  const x = Math.floor(Math.random() * arenaW);
  const id = `fall-${Date.now()}-${Math.random()}`;
  const speed = (60 + Math.random() * 40) * stage.speedMultiplier;

  const el = document.createElement('div');
  el.id = id;
  el.className = `falling-char border-2 ${getEntityFontClass(character)} ${color[0]}`;
  el.textContent = character;
  el.style.left = `${x}px`;
  el.style.top = '0px';
  arena.appendChild(el);

  const item = { id, character, el, top: 0, speed };
  falling.push(item);
  return item;
}

let lastTime = null;
function gameLoop(timestamp) {
  if (!gameActive) return;
  if (!lastTime) lastTime = timestamp;
  const dt = (timestamp - lastTime) / 1000;
  lastTime = timestamp;

  const arenaH = arena.clientHeight;
  const stage = getCurrentStage();
  falling = falling.filter(item => {
    item.top += item.speed * dt;
    item.el.style.top = `${item.top}px`;
    if (item.top + 64 >= arenaH) {
      item.el.remove();
      totalInputs += 1;
      updateStageUi();
      showFeedback(stage.mode === 'token' ? 'Uma combinação caiu. Tente a próxima.' : 'Um caractere caiu. Tente o próximo.', 'error');
      return false;
    }
    return true;
  });

  requestAnimationFrame(gameLoop);
}

document.addEventListener('keydown', (e) => {
  if (!gameActive) return;
  if (e.key.length !== 1) return;

  const stage = getCurrentStage();
  const key = e.key;

  if (stage.mode === 'single') {
    totalInputs += 1;
    const idx = falling.findIndex((item) => item.character === key);

    if (idx !== -1) {
      const item = falling[idx];
      item.el.style.background = '#22c55e';
      item.el.style.color = 'white';
      item.el.style.transform = 'scale(0.92)';
      setTimeout(() => item.el.remove(), 200);
      falling.splice(idx, 1);
      score += 1;
      correctInputs += 1;
      updateStageUi();
      clearFeedback();
      notify('running', { step: stageIndex + 1 });
      if (score >= stage.goal) {
        evaluateStageAndAdvance();
      }
      return;
    }

    updateStageUi();
    showFeedback('Esse não era o caractere da tela.', 'error');
    return;
  }

  inputBuffer += key;
  const tokenLength = stage.tokenLength ?? 2;
  if (inputBuffer.length < tokenLength) {
    return;
  }

  const attempt = inputBuffer.slice(-tokenLength);
  inputBuffer = '';
  totalInputs += 1;
  const idx = falling.findIndex((item) => item.character === attempt);

  if (idx !== -1) {
    const item = falling[idx];
    item.el.style.background = '#22c55e';
    item.el.style.color = 'white';
    item.el.style.transform = 'scale(0.92)';
    setTimeout(() => item.el.remove(), 200);
    falling.splice(idx, 1);
    score += 1;
    correctInputs += 1;
    updateStageUi();
    clearFeedback();
    notify('running', { step: stageIndex + 1 });
    if (score >= stage.goal) {
      evaluateStageAndAdvance();
    }
  } else {
    updateStageUi();
    showFeedback(`Combinação incorreta: ${attempt}`, 'error');
  }
});

function startSpawnLoop() {
  if (spawnTimer) clearInterval(spawnTimer);

  spawnTimer = setInterval(() => {
    if (!gameActive) {
      clearInterval(spawnTimer);
      return;
    }
    if (falling.length < 5) spawnCharacter();
  }, 1500);
}

retryStageBtn.addEventListener('click', restartCurrentStage);

updateStageUi();
startSpawnLoop();
spawnCharacter();

document.addEventListener('visibilitychange', () => {
  if (!gameActive) { clearInterval(spawnTimer); return; }
  if (!document.hidden && falling.length === 0) {
    spawnCharacter();
  }
});

requestAnimationFrame(gameLoop);
