// Copyright 2026 International Digital Economy Academy
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

///|
pub enum Json {
  Null
  Bool(Bool)
  Number(Number)
  String(String)
  Array(Array[Json])
  Object(Map[String, Json])
} derive(Debug)

///|
pub impl Eq for Json with equal(a, b) {
  match (a, b) {
    (Null, Null) => true
    (Bool(a_bool), Bool(b_bool)) => a_bool == b_bool
    (Number(a_num), Number(b_num)) => a_num == b_num
    (String(a_str), String(b_str)) => a_str == b_str
    (Array(a_arr), Array(b_arr)) => a_arr == b_arr
    (Object(a_obj), Object(b_obj)) => a_obj == b_obj
    _ => false
  }
}

///|
#as_free_fn
pub fn Json::array(elements : Array[Json]) -> Json {
  return Array(elements)
}

///|
#as_free_fn
pub fn Json::object(object : Map[String, Json]) -> Json {
  return Object(object)
}

///|
#as_free_fn
pub fn Json::string(s : String) -> Json {
  return String(s)
}

///|
#as_free_fn
pub fn Json::number(n : Number) -> Json {
  return Number(n)
}

///|
#as_free_fn
pub fn Json::int(n : Int) -> Json {
  return Number(Number::from_int(n))
}

///|
#as_free_fn
pub fn Json::uint(n : UInt) -> Json {
  return Number(Number::from_uint(n))
}

///|
#as_free_fn
pub fn Json::int64(n : Int64) -> Json {
  return Number(Number::from_int64(n))
}

///|
#as_free_fn
pub fn Json::uint64(n : UInt64) -> Json {
  return Number(Number::from_uint64(n))
}

///|
#as_free_fn
pub fn Json::double(n : Double) -> Json {
  return Number(Number::from_double(n))
}

///|
#as_free_fn
pub fn Json::float(n : Float) -> Json {
  return Number(Number::from_float(n))
}

///|
#as_free_fn
pub fn Json::bigint(n : BigInt) -> Json {
  return Number(Number::from_bigint(n))
}

///|
#as_free_fn
pub fn Json::bool(b : Bool) -> Json {
  return Bool(b)
}

///|
pub let null : Json = Null

///|
pub(open) trait ToJson {
  to_json(Self) -> Json
}

///|
/// Useful for json interpolation
pub impl ToJson for Json with to_json(self) {
  self
}

///|
pub using @moonbitlang/core/json {type Replacer}

///|
pub fn[T : ToJson] to_json(value : T) -> Json {
  ToJson::to_json(value)
}

///|
pub fn stringify(json : Json, escape_slash? : Bool, indent? : Int) -> String {
  json.stringify(escape_slash?, indent?)
}