@use 'sass:list';
@use 'sass:math';
@use 'sass:meta';
@use '../utils/array';
@use '../utils/units';
@use '../convert';

@function normalize(
  $lch,
) {
  $lch: list.set-nth($lch, 3, units.to-degrees(list.nth($lch, 3)));
  @return units.strip-all($lch);
}

@function _channel-in_srgb(
  $is,
  $val,
  $range: 0 1,
) {
  $E: 0.000005;
  @return $is and ($val == math.clamp(0 - $E, $val, 1 + $E));
}

@function in-srgb(
  $rgb
) {
  @return array.reduce(
    $rgb,
    meta.get-function('_channel-in_srgb'),
    true
  );
}

@function to-srgb(
  $lch,
  $check-gamut: false
) {
  $result: convert.LCH_to_sRGB($lch);

  @if ($check-gamut) {
    @return if(in-srgb($result), $result, null);
  }

  @return $result;
}

// gamut correction
@function gamut-correct(
  $l, $c, $h
) {
  // Moves an lch color into the sRGB gamut
  // by holding the l and h steady,
  // and adjusting the c via binary-search
  // until the color is on the sRGB boundary.
  $output: to-srgb($l $c $h, true);

  @if (not $output) {
    $hiC: $c;
    $loC: 0;

    $c: $c * 0.5;

    // 0.0001 chosen fairly arbitrarily as "close enough"
    @while (($hiC - $loC) > 0.0001) {
      @if to-srgb($l $c $h, true) {
        $loC: $c;
      } @else {
        $hiC: $c;
      }
      $c: ($hiC + $loC) * 0.5;
    }

    $output: to-srgb($l $c $h);
  }

  @return $output;
}
