// sorting.cm — Sorting and searching kernel
// Array manipulation, comparison-heavy, allocation patterns.

function make_random_array(n, seed) {
  var a = []
  var x = seed
  var i = 0
  for (i = 0; i < n; i++) {
    x = ((x * 1103515245 + 12345) & 0x7FFFFFFF) | 0
    push(a, x % 10000)
  }
  return a
}

function make_descending(n) {
  var a = []
  var i = 0
  for (i = n - 1; i >= 0; i--) push(a, i)
  return a
}

// Manual quicksort (tests recursion + array mutation)
function qsort(arr, lo, hi) {
  var i = lo
  var j = hi
  var pivot = arr[floor((lo + hi) / 2)]
  var tmp = 0
  if (lo >= hi) return null
  while (i <= j) {
    while (arr[i] < pivot) i++
    while (arr[j] > pivot) j--
    if (i <= j) {
      tmp = arr[i]
      arr[i] = arr[j]
      arr[j] = tmp
      i++
      j--
    }
  }
  if (lo < j) qsort(arr, lo, j)
  if (i < hi) qsort(arr, i, hi)
  return null
}

// Merge sort (tests allocation + array creation)
function msort(arr) {
  var n = length(arr)
  if (n <= 1) return arr
  var mid = floor(n / 2)
  var left = msort(array(arr, 0, mid))
  var right = msort(array(arr, mid, n))
  return merge(left, right)
}

function merge(a, b) {
  var result = []
  var i = 0
  var j = 0
  while (i < length(a) && j < length(b)) {
    if (a[i] <= b[j]) {
      push(result, a[i])
      i++
    } else {
      push(result, b[j])
      j++
    }
  }
  while (i < length(a)) {
    push(result, a[i])
    i++
  }
  while (j < length(b)) {
    push(result, b[j])
    j++
  }
  return result
}

// Binary search
function bsearch(arr, target) {
  var lo = 0
  var hi = length(arr) - 1
  var mid = 0
  while (lo <= hi) {
    mid = floor((lo + hi) / 2)
    if (arr[mid] == target) return mid
    if (arr[mid] < target) lo = mid + 1
    else hi = mid - 1
  }
  return -1
}

// Sort objects by field
function sort_records(n) {
  var records = []
  var x = 42
  var i = 0
  for (i = 0; i < n; i++) {
    x = ((x * 1103515245 + 12345) & 0x7FFFFFFF) | 0
    push(records, {id: i, score: x % 10000, name: `item_${i}`})
  }
  return sort(records, "score")
}

return {
  // Quicksort 1K random integers
  qsort_1k: function(n) {
    var i = 0
    var a = null
    for (i = 0; i < n; i++) {
      a = make_random_array(1000, i)
      qsort(a, 0, length(a) - 1)
    }
    return a
  },

  // Quicksort 10K random integers
  qsort_10k: function(n) {
    var i = 0
    var a = null
    for (i = 0; i < n; i++) {
      a = make_random_array(10000, i)
      qsort(a, 0, length(a) - 1)
    }
    return a
  },

  // Merge sort 1K (allocation heavy)
  msort_1k: function(n) {
    var i = 0
    var result = null
    for (i = 0; i < n; i++) {
      result = msort(make_random_array(1000, i))
    }
    return result
  },

  // Built-in sort 1K
  builtin_sort_1k: function(n) {
    var i = 0
    var result = null
    for (i = 0; i < n; i++) {
      result = sort(make_random_array(1000, i))
    }
    return result
  },

  // Sort worst case (descending → ascending)
  sort_worst_case: function(n) {
    var i = 0
    var a = null
    for (i = 0; i < n; i++) {
      a = make_descending(1000)
      qsort(a, 0, length(a) - 1)
    }
    return a
  },

  // Binary search in sorted array
  bsearch_1k: function(n) {
    var sorted = make_random_array(1000, 42)
    sorted = sort(sorted)
    var found = 0
    var i = 0
    for (i = 0; i < n; i++) {
      if (bsearch(sorted, sorted[i % 1000]) >= 0) found++
    }
    return found
  },

  // Sort records by field
  sort_records_500: function(n) {
    var i = 0
    var result = null
    for (i = 0; i < n; i++) {
      result = sort_records(500)
    }
    return result
  }
}
