@use "sass:math";
@use "sass:list";
@use "sass:map";
@use "sass:meta";

/// list模块扩展
/// @function list-sub($list, $start, $count: false)
/// @function list-subset($list, $start, $end: false)
/// @function list-remove($list, $args...)
/// @function list-insert($list, $start, $args...)
/// @function list-splice($list, $start, $count: false, $args...)
/// @function list-extend($lists..., $separator, $bracketed)
/// @function list-each($list, $callback: null)
/// @function list-sort($list, $order: ascend)
/// @function list-reverse($list, $separator: false, $bracketed: false)
/// -----------------------------------------------------

/// 删除list中指定值
/// @access private
/// @param {list} $list list列表
/// @param {list} $item 需要删除项
/// @return {list} 删除后的list
/// @example `_remove-item((10, 20, 30), 20)`
/// -------------------------------------
@function _remove-item($list, $item) {
  $index: list.index($list, $item);
  
  @if $index {
    $list: _remove-item(list-sub($list, $index, 1), $item);
  }
  @return $list;
}

/// 通过索引截取list
///!⚠️ Sass索引从 `1` 开始.
/// @param {list} $list 待遍历的 list
/// @param {number} $start 开始索引
/// @param {number} $count 截取长度
/// @return {list} 截取后的 list
/// @example `list-sub((10, 20, 30, 40), 2, 1)`
/// @author Mervin <mengqing723@gmail.com>
/// @link https://github.com/meqn/sass-magic
/// -----------------------------------------------------
@function list-sub($list, $start, $count: false) {
  @if $start <= 0 or ($count and $count < 0) {
    @error "[list-sub]: The 'start' and 'count' parameter must be greater than 0.";
  }

  $length: list.length($list);
  $count: if($count, $count, $length - $start + 1);
  $end: $start + $count;
  
  @if $start > $length or $count == 0{
    @return $list;
  }
  
  $result: ();
  $separator: list.separator($list);
  @for $i from 1 through $length {
    @if $i < $start or $i >= $end {
      $result: list.append($result, list.nth($list, $i), $separator);
    }
  }
  @return $result;
}

/// 通过开始和结束索引截取list
/// @param {list} $list 待遍历的 list
/// @param {number} $start 开始索引
/// @param {number} $end 结束索引
/// @return {list} 截取后的 list
/// @example `list-subset((10, 20, 30, 40), 2, 3)`
/// @author Mervin <mengqing723@gmail.com>
/// @link https://github.com/meqn/sass-magic
/// -----------------------------------------------------
@function list-subset($list, $start, $end: false) {
  @if $start <= 0 or ($end and $end < 0) {
    @error "[list-subset]: The 'start' and 'end' parameter must be greater than 0.";
  }

  $length: list.length($list);
  
  @if not $end {
    $end: $length;
  } @else if $end < $start {
    @error "[list-subset]: The 'end' parameter must be greater than 'start'.";
  }

  $result: ();
  $separator: list.separator($list);
  @for $i from 1 through $length {
    @if $i < $start or $i > $end {
      $result: list.append($result, list.nth($list, $i), $separator);
    }
  }
  @return $result;
}

/// 删除list中指定值
/// @param {list} $list list列表
/// @param {list} $args... 需要删除的值
/// @return {list} 删除后的list
/// @example `list-remove((10, 20, 30, 40), 20, 30)`
/// @author Mervin <mengqing723@gmail.com>
/// @link https://github.com/meqn/sass-magic
/// -----------------------------------------------------
@function list-remove($list, $args...) {
  @if list.length($args) == 0 or list.length($list) == 0 {
    @return $list;
  }

  // 支持多参二次调用
  @if meta.type-of(list.nth($args, 1)) == arglist {
    $args: list.nth($args, 1);
  }

  @each $arg in $args {
    $list: _remove-item($list, $arg);
  }
  @return $list;
}

/// 在list任意位置插入值
/// @param {list} $list list列表
/// @param {number} $start 插入的位置
/// @param {list} $args... 需要插入的值
/// @return {list} 插入后的list
/// @example `list-insert((10, 20, 50, 60), 2, 30, 40)`
/// @author Mervin <mengqing723@gmail.com>
/// @link https://github.com/meqn/sass-magic
/// -----------------------------------------------------
@function list-insert($list, $start, $args...) {
  $listLength: list.length($list);
  $argsLength: list.length($args);
  $separator: list.separator($list);
  
  @if $argsLength == 0 {
    @return $list;
  }
  // 支持多参二次调用
  @if meta.type-of(list.nth($args, 1)) == arglist {
    $args: list.nth($args, 1);
    $argsLength: list.length($args);
  }

  @if $start <= 0 {
    @return list.join($args, $list, $separator);
  }
  @if ($start >= $listLength) {
    @return list.join($list, $args, $separator);
  }
  
  $result: ();
  @for $i from 1 through $listLength {
    $result: list.append($result, list.nth($list, $i), $separator);
    @if $i == $start {
      $result: list.join($result, $args, $separator);
    }
  }
  @return $result;
}

/// 删除或替换现有元素和添加新元素
/// @param {list} $list list列表
/// @param {number} $start 插入的位置
/// @param {number} $count 删除的个数
/// @param {list} $args... 需要插入的值
/// @return {list} 更改后的list
/// @example `list-splice((10, 20, 60, 40), 2, 1, 30)`
/// @author Mervin <mengqing723@gmail.com>
/// @link https://github.com/meqn/sass-magic
/// ----------------------------------------------------- 
@function list-splice($list, $start, $count: false, $args...) {
  $length: list.length($list);
  $argLength: list.length($args);

  // 1. 先删除
  $list: list-sub($list, $start, $count);
  @if $argLength and $argLength > 0 {
    // 支持多参二次调用
    @if meta.type-of(list.nth($args, 1)) == arglist {
      $args: list.nth($args, 1);
    }
    // 2. 再追加
    $start: $start - $count; // 计算插入位置
    $list: list-insert($list, $start, $args)
  }
  @return $list;
}

/// 合并list集合
/// @param {list} $lists... 待合并的 list集合
/// @param {string} $separator 分隔符
/// @param {boolean} $bracketed 是否有中括号 []
/// @return {list} 合并后的 list
/// @example `list-extend((10, 20, 30), (40, 50, 60), 'space')`
/// @author Mervin <mengqing723@gmail.com>
/// @link https://github.com/meqn/sass-magic
/// -----------------------------------------------------
@function list-extend($lists...) {
  $length: list.length($lists);

  @if not $length {
    @return ();
  }
  @if list.length($lists) == 1 {
    @return $lists;
  }

  $separator: auto;
  $bracketed: false;
  @if $length >= 3 {
    $last: list.nth($lists, $length);
    $secondLast: list.nth($lists, $length - 1);

    @if meta.type-of($last) == bool {
      $bracketed: $last;
      @if $secondLast == "space" or $secondLast == "comma" or $secondLast == "slash" {
        $separator: $secondLast;
        // 删除最后两项
        $lists: list-sub($lists, $length - 1);
      } @else {
        // 删除最后一项
        $lists: list-sub($lists, $length);
      }
    }
    @if $last == "space" or $last == "comma" or $last == "slash" {
      $separator: $last;
      // 删除最后一项
      $lists: list-sub($lists, $length);
    }
  }

  $result: ();
  @each $list in $lists {
    $result: list.join($result, $list, $separator, $bracketed);
  }
  @return $result;
}

/// 遍历并返回新的 list(map)
/// @param {string} $list 待遍历的 list(map)
/// @param {function} $callback 遍历回调, 通过`get-function(callbackName)`获取
/// @return {list | map} 新的 list(map)
/// @example scss
/// list-each((width: 100px, height: 100px), get-function('item-callback'))
/// @function item-callback($item, $index, $list) { @return list.nth($item, 2); }
/// @author Mervin <mengqing723@gmail.com>
/// @link https://github.com/meqn/sass-magic
///-----------------------------------------------------
@function list-each($list, $callback: null) {
  @if not $callback {
    @return $list;
  }

  @if meta.type-of($callback) != function {
    @error "[list-each]: The 'callback' parameter must be a function.";
  }

  $length: list.length($list);
  $separator: list.separator($list);
  $results: ();

  @for $i from 1 through $length {
    $current: list.nth($list, $i);
    $item: meta.call($callback, $current, $i, $list);

    @if meta.type-of($item) == map {
      $results: map.merge($results, $item);
    } @else {
      $results: list.append($results, $item, $separator);
    }
  }
  @return $results;
}

/// 遍历的回调函数
/// @access private
/// @param {any} $item 当前项
/// @param {number} $index 当前项索引
/// @param {list | map} $list 待遍历的 list(map)
@function _each-callback($item: null, $index: null, $list: null) {
  @return $item;
}

/// 快速排序 list
/// @param {list} $list list
/// @param {string} $order 排序方式，可选 'ascend' 或 'descend'
/// @return {list} 排序后的 list
/// @example `list-sort((20, 10, 50, 40), 'descend')`
/// @author Mervin <mengqing723@gmail.com>
/// @link https://github.com/meqn/sass-magic
///-----------------------------------------------------
@function list-sort($list, $order: ascend) {
  // 判断终止条件
  @if list.length($list) < 2 {
    @return $list;
  }

  @if $order != ascend and $order != descend {
    @error "[list-sort]: The 'order' parameter must be 'ascend' or 'descend'.";
  }

  $separator: list.separator($list);

  // 初始化左右数组
  $left: ();
  $right: ();

  // 取第一个作为 pivot
  $pivot: list.nth($list, 1);

  // 遍历列表,分割到左右数组
  @for $i from 2 through list.length($list) {
    $current: list.nth($list, $i);

    @if $order == ascend {
      @if $current < $pivot {
        $left: list.append($left, $current, $separator);
      } @else {
        $right: list.append($right, $current, $separator); 
      }
    } @else {
      // @else if $order == descend
      @if $current > $pivot {
        $left: list.append($left, $current, $separator);
      } @else {
        $right: list.append($right, $current, $separator);
      }
    }
  }

  // 递归排序左右数组
  $left: list-sort($left, $order);
  $right: list-sort($right, $order);

  // 拼接最终结果
  @return list.join(list.join($left, $pivot), $right, $separator);
}

/// 反转 list并返回新的 list
/// @param {list} $list 待反转的 list
/// @param {string} $separator 分隔符
/// @param {boolean} $bracketed 是否有中括号
/// @return {list} 反转后的 list
/// @example `list-reverse((10, 20, 30, 40), 'space', true)`
/// @author Mervin <mengqing723@gmail.com>
/// @link https://github.com/meqn/sass-magic
/// -----------------------------------------------------
@function list-reverse($list, $separator: false, $bracketed: false) {
  $result: ();
  $length: list.length($list);
  $separator: if($separator, $separator, list.separator($list));

  @for $i from $length through 1 {
    $result: list.append($result, list.nth($list, $i), $separator);
  }

  @if $bracketed {
    $bracketed: if($bracketed, $bracketed, auto);
    $result: list.join($result, (), $separator, $bracketed);
  }
  @return $result;
}
