// core.mbt - Common interface (all targets)
// Target-specific implementations in core_js.mbt / core_wasm.mbt

///|
/// Opaque type for JavaScript values
#external
pub type Any

///|
/// Represents a JavaScript constructor/class type.
/// Similar to TypeScript's `typeof ClassName`.
#external
pub type TypeOf[T]

// ============================================
// Zero-cost type conversions using %identity
// ============================================

///|
pub fn[A, B] identity(value : A) -> B = "%identity"

///|
pub fn[T] any(value : T) -> Any = "%identity"

///|
pub fn[T] Any::cast(self : Any) -> T = "%identity"

///|
/// Convert Option[T] to Any (None becomes undefined)
/// Zero-cost: concrete Option[T] compiles to T | undefined in JS
pub fn[T] nullable(opt : T?) -> Any = "%identity"

// ============================================
// Function wrappers (zero-cost)
// ============================================

///|
/// Wrap MoonBit function as JS function (0 args)
pub fn[A] from_fn0(f : () -> A) -> Any = "%identity"

///|
/// Wrap MoonBit function as JS function (1 arg)
pub fn[A, B] from_fn1(f : (A) -> B) -> Any = "%identity"

///|
/// Wrap MoonBit function as JS function (2 args)
pub fn[A, B, C] from_fn2(f : (A, B) -> C) -> Any = "%identity"

///|
/// Wrap MoonBit function as JS function (3 args)
pub fn[A, B, C, D] from_fn3(f : (A, B, C) -> D) -> Any = "%identity"

// ============================================
// Trait implementations (common)
// ============================================

///|
pub impl Eq for Any with equal(self, other) -> Bool {
  equal(self, other)
}

///|
pub impl Show for Any with output(self, logger) {
  logger.write_string(self.to_string())
}

// ============================================
// Option conversions (use target-specific functions)
// ============================================

///|
/// Safely convert a JavaScript value to an Option type.
/// Converts JavaScript `null` or `undefined` to `None`, otherwise returns `Some(value)`.
pub fn[T] identity_option(v : Any) -> T? {
  if is_nullish(v) {
    None
  } else {
    Some(identity(v))
  }
}

///|
/// Convert an Option to Any, mapping None to null and Some(v) to v.
pub fn[A] from_option(opt : A?) -> Any {
  match opt {
    Some(v) => identity(v)
    None => null()
  }
}

// ============================================
// TypeOf utilities (common logic, uses target-specific functions)
// ============================================

///|
/// Type-safe instanceof check: TypeOf[T].is_instanceof(value)
pub fn[T] TypeOf::is_instanceof(self : TypeOf[T], v : Any) -> Bool {
  instanceof_(v, identity(self))
}

///|
/// Convert TypeOf[T] to Any for use with generic functions
pub fn[T] TypeOf::as_any(self : TypeOf[T]) -> Any = "%identity"

///|
/// Type-safe constructor call: new cls(...args) -> T
pub fn[T] new_instance(cls : TypeOf[T], args : Array[Any]) -> T {
  identity(new(identity(cls), args))
}