///|
pub let map_methods : Map[String, RuntimeFunction] = {
  "at": map_at_fn,
  "capacity": map_capacity_fn,
  "clear": map_clear_fn,
  "contains": map_contains_fn,
  "contains_kv": map_contains_kv_fn,
  "copy": map_copy_fn,
  "each": map_each_fn,
  "eachi": map_eachi_fn,
  "from_array": map_from_array_fn,
  "from_iter": map_from_iter_fn,
  "get": map_get_fn,
  "get_from_bytes": map_get_from_bytes_fn,
  "get_from_string": map_get_from_string_fn,
  "get_or_default": map_get_or_default_fn,
  "get_or_init": map_get_or_init_fn,
  "is_empty": map_is_empty_fn,
  "iter": map_iter_fn,
  "iter2": map_iter2_fn,
  "keys": map_keys_fn,
  "length": map_length_fn,
  "map": map_map_fn,
  "merge": map_merge_fn,
  "merge_in_place": map_merge_in_place_fn,
  "new": map_new_fn,
  "of": map_of_fn,
  "remove": map_remove_fn,
  "retain": map_retain_fn,
  "set": map_set_fn,
  "to_array": map_to_array_fn,
  "update": map_update_fn,
  "values": map_values_fn,
  "output": map_output_fn,
}

///|
fn map_from_pairs(iter : Iter[RuntimeValue]) -> Map[RuntimeValue, RuntimeValue] {
  let map = {}
  iter.each(fn(item) {
    match item {
      Tuple([key, val]) => map.set(key, val)
      _ => ()
    }
  })
  map
}

///|
/// Map clear操作
let map_clear_fn : RuntimeFunction = ctx => {
  match ctx.args {
    [{ val: Map(map), .. }] => {
      map.clear()
      Unit
    }
    _ => Unit
  }
}

///|
/// Map is_empty操作
let map_is_empty_fn : RuntimeFunction = ctx => {
  match ctx.args {
    [{ val: Map(map), .. }] => Bool(map.is_empty())
    _ => Unit
  }
}

///|
/// Map capacity操作
let map_capacity_fn : RuntimeFunction = ctx => {
  match ctx.args {
    [{ val: Map(map), .. }] => Int(map.capacity(), raw=None)
    _ => Unit
  }
}

///|
/// Map contains操作
let map_contains_fn : RuntimeFunction = ctx => {
  match ctx.args {
    [{ val: Map(map), .. }, { val: key, .. }] => Bool(map.contains(key))
    _ => Unit
  }
}

///|
/// Map contains_kv操作
let map_contains_kv_fn : RuntimeFunction = ctx => {
  match ctx.args {
    [{ val: Map(map), .. }, { val: key, .. }, { val, .. }] =>
      Bool(map.get(key) == Some(val))
    _ => Unit
  }
}

///|
/// Map copy操作
let map_copy_fn : RuntimeFunction = ctx => {
  match ctx.args {
    [{ val: Map(map), .. }] => Map(map.copy())
    _ => Unit
  }
}

///|
/// Map each操作
let map_each_fn : RuntimeFunction = ctx => {
  match ctx.args {
    [{ val: Map(map), .. }, { val: Fn(f), .. }] => {
      map.each((key, val) => {
        ctx.context.call(f.val, ctx.pkg, [
          { val: key, kind: Positional },
          { val, kind: Positional },
        ])
        |> ignore
      })
      Unit
    }
    _ => Unit
  }
}

///|
/// Map eachi操作
let map_eachi_fn : RuntimeFunction = ctx => {
  match ctx.args {
    [{ val: Map(map), .. }, { val: Fn(f), .. }] => {
      map.eachi((i, key, val) => {
        ctx.context.call(f.val, ctx.pkg, [
          { val: Int(i, raw=None), kind: Positional },
          { val: key, kind: Positional },
          { val, kind: Positional },
        ])
        |> ignore
      })
      Unit
    }
    _ => Unit
  }
}

///|
/// Map from_array操作
let map_from_array_fn : RuntimeFunction = ctx => {
  match ctx.args {
    [{ val: Array(arr), .. }] => Map(map_from_pairs(arr.iter()))
    [{ val: ArrayView(arr), .. }] => Map(map_from_pairs(arr.iter()))
    [{ val: FixedArray(arr), .. }] => Map(map_from_pairs(arr.iter()))
    _ => Unit
  }
}

///|
/// Map at操作
let map_at_fn : RuntimeFunction = ctx => {
  match ctx.args {
    [{ val: Map(map), .. }, { val: key, .. }] => map.at(key)
    _ => Unit
  }
}

///|
/// Map from_iter操作
let map_from_iter_fn : RuntimeFunction = ctx => {
  match ctx.args {
    [{ val: Iter(iter), .. }] =>
      Map(
        Map::from_iter(
          iter.map(item => {
            match item {
              Tuple([key, val]) => (key, val)
              _ => panic()
            }
          }),
        ),
      )
    _ => Unit
  }
}

///|
/// Map get操作
let map_get_fn : RuntimeFunction = ctx => {
  match ctx.args {
    [{ val: Map(map), .. }, { val: key, .. }] =>
      RuntimeValue::from_option(map.get(key))
    _ => Unit
  }
}

///|
/// Map get_from_bytes操作
let map_get_from_bytes_fn : RuntimeFunction = ctx => {
  match ctx.args {
    [{ val: Map(map), .. }, { val: Bytes(bytes), .. }] =>
      RuntimeValue::from_option(map.get(Bytes(bytes)))
    _ => RuntimeValue::from_option(None)
  }
}

///|
/// Map get_from_string操作
let map_get_from_string_fn : RuntimeFunction = ctx => {
  match ctx.args {
    [{ val: Map(map), .. }, { val: StringView(view), .. }] =>
      RuntimeValue::from_option(map.get(String(view.to_owned())))
    [{ val: Map(map), .. }, { val: String(string), .. }] =>
      RuntimeValue::from_option(map.get(String(string)))
    _ => RuntimeValue::from_option(None)
  }
}

///|
/// Map get_or_default操作
let map_get_or_default_fn : RuntimeFunction = ctx => {
  match ctx.args {
    [{ val: Map(map), .. }, { val: key, .. }, { val: default, .. }] =>
      match map.get(key) {
        Some(val) => val
        None => default
      }
    _ => Unit
  }
}

///|
/// Map get_or_init操作
let map_get_or_init_fn : RuntimeFunction = ctx => {
  match ctx.args {
    [{ val: Map(map), .. }, { val: key, .. }, { val: Fn(f), .. }] =>
      match map.get(key) {
        Some(val) => val
        None => {
          let val = ctx.context.call(f.val, ctx.pkg, [])
          map.set(key, val)
          val
        }
      }
    _ => Unit
  }
}

///|
/// Map iter操作
let map_iter_fn : RuntimeFunction = ctx => {
  match ctx.args {
    [{ val: Map(self), .. }] =>
      Iter(
        self
        .iter()
        .map(item => {
          match item {
            (key, val) => Tuple([key, val])
          }
        }),
      )
    _ => Unit
  }
}

///|
/// Map iter2操作
let map_iter2_fn : RuntimeFunction = ctx => {
  match ctx.args {
    [{ val: Map(self), .. }] => Iter2(self.iter2())
    _ => Unit
  }
}

///|
/// Map keys操作
let map_keys_fn : RuntimeFunction = ctx => {
  match ctx.args {
    [{ val: Map(map), .. }] => Iter(map.keys())
    _ => Unit
  }
}

///|
/// Map length操作
let map_length_fn : RuntimeFunction = ctx => {
  match ctx.args {
    [{ val: Map(map), .. }] => Int(map.length(), raw=None)
    _ => Unit
  }
}

///|
/// Map map操作
let map_map_fn : RuntimeFunction = ctx => {
  match ctx.args {
    [{ val: Map(map), .. }, { val: Fn(f), .. }] => {
      let new_map = {}
      map.each((key, val) => {
        let new_val = ctx.context.call(f.val, ctx.pkg, [
          { val: key, kind: Positional },
          { val, kind: Positional },
        ])
        new_map.set(key, new_val)
      })
      Map(new_map)
    }
    _ => Unit
  }
}

///|
/// Map merge操作
let map_merge_fn : RuntimeFunction = ctx => {
  match ctx.args {
    [{ val: Map(left), .. }, { val: Map(right), .. }] => Map(left.merge(right))
    _ => Unit
  }
}

///|
/// Map merge_in_place操作
let map_merge_in_place_fn : RuntimeFunction = ctx => {
  match ctx.args {
    [{ val: Map(left), .. }, { val: Map(right), .. }] => {
      left.merge_in_place(right)
      Unit
    }
    _ => Unit
  }
}

///|
/// Map new操作
let map_new_fn : RuntimeFunction = ctx => {
  match ctx.args {
    [{ val: Int(capacity, ..), kind: LabelledOption("capacity") }] =>
      Map(Map([], capacity~))
    [{ val: Int(capacity, ..), .. }] => Map(Map([], capacity~))
    _ => Map({})
  }
}

///|
/// Map of操作
let map_of_fn : RuntimeFunction = ctx => {
  match ctx.args {
    [{ val: Array(arr), .. }] => Map(map_from_pairs(arr.iter()))
    [{ val: ArrayView(arr), .. }] => Map(map_from_pairs(arr.iter()))
    [{ val: FixedArray(arr), .. }] => Map(map_from_pairs(arr.iter()))
    _ => error("Map of: (arr: T)")
  }
}

///|
/// Map remove操作
let map_remove_fn : RuntimeFunction = ctx => {
  match ctx.args {
    [{ val: Map(map), .. }, { val: key, .. }] => {
      map.remove(key)
      Unit
    }
    _ => Unit
  }
}

///|
/// Map retain操作
let map_retain_fn : RuntimeFunction = ctx => {
  match ctx.args {
    [{ val: Map(map), .. }, { val: Fn(f), .. }] => {
      map.retain(fn(key, val) {
        try {
          match
            ctx.context.call(f.val, ctx.pkg, [
              { val: key, kind: Positional },
              { val, kind: Positional },
            ]) {
            Bool(b) => b
            _ => false
          }
        } catch {
          _ => false
        }
      })
      Unit
    }
    _ => Unit
  }
}

///|
/// Map set操作
let map_set_fn : RuntimeFunction = ctx => {
  match ctx.args {
    [{ val: Map(map), .. }, { val: key, .. }, { val, .. }] => {
      map.set(key, val)
      Unit
    }
    _ => Unit
  }
}

///|
/// Map to_array操作
let map_to_array_fn : RuntimeFunction = ctx => {
  match ctx.args {
    [{ val: Map(map), .. }] => {
      let arr : Array[RuntimeValue] = Array::new()
      map.each(fn(key, val) { arr.push(Tuple([key, val])) })
      Array(arr)
    }
    _ => Unit
  }
}

///|
/// Map update操作
let map_update_fn : RuntimeFunction = ctx => {
  match ctx.args {
    [{ val: Map(map), .. }, { val: key, .. }, { val: Fn(f), .. }] => {
      let current = map.get(key)
      let result = ctx.context.call(f.val, ctx.pkg, [
        { val: RuntimeValue::from_option(current), kind: Positional },
      ])
      match result {
        Constructor(
          { val: { name: "Some", fields: [{ value: new_value, .. }] }, .. }
        ) => map.set(key, new_value)
        Constructor({ val: { name: "None", fields: [] }, .. }) =>
          if current is Some(_) {
            map.remove(key)
          }
        _ => ()
      }
      Unit
    }
    _ => Unit
  }
}

///|
/// Map values操作
let map_values_fn : RuntimeFunction = ctx => {
  match ctx.args {
    [{ val: Map(map), .. }] => Iter(map.values())
    _ => Unit
  }
}

///|
let map_output_fn : RuntimeFunction = ctx => {
  match ctx.args {
    [{ val: Map(map), .. }, { val: StringBuilder(logger), .. }] => {
      logger.write_string(Map(map).to_string())
      Unit
    }
    _ => Unit
  }
}