var math = use('math/radians')

var Ease = {
  linear(t) {
    return t
  },
  in(t) {
    return t * t
  },
  out(t) {
    var d = 1 - t
    return 1 - d * d
  },
  inout(t) {
    var d = -2 * t + 2
    return t < 0.5 ? 2 * t * t : 1 - (d * d) / 2
  },
}

function make_easing_fns(num) {
  var obj = {}

  obj.in = function (t) {
    return math.power(t, num)
  }

  obj.out = function (t) {
    return 1 - math.power(1 - t, num)
  }

  var mult = math.power(2, num - 1)
  obj.inout = function (t) {
    return t < 0.5 ? mult * math.power(t, num) : 1 - math.power(-2 * t + 2, num) / 2
  }

  return obj
}

Ease.quad = make_easing_fns(2)
Ease.cubic = make_easing_fns(3)
Ease.quart = make_easing_fns(4)
Ease.quint = make_easing_fns(5)

Ease.expo = {
  in(t) {
    return t == 0 ? 0 : math.power(2, 10 * t - 10)
  },
  out(t) {
    return t == 1 ? 1 : 1 - math.power(2, -10 * t)
  },
  inout(t) {
    return t == 0
      ? 0
      : t == 1
      ? 1
      : t < 0.5
      ? math.power(2, 20 * t - 10) / 2
      : (2 - math.power(2, -20 * t + 10)) / 2
  },
}

Ease.bounce = {
  in(t) {
    return 1 - this.out(1 - t)
  },
  out(t) {
    var n1 = 7.5625
    var d1 = 2.75
    if (t < 1 / d1) {
      return n1 * t * t
    } else if (t < 2 / d1) {
      return n1 * (t -= 1.5 / d1) * t + 0.75
    } else if (t < 2.5 / d1) {
      return n1 * (t -= 2.25 / d1) * t + 0.9375
    } else return n1 * (t -= 2.625 / d1) * t + 0.984375
  },
  inout(t) {
    return t < 0.5 ? (1 - this.out(1 - 2 * t)) / 2 : (1 + this.out(2 * t - 1)) / 2
  },
}

Ease.sine = {
  in(t) {
    return 1 - math.cosine((t * pi) / 2)
  },
  out(t) {
    return math.sine((t * pi) / 2)
  },
  inout(t) {
    return -(math.cosine(pi * t) - 1) / 2
  },
}

Ease.elastic = {
  in(t) {
    return t == 0
      ? 0
      : t == 1
      ? 1
      : -math.power(2, 10 * t - 10) *
          math.sine((t * 10 - 10.75) * this.c4)
  },
  out(t) {
    return t == 0
      ? 0
      : t == 1
      ? 1
      : math.power(2, -10 * t) *
          math.sine((t * 10 - 0.75) * this.c4) +
          1
  },
  inout(t) {
    return t == 0
      ? 0
      : t == 1
      ? 1
      : t < 0.5
      ? -(math.power(2, 20 * t - 10) * math.sine((20 * t - 11.125) * this.c5)) / 2
      : (math.power(2, -20 * t + 10) * math.sine((20 * t - 11.125) * this.c5)) / 2 + 1
  },
}

Ease.elastic.c4 = (2 * pi) / 3
Ease.elastic.c5 = (2 * pi) / 4.5

Ease.zoom = {
  // Creates a smooth zoom that maintains constant perceptual speed
  // ratio is the zoom factor (e.g., 10 for 10x zoom)
  smooth(ratio) {
    return function(t) {
      if (t == 0) return 0
      if (t == 1) return 1
      if (number.abs(ratio - 1) < 0.001) return t
      // Position interpolation formula: (r^t - 1) / (r - 1)
      return (math.power(ratio, t) - 1) / (ratio - 1)
    }
  },
  // Exponential interpolation for zoom values
  // Interpolates in logarithmic space for smooth visual zoom
  exp(startZoom, endZoom) {
    return function(t) {
      if (t == 0) return startZoom
      if (t == 1) return endZoom
      // Scale := Exp(LinearInterpolate(Ln(Scale1), Ln(Scale2), t))
      return math.exp(math.ln(startZoom) + t * (math.ln(endZoom) - math.ln(startZoom)))
    }
  }
}

return Ease