require "ruby_llm"
require "yaml"

ENV.merge!(YAML.load_file(".env.yaml"))

RubyLLM.configure do |config|
  config.gemini_api_key = ENV.fetch("GEMINI_KEY")
end

RubyLLM.models.refresh!

class LiveCode
  def initialize
    @chat = RubyLLM.chat(model: "gemini-3.6-flash")
  end

  def method_missing(method_name, *args, **kwargs)
    p "Missing method: #{method_name}, #{args.inspect}, #{kwargs.inspect}"

    prompt = <<~PROMPT
      You are a Ruby code generator. A missing method `#{method_name}` was called
      with the arguments: #{args.map(&:class)}, keyword arguments: #{kwargs.keys}.

      Write ONLY the valid Ruby code to define `#{method_name}`. Ensure it works
      well with the existing instance variables and previously generated methods.

      #{llm_context}

      Return ONLY valid Ruby code defining this method. Do not include markdown formatting.
      Example:
      def #{method_name}(...)
        # implementation
      end
    PROMPT

    p "Prompt: #{prompt}"

    ruby_code = @chat.ask(prompt).content

    p "Code: #{ruby_code}"

    @_generated_methods ||= {}
    @_generated_methods[method_name] = ruby_code

    singleton_class.class_eval(ruby_code)

    send(method_name, *args, **kwargs)
  end

  def llm_context
    context = "# Current Instance Variables and Types:\n"
    if instance_variables.empty?
      context += "(No instance variables yet)\n"
    else
      instance_variables.each do |name, schema|
        value = instance_variable_get(name)
        context += " - #{name}: #{value.class.name}\n"
      end
    end

    context += "# Previously Generated Methods:\n"
    if @_generated_methods.nil? || @_generated_methods.empty?
      context += "(No generated methods yet)\n"
    else
      @_generated_methods.each do |name, code|
        context += "#{code}\n"
      end
    end

    context
  end
end
