# typed: strict
# ----------------------------------------------------------------------------
#
#  Welcome to Baml! To use this generated code, please run the following:
#
#  $ gem install baml
#
# ----------------------------------------------------------------------------

# This file was generated by BAML: please do not edit it. Instead, edit the
# BAML files and re-generate this code using: baml-cli generate
# baml-cli is available with the baml package.
# gem install baml
require "sorbet-runtime"
require "baml"

require_relative "type_builder"

module BamlClient

  class BamlCallOptions < T::Struct
      extend T::Sig

      const :tb,              T.nilable(BamlClient::TypeBuilder),  default: nil
      const :client_registry, T.nilable(Baml::ClientRegistry), default: nil
      const :env,             T.nilable(T::Hash[String, T.nilable(String)]), default: nil
      const :tags,            T.nilable(T::Hash[String, String]), default: nil
      const :collector,       T.any(T.nilable(Baml::Collector), T::Array[Baml::Collector]), default: nil
  end

  module Internal
    class ResolvedBamlOptions < T::Struct
        const :tb,              T.nilable(Baml::Ffi::TypeBuilder)
        const :client_registry, T.nilable(Baml::ClientRegistry)
        const :collectors,      T::Array[Baml::Collector]
        const :env_vars,        T::Hash[String, String]
        const :tags,            T::Hash[String, String]
    end

    class DoNotUseDirectlyCallManager
        extend T::Sig

        class CallMode < T::Enum
            enums do
                STREAM = new
                REQUEST = new
            end
        end

        sig { params(baml_options: BamlCallOptions).void }
        def initialize(baml_options)
          @baml_options = baml_options
        end

        # -------------------------------------------------------------------------
        # Public helpers – identical API surface to Python version
        # -------------------------------------------------------------------------

        sig { params(options: BamlCallOptions).returns(DoNotUseDirectlyCallManager) }
        def merge_options(options)
          merged = @baml_options.serialize.merge(options.serialize)
          DoNotUseDirectlyCallManager.new(BamlCallOptions.from_hash(merged))
        end

        sig { params(function_name: String, args: T::Hash[String, T.untyped]).returns(Baml::Ffi::FunctionResult) }
        def call_function_sync(function_name:, args:)
          r = resolve
          runtime = Internal::DO_NOT_USE_DIRECTLY_UNLESS_YOU_KNOW_WHAT_YOU_RE_DOING_RUNTIME
          ctx = Internal::DO_NOT_USE_DIRECTLY_UNLESS_YOU_KNOW_WHAT_YOU_RE_DOING_CTX
          runtime.call_function(
            function_name,
            args,
            ctx,
            r.tb,
            r.client_registry,
            r.collectors,
            r.env_vars,
            r.tags,
          )
        end

        sig { params(function_name: String, args: T::Hash[String, T.untyped]).returns([Baml::Ffi::RuntimeContextManager, Baml::Ffi::FunctionResultStream]) }
        def create_sync_stream(function_name:, args:)
          r = resolve
          runtime = Internal::DO_NOT_USE_DIRECTLY_UNLESS_YOU_KNOW_WHAT_YOU_RE_DOING_RUNTIME
          ctx = Internal::DO_NOT_USE_DIRECTLY_UNLESS_YOU_KNOW_WHAT_YOU_RE_DOING_CTX
          result = runtime.stream_function(
            function_name,
            args,
            ctx,
            r.tb,
            r.client_registry,
            r.collectors,
            r.env_vars,
            r.tags,
          )
          [ctx, result]
        end
        # -------------------------------------------------------------------------
        # Private helpers
        # -------------------------------------------------------------------------
        private

        sig { returns(ResolvedBamlOptions) }
        def resolve
          tb       = @baml_options.tb
          baml_tb = case tb
                    when nil then nil
                    else tb._registry
                    end

          cr = @baml_options.client_registry

          collector = @baml_options.collector
          collectors = case collector
                       when nil    then []
                       when Array  then collector
                       else             [collector]
                       end

          # 4. env – start with ENV and patch
          env_vars = ENV.to_h
          (@baml_options.env || {}).each do |k, v|
            v.nil? ? env_vars.delete(k) : env_vars[k] = v
          end

          # 5. tags
          tags = @baml_options.tags || {}

          ResolvedBamlOptions.new(
            tb:              baml_tb,
            client_registry: cr || nil,
            collectors:      collectors,
            env_vars:        env_vars,
            tags:            tags,
          )
        end
    end
  end

end
