package io.kotest.property.arbitrary

import io.kotest.property.Arb
import io.kotest.property.Shrinker

/**
 * Returns an [Arb] which returns range that contain values generated by the given generator.
 * The resulting range is determined as subrange specified [domain] argument.
 *
 * The edge cases are empty range and single element ranges consisting of first and last [domain] elements
 *
 * Shrinking is performed by moving range edges until the empty range is reached.
 */
fun Arb.Companion.intRange(domain: IntRange): Arb<IntRange> {
   return arbitrary(
      edgecases = listOf(IntRange.EMPTY),
      shrinker = IntRangeShrinker()
   ) { randomSource ->
      val actualMin = randomSource.random.nextInt(domain.first, domain.last + 1)
      val actualMax = randomSource.random.nextInt(actualMin, domain.last + 1)
      actualMin..actualMax
   }
}

/**
 * A Shrinker for [IntRange]. The candidates at each step include:
 *  - the empty range
 *  - range with start edge move forward by 1
 *  - range with end edge moved backward by 1
 */
class IntRangeShrinker : Shrinker<IntRange> {

   override fun shrink(value: IntRange): List<IntRange> {
      if (value.isEmpty()) {
         return emptyList()
      }

      return listOf(
         value.first until value.last,
         value.first + 1..value.last,
         IntRange.EMPTY,
      ).distinct()
   }
}
