import { getFirestore } from 'firebase-admin/firestore';
import { onDocumentUpdated } from 'firebase-functions/v2/firestore';
import { logger } from 'firebase-functions';

/**
 * Libera o sigilo dos palpites quando o jogo **termina**.
 *
 * A rule de leitura decide o sigilo por um campo copiado para dentro do palpite
 * (`matchFinished`), porque security rule não filtra resultado de consulta e
 * `get()` no jogo a cada documento avaliado estouraria o limite. Alguém tem de
 * virar esse campo, e é esta Function.
 *
 * **O risco mudou de lugar, não desapareceu.** No NestJS o sigilo era um filtro na
 * consulta: se o código estivesse certo, valia sempre. Aqui, se esta Function não
 * rodar, os palpites de um jogo terminado ficam secretos **a mais** — chato, e
 * seguro. O inverso é que seria grave: liberar antes do fim. Por isso o gatilho é
 * a transição para `FINISHED` **com placar**, e não o apito.
 *
 * Libera no **fim**, não no início: jogo em andamento continua secreto. Quem vê o
 * palpite alheio no intervalo sabe o que precisa acontecer no segundo tempo.
 */
export const liberarSigiloQuandoJogoTermina = onDocumentUpdated(
  { document: 'jogos/{matchId}', region: 'southamerica-east1' },
  async (evento) => {
    const antes = evento.data?.before.data();
    const depois = evento.data?.after.data();
    if (!antes || !depois) return;

    const terminouAgora =
      terminou(depois) && !terminou(antes);
    if (!terminouAgora) return;

    const matchId = evento.params.matchId;
    const db = getFirestore();

    // Consulta de grupo: o mesmo jogo aparece em vários bolões, e o palpite vive
    // dentro do bolão. Exige índice de grupo em `palpites.matchId` — declarado em
    // `firestore.indexes.json`, e o emulador **não** cobra isso (ver MG-2).
    const palpites = await db
      .collectionGroup('palpites')
      .where('matchId', '==', matchId)
      .where('matchFinished', '==', false)
      .get();

    if (palpites.empty) {
      logger.info(`jogo ${matchId} terminou sem palpite para liberar`);
      return;
    }

    // Lote, não transação: bolão de empresa com muitos participantes passa do
    // limite de 500 operações por transação. `BulkWriter` divide sozinho e é
    // idempotente aqui — reescrever `matchFinished: true` não muda nada.
    const lote = db.bulkWriter();
    for (const doc of palpites.docs) {
      lote.update(doc.ref, { matchFinished: true });
    }
    await lote.close();

    logger.info(
      `jogo ${matchId} terminou: sigilo liberado em ${palpites.size} palpite(s)`,
    );
  },
);

/**
 * Terminado **e com placar**. `status: FINISHED` sem placar acontece na fonte
 * oficial (jogo encerrado sem resultado publicado ainda) — liberar aí revelaria o
 * palpite de todos sem ninguém ter pontuado, e sem o que conferir.
 */
function terminou(jogo: Record<string, unknown>): boolean {
  return (
    jogo.status === 'FINISHED' &&
    jogo.homeScore !== null &&
    jogo.homeScore !== undefined &&
    jogo.awayScore !== null &&
    jogo.awayScore !== undefined
  );
}
