@use 'sass:math';

@function pow($number, $exponent) {
  @if (round($exponent) != $exponent) {
    @return exp(strip-unit($exponent) * ln(strip-unit($number)));
  }

  $value: 1;

  @if $exponent > 0 {
    @for $i from 1 through $exponent {
      $value: $value * $number;
    }
  } @else if $exponent < 0 {
    @for $i from 1 through -$exponent {
      $value: math.div($value, $number);
    }
  }

  @return $value;
}

@function factorial($value) {
  $result: 1;

  @if $value == 0 {
    @return $result;
  }

  @for $index from 1 through $value {
    $result: $result * $index;
  }

  @return $result;
}

@function summation($iteratee, $input, $initial: 0, $limit: 100) {
  $sum: 0;

  @for $index from $initial to $limit {
    $sum: $sum + call($iteratee, $input, $index);
  }

  @return $sum;
}

@function exp-maclaurin($x, $n) {
  @return math.div(pow($x, $n), factorial($n));
}

@function exp($value) {
  @return summation(get-function('exp-maclaurin'), $value, 0, 100);
}

@function ln-maclaurin($x, $n) {
  @return math.div(pow(-1, $n + 1), $n) * (pow($x - 1, $n));
}

@function ln($value) {
  $ten-exp: 1;
  $ln-ten: 2.30258509;

  @while ($value > pow(10, $ten-exp)) {
    $ten-exp: $ten-exp + 1;
  }

  @return summation(get-function('ln-maclaurin'), math.div($value, pow(10, $ten-exp)), 1, 100) +
    $ten-exp * $ln-ten;
}

@function strip-unit($number) {
  @if type-of($number) == 'number' and not unitless($number) {
    @return math.div($number, ($number * 0 + 1));
  }

  @return $number;
}
