// Per-realm canonical Proxy constructor used by the standard-library wiring
// and exact activation admission. Its construct callback is a synchronous
// runtime leaf: it validates inputs and allocates ProxyData without invoking
// interpreted guest code.

///|
fn canonical_proxy_constructor_construct(
  _interp : Interpreter,
  args : Array[Value],
) -> Value raise Error {
  if args.length() < 2 {
    raise @errors.TypeError(
      message="Cannot create proxy with a non-object as target or handler",
    )
  }
  let target = args[0]
  let handler = args[1]
  match target {
    Object(_) | Array(_) | Map(_) | Set(_) | Promise(_) | Proxy(_) => ()
    _ =>
      raise @errors.TypeError(
        message="Cannot create proxy with a non-object as target or handler",
      )
  }
  match handler {
    Object(_) | Array(_) | Map(_) | Set(_) | Promise(_) | Proxy(_) => ()
    _ =>
      raise @errors.TypeError(
        message="Cannot create proxy with a non-object as target or handler",
      )
  }
  Proxy({
    target: Some(target),
    handler: Some(handler),
    is_callable: is_callable(target),
    is_constructor: is_constructor_value(target),
  })
}

///|
pub fn make_canonical_proxy_constructor(realm_state : RealmState) -> Value {
  match realm_state.canonical_proxy_constructor.val {
    Some(existing) => existing
    None => {
      let fixed_descriptor : PropDescriptor = {
        writable: false,
        enumerable: false,
        configurable: true,
        getter: None,
        setter: None,
        is_accessor: false,
      }
      let proxy_constructor : Value = Object({
        bag: {
          properties: { "name": String_("Proxy"), "length": Number(2.0) },
          symbol_properties: Map([]),
          descriptors: { "name": fixed_descriptor, "length": fixed_descriptor },
          symbol_descriptors: Map([]),
          internal_slots: Map([]),
          host_slots: Map([]),
        },
        prototype: Null,
        callable: Some(
          ConstructorOnlyCallable(
            "Proxy", canonical_proxy_constructor_construct,
          ),
        ),
        class_name: "Function",
        extensible: true,
        arraybuffer_state: None,
      })
      realm_state.canonical_proxy_constructor.val = Some(proxy_constructor)
      proxy_constructor
    }
  }
}

///|
#warnings("-unused_value")
fn RealmState::canonical_proxy_constructor_matches(
  self : RealmState,
  candidate : Value,
) -> Bool {
  match (self.canonical_proxy_constructor.val, candidate) {
    (Some(Object(expected)), Object(actual)) => physical_equal(expected, actual)
    _ => false
  }
}