/**
 * @fileoverview Perfil de detecção: Selection Sort.
 *
 * Invariantes obrigatórios:
 *   1. swapCount <= n - 1 (no máximo uma troca por passada externa).
 *   2. compareCount >= n - 1 (a varredura interna sempre ocorre).
 *   3. Razão comparações/trocas acima do limiar mínimo (varredura interna presente).
 *
 * Variações aceitas:
 *   - Buscar o mínimo (ordenação crescente) ou o máximo (decrescente).
 *   - Trocas adjacentes ou não adjacentes.
 *   - Omitir troca quando mínimo já está na posição certa (swap guardado por condicional).
 *
 * O que NÃO é aceito:
 *   - Mais de n-1 trocas (descarta Bubble Sort mascarado como Selection).
 *   - Poucas comparações relativas às trocas (sem varredura interna real).
 */

const MIN_COMPARE_PER_SWAP_RATIO = 2.0;

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

  // Variante de escrita em massa sem swaps tende a Insertion/Shell/Counting, não Selection.
  if (swaps.length === 0 && writes.length > n) {
    return {
      match: false,
      failReason:
        "Muitas operações de escrita detectadas. O Selection Sort usa trocas simples, " +
        "não deslocamentos em massa.",
    };
  }

  // Invariante 1: no máximo n-1 trocas
  if (swaps.length > n - 1) {
    return {
      match: false,
      failReason:
        `${swaps.length} trocas detectadas, mas o Selection Sort realiza no máximo ${n - 1} trocas ` +
        "(uma por passada externa). Verifique se está trocando somente ao final de cada varredura.",
    };
  }

  // Modo atividade real: sem compare explícito (blocos nativos), usa reads + padrão de swaps.
  if (compares.length === 0) {
    if (swaps.length === 0) {
      return {
        match: false,
        failReason:
          "Nenhuma troca detectada. O Selection Sort normalmente realiza uma troca por passada " +
          "(ou nenhuma quando o mínimo já está na posição certa). Verifique se o índice do mínimo " +
          "está sendo encontrado e usado na troca final.",
      };
    }

    const nonAdjacentSwaps = swaps.filter(e => Math.abs(e.i - e.j) > 1).length;
    const nonAdjacentRatio = nonAdjacentSwaps / swaps.length;

    if (nonAdjacentRatio < 0.5) {
      return {
        match: false,
        failReason:
          "As trocas detectadas foram majoritariamente adjacentes. Isso não parece Selection Sort. " +
          "No Selection Sort, a troca principal normalmente ocorre entre a posição atual e o índice do mínimo.",
      };
    }

    if (reads.length < n) {
      return {
        match: false,
        failReason:
          "Poucas leituras para caracterizar a varredura do Selection Sort. " +
          "A cada passada, é preciso varrer a parte não ordenada buscando o menor valor.",
      };
    }

    // Selection costuma ter poucas escritas: ~2 por troca principal.
    // Muitas escritas indicam mais deslocamentos (Insertion/Shell) do que trocas pontuais.
    if (writes.length > 2 * (swaps.length + 1) + 2) {
      return {
        match: false,
        failReason:
          "Foram detectadas muitas escritas para um padrão de Selection Sort. " +
          "No Selection Sort, a escrita acontece principalmente na troca final de cada passada, " +
          "não em deslocamentos repetidos de elementos.",
      };
    }

    return { match: true };
  }

  // Invariante 3: razão mínima comparações/trocas
  const ratio = compares.length / Math.max(swaps.length, 1);
  if (ratio < MIN_COMPARE_PER_SWAP_RATIO) {
    return {
      match: false,
      failReason:
        `Poucas comparações em relação às trocas (${compares.length} comparações, ${swaps.length} trocas). ` +
        "O Selection Sort varre toda a parte não ordenada antes de cada troca — " +
        "o número de comparações deve ser bem maior que o de trocas.",
    };
  }

  // Sinal adicional: comparações não adjacentes indicam varredura interna (compare j vs minIdx)
  // O Selection Sort geralmente gera compare(j, minIdx) onde j-minIdx > 1 em muitos casos.
  // Mas isso é um sinal de reforço, não um critério de reprovação isolado.

  return { match: true };
}
