/**
 * @fileoverview Proxy de array com rastreamento de eventos para validação de ordenação.
 *
 * Objetivo: instrumentar a lista real da atividade (blocos nativos do Blockly)
 * sem exigir API customizada (`compare`, `swap`, etc.).
 *
 * Eventos gerados no historico:
 *   - read  { type: "read", i }
 *   - write { type: "write", i, value }
 *   - swap  { type: "swap", i, j } (inferido por par de writes)
 */

function isArrayIndex(prop) {
  if (typeof prop === "symbol") return false;
  if (prop === "length") return false;
  const n = Number(prop);
  return Number.isInteger(n) && n >= 0;
}

/**
 * Cria um Proxy que sincroniza mutações no array original e registra eventos no historico.
 *
 * @param {number[]} originalArray
 * @param {Array} historico
 * @param {{ trackReads?: boolean, inferSwap?: boolean }} [options]
 * @returns {Proxy}
 */
export function createTraceableArrayProxy(originalArray, historico, options = {}) {
  const trackReads = options.trackReads !== false;
  const inferSwap = options.inferSwap !== false;

  const target = [...originalArray];

  // Guarda a última escrita para inferir swap por padrão de dupla atribuição.
  let lastWrite = null;

  return new Proxy(target, {
    get(arr, prop, receiver) {
      if (isArrayIndex(prop)) {
        const i = Number(prop);
        if (trackReads) historico.push({ type: "read", i });
        // Se houve leitura entre duas escritas, não é uma troca direta típica.
        lastWrite = null;
      }
      return Reflect.get(arr, prop, receiver);
    },

    set(arr, prop, value, receiver) {
      if (isArrayIndex(prop)) {
        const i = Number(prop);
        const oldValue = arr[i];

        // Atualiza array da cena e array do proxy
        originalArray[i] = value;
        const ok = Reflect.set(arr, prop, value, receiver);

        historico.push({ type: "write", i, value });

        if (inferSwap) {
          if (
            lastWrite &&
            lastWrite.i !== i &&
            lastWrite.oldValue === value &&
            oldValue === lastWrite.newValue
          ) {
            historico.push({ type: "swap", i: lastWrite.i, j: i });
            lastWrite = null;
          } else {
            lastWrite = { i, oldValue, newValue: value };
          }
        }

        return ok;
      }

      lastWrite = null;
      return Reflect.set(arr, prop, value, receiver);
    },
  });
}
