/**
 * @fileoverview Perfil de detecção: Counting Sort.
 *
 * Invariantes obrigatórios:
 *   1. Nenhuma troca (swapCount === 0).
 *   2. Nenhuma comparação posição-a-posição (compareCount === 0).
 *   3. Exatamente n escritas, nas posições 0, 1, 2, ..., n-1 em ordem sequencial.
 *      Isso é a assinatura da fase de reconstrução do Counting Sort.
 *   4. Pelo menos n leituras (fase de contagem — ler cada elemento da lista original).
 *
 * Por que o critério 3 é forte:
 *   - Insertion Sort: escreve de volta nas mesmas posições que deslocou → não sequencial.
 *   - Shell Sort: escreve nas posições do gap → não sequencial.
 *   - Counting Sort: reconstrói a lista de 0 a n-1, em ordem crescente de valor.
 *
 * Variações aceitas:
 *   - Contagem com array de tamanho max+1 ou com offset min..max.
 *   - Reconstrução com loop de valores (v=0..max) ou com prefixos acumulados.
 *
 * O que NÃO é aceito:
 *   - Qualquer swap ou compare.
 *   - Menos de n escritas ou escritas fora de ordem sequencial.
 */

/**
 * @param {import("../core/ExecutionTrace.js").TraceEvent[]} trace
 * @param {number} n - Tamanho da lista.
 * @returns {{ match: boolean, failReason?: string }}
 */
export function countingProfile(trace, n) {
  const compares       = trace.filter(e => e.type === "compare");
  const swaps          = trace.filter(e => e.type === "swap");
  const writes         = trace.filter(e => e.type === "write");
  const reads          = trace.filter(e => e.type === "read");
  const contagemWrites = trace.filter(e => e.type === "contagem_write");

  // Invariante 0: deve haver escritas na contagem — assinatura do Counting Sort
  if (contagemWrites.length === 0) {
    return {
      match: false,
      failReason:
        "Nenhuma escrita na lista de contagem detectada. O Counting Sort requer o uso de " +
        "lista_contagem_escrever para registrar as frequências de cada valor.",
    };
  }

  // Invariante 1: sem trocas
  if (swaps.length > 0) {
    return {
      match: false,
      failReason:
        "Trocas (swap) foram detectadas. O Counting Sort não realiza trocas entre elementos. " +
        "Ele conta quantas vezes cada valor aparece e reconstrói a lista a partir dessas contagens.",
    };
  }

  // Invariante 2: sem comparações posição-a-posição
  if (compares.length > 0) {
    return {
      match: false,
      failReason:
        "Comparações entre posições da lista foram detectadas. O Counting Sort não compara " +
        "elementos entre si — use lista_ler(i) para obter o valor e incrementar a contagem, " +
        "sem usar lista_comparar.",
    };
  }

  // Invariante 3: exatamente n escritas em posições sequenciais 0..n-1
  if (writes.length < n) {
    return {
      match: false,
      failReason:
        `Apenas ${writes.length} escrita(s) detectada(s), mas a lista tem ${n} elementos. ` +
        "O Counting Sort precisa reescrever todos os elementos na lista de saída. " +
        "Verifique se o loop de reconstrução percorre todas as contagens e escreve os valores na ordem certa.",
    };
  }

  // Pega as últimas n escritas (a reconstrução final, caso haja escritas auxiliares antes)
  const lastNWrites = writes.slice(-n);
  const isSequential = lastNWrites.every((e, idx) => e.i === idx);
  if (!isSequential) {
    return {
      match: false,
      failReason:
        "As escritas na lista não foram sequenciais (posições 0, 1, 2, ..., n-1 em ordem). " +
        "O Counting Sort reconstrói a lista escrevendo cada valor na próxima posição livre (pos++). " +
        "Verifique se o loop de reconstrução incrementa a posição a cada escrita.",
    };
  }

  // Invariante 4: pelo menos n leituras (contagem dos valores originais)
  if (reads.length < n) {
    return {
      match: false,
      failReason:
        `Apenas ${reads.length} leitura(s) detectada(s), mas a lista tem ${n} elementos. ` +
        "O Counting Sort deve ler cada elemento da lista original para incrementar sua contagem.",
    };
  }

  return { match: true };
}
