/**
 * @fileoverview Perfil de detecção: Insertion Sort.
 *
 * Dois variantes são aceitos:
 *
 * Variante A — Deslocamento (shift):
 *   O aluno lê a chave com vm.read(i), depois desloca elementos para a direita
 *   com vm.write(j+1, vm.read(j)) até encontrar a posição correta.
 *   Sinal: writeCount >= n-1 e swapCount === 0.
 *
 * Variante B — Trocas adjacentes para trás:
 *   O aluno usa vm.compare(j-1, j, ">") + vm.swap(j-1, j) e j-- até o lugar certo.
 *   Sinal: todas as trocas são adjacentes E o padrão de comparações é decrescente
 *   (índices caem dentro de cada inserção).
 *
 * Variações aceitas:
 *   - Variante A ou B indiferentemente.
 *   - Inserção encerrada antes do fim do array (elemento já na posição certa).
 *
 * O que NÃO é aceito:
 *   - Trocas não adjacentes na variante B.
 *   - Writes sem reads correspondentes (escrita sem deslocamento real).
 *   - Ausência de qualquer padrão de retrocesso (sem reads+writes nem backward swaps).
 */

const MIN_WRITE_THRESHOLD = 0; // escrita mínima para variant A (pode ser 0 se lista já quase ordenada)

/**
 * @param {import("../core/ExecutionTrace.js").TraceEvent[]} trace
 * @param {number} n - Tamanho da lista.
 * @returns {{ match: boolean, variant?: string, failReason?: string }}
 */
export function insertionProfile(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");

  if (compares.length === 0 && swaps.length === 0 && writes.length === 0) {
    return {
      match: false,
      failReason:
        "Nenhuma operação relevante detectada. O Insertion Sort lê cada elemento, " +
        "desloca os maiores para a direita e insere o elemento na posição correta.",
    };
  }

  // ── Variante A: deslocamento (writes dominam, sem swaps) ──────────────────
  // Requer reads >= n-1 para confirmar que os deslocamentos são reais.
  // Sem reads, pode ser cheat sort ou outra solução inválida.
  if (swaps.length === 0 && writes.length >= n - 1 && reads.length >= n - 1) {
    return { match: true, variant: "shift" };
  }

  // ── Variante B: trocas adjacentes para trás ────────────────────────────────
  if (swaps.length > 0) {
    // Todas as trocas devem ser adjacentes
    const nonAdjacentSwap = swaps.find(e => Math.abs(e.i - e.j) !== 1);
    if (nonAdjacentSwap) {
      return {
        match: false,
        failReason:
          `Troca não adjacente detectada (posições ${nonAdjacentSwap.i} e ${nonAdjacentSwap.j}). ` +
          "O Insertion Sort na variante de trocas opera apenas com elementos vizinhos (j-1 e j).",
      };
    }

    // Verificar padrão de retrocesso: comparações com índices decrescentes
    // Conta pares consecutivos de comparações onde o índice mínimo cai
    let backwardPairs = 0;
    let forwardPairs = 0;
    for (let k = 1; k < compares.length; k++) {
      const prevMin = Math.min(compares[k - 1].i, compares[k - 1].j);
      const currMin = Math.min(compares[k].i,     compares[k].j);
      if (currMin < prevMin) backwardPairs++;
      if (currMin > prevMin) forwardPairs++;
    }

    // Sinal forte de inserção: retrocesso presente
    if (backwardPairs > 0) {
      return { match: true, variant: "swap-backward" };
    }

    // Lista quase ordenada: poucos elementos precisaram se mover,
    // então o padrão de retrocesso pode não aparecer. Ainda assim,
    // se as trocas foram poucas (≤ n-1), aceitar como possível insertion sort.
    if (swaps.length <= n - 1 && forwardPairs === 0) {
      return { match: true, variant: "swap-minimal" };
    }

    // Apenas trocas para frente com muitas trocas → provavelmente Bubble Sort
    return {
      match: false,
      failReason:
        "O padrão de trocas adjacentes é progressivo (esquerda → direita), não regressivo. " +
        "O Insertion Sort deve mover cada elemento para trás até encontrar sua posição — " +
        "use j-- no loop interno, com comparações do tipo arr[j-1] > arr[j].",
    };
  }

  // Writes presentes mas poucos e sem swaps (lista quase ordenada, poucos elementos movidos)
  if (writes.length > 0 && reads.length > 0) {
    return { match: true, variant: "shift-partial" };
  }

  return {
    match: false,
    failReason:
      "O padrão de operações não corresponde ao Insertion Sort. " +
      "Verifique se cada elemento é inserido na posição correta: " +
      "desloque os maiores com vm.write(j+1, vm.read(j)) ou use trocas regressivas (j--).",
  };
}
