(*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *)

module Flow = Flow_js
include Flow
open Type
open TypeUtil

let map_on_resolved_type = Flow_js_utils.map_on_resolved_type

let specialize cx c use_op reason_op reason_tapp targs =
  let open Type in
  let open TypeUtil in
  let reason = reason_of_t c in
  let f c =
    Tvar_resolver.mk_tvar_and_fully_resolve_where cx reason (fun tvar ->
        Flow.flow cx (c, SpecializeT (use_op, reason_op, reason_tapp, targs, tvar))
    )
  in
  map_on_resolved_type cx reason c f

let mixin cx reason i =
  let f i =
    Tvar_resolver.mk_tvar_and_fully_resolve_where cx reason (fun tout ->
        Flow.flow cx (i, Type.MixinT (reason, tout))
    )
  in
  map_on_resolved_type cx reason i f

let obj_test_proto cx reason t =
  let f t =
    Tvar_resolver.mk_tvar_and_fully_resolve_where cx reason (fun tout ->
        Flow.flow cx (t, ObjTestProtoT (reason, tout))
    )
  in
  map_on_resolved_type cx reason t f

let get_prop cx use_op reason ?(op_reason = reason) name l =
  let f l =
    Tvar_resolver.mk_tvar_and_fully_resolve_no_wrap_where cx op_reason (fun tout ->
        Flow.flow
          cx
          ( l,
            GetPropT
              {
                use_op;
                reason = op_reason;
                id = None;
                from_annot = false;
                skip_optional = false;
                propref = mk_named_prop ~reason name;
                tout;
                hint = hint_unavailable;
              }
          )
    )
  in
  map_on_resolved_type cx op_reason l f

let qualify_type cx use_op reason ~op_reason prop_name l =
  let f l =
    Tvar_resolver.mk_tvar_and_fully_resolve_no_wrap_where cx op_reason (fun tout ->
        Flow.flow
          cx
          ( l,
            GetTypeFromNamespaceT
              { use_op; reason = op_reason; prop_ref = (reason, prop_name); tout }
          )
    )
  in
  map_on_resolved_type cx op_reason l f

let mk_instance cx ?(type_t_kind = InstanceKind) instance_reason ?(use_desc = false) l =
  let f t =
    t
    |> Flow.singleton_concrete_type_for_inspection cx instance_reason
    |> Flow_js_utils.ValueToTypeReferenceTransform.run_on_concrete_type
         cx
         ~use_op:unknown_use
         instance_reason
         type_t_kind
    |> Tvar_resolver.resolved_t cx
  in
  AnnotT (instance_reason, map_on_resolved_type cx instance_reason l f, use_desc)
