@function __base-is-match(
  $map,
  $props,
  $values,
  $strict-compare-flags: (),
  $customizer: false
) {
  $length: length($props);
  $result: null;

  @if ($map == null) {
    @return if($length == 0 or $length == null, false, true);
  }

  $index: 1;
  $no-customizer: if($customizer, false, true);

  @while ($index <= $length) {
    @if if(
      (
        $no-customizer and
          length($strict-compare-flags) >
          0 and
          nth($strict-compare-flags, $index)
      ),
      (nth($values, $index) != __get($map, nth($props, $index))),
      (not map-has-key($map, nth($props, $index)))
    )
    {
      @return false;
    }

    $index: $index + 1;
  }

  $index: 1;

  @while ($index <= $length) {
    $key: nth($props, $index);

    @if $no-customizer and nth($strict-compare-flags, $index) {
      $result: map-has-key($map, $key);
    } @else {
      $map-value: __get($map, $key);
      $src-value: nth($values, $index);
      $result: if(
        $customizer,
        __exec($customizer, $map-value, $src-value, $key),
        null
      );

      @if ($result == null) {
        $result: __call(
          __base-is-equal,
          null,
          $src-value,
          $map-value,
          $customizer,
          true
        );
      }
    }

    @if (not $result) {
      @return false;
    }

    $index: $index + 1;
  }

  @return true;
}

@function __is-match($map, $source, $customizer: null, $this-arg: null) {
  $props: __keys($source);
  $length: length($props);

  @if __is-falsey($map) {
    @return __is-empty($source);
  }

  $customizer: if(
    __is-function($customizer),
    __bind-callback($customizer, $this-arg, 3),
    false
  );

  @if (not $customizer and $length == 1) {
    $key: nth($props, 1);
    $value: __get($source, $key);

    @if (__is-strict-comparable($value)) {
      @return if(
        $map != null and $value == __get($map, $key),
        map-has-key($map, $key),
        false
      );
    }
  }

  $values: ();
  $strict-compare-flags: ();

  @while ($length > 0) {
    $value: __get($source, nth($props, $length));
    $values: __set($values, $length, $value);
    $strict-compare-flags: __set(
      $strict-compare-flags,
      $length,
      __is-strict-comparable($value)
    );
    $length: $length - 1;
  }

  $values: __to-list($values);
  $strict-compare-flags: __to-list($strict-compare-flags);

  @return __base-is-match(
    $map,
    $props,
    $values,
    $strict-compare-flags,
    $customizer
  );
}

/// Performs a deep comparison between `$map` and `source` to determine if
/// `$map` contains equivalent property values. If `$customizer` is provided
/// it is invoked to compare values. If `$customizer` returns `undefined`
/// comparisons are handled by the method instead. The `$customizer` is bound
/// to `$this-arg` and invoked with three arguments; (value, other, index|key).
///
///
/// @access public
/// @group Lang
/// @param {Map} $map The map to inspect.
/// @param {Map} $source The map of property values to match.
/// @param {Function} $customizer [null] The function to customize comparing values.
/// @param {*} $this-arg [null] - The `_this` binding of `$customizer`.
/// @returns {boolean} Returns `true` if `$map` is a match, else `false`.
/// @example scss
/// $map: ( 'user': 'fred', 'age': 40 );
///
/// _is-match($map, ( 'age': 40 ));
/// // => true
///
/// _is-match($map, ( 'age': 36 ));
/// // => false
///
/// // using a customizer callback
/// // todo

@function _is-match($args...) {
  @return call(get-function("__is-match"), $args...);
}
