defmodule LangChain.Chain do
  @moduledoc """
  A chain of ChainLinks to be processed in order, usually ending in an anchor for user confirmation.
  """

  alias LangChain.Anchor.CLI

  @derive Jason.Encoder
  defstruct [
    # List of ChainLinks, processed in order
    links: []
  ]

  @doc """
  Creates a new Chain struct with the given chain_links.
  """
  def new(chain_links) do
    %LangChain.Chain{
      links: chain_links
    }
  end

  @doc """
  Processes the ChainLinks in the chain and accumulates the output.
  If the optional `anchor` parameter is set to `true`, an anchor step will be added at the end of the chain for user confirmation.
  """
  def call(lang_chain, llm_pid, previous_values, anchor \\ false) do
    # Use Enum.reduce to process the ChainLinks and accumulate the output in previous_values
    result =
      Enum.reduce(lang_chain.links, previous_values, fn chain_link, acc ->
        updated_chain_link = LangChain.ChainLink.call(chain_link, llm_pid, acc)
        # Merge the output of the current ChainLink with the accumulated previous values
        Map.merge(acc, updated_chain_link.output)
      end)

    # anchor behavior is under development still
    if anchor do
      case CLI.get_confirmation() do
        :yes -> result
        :no -> {:error, "User declined"}
      end
    else
      result
    end
  end

  # def call(lang_chain, previous_values, anchor \\ false) do
  #   # Use Enum.reduce to process the ChainLinks and accumulate the output in previous_values
  #   result =
  #     Enum.reduce(lang_chain.links, previous_values, fn chain_link, acc ->
  #       updated_chain_link = LangChain.ChainLink.call(chain_link, acc)
  #       # Merge the output of the current ChainLink with the accumulated previous values
  #       Map.merge(acc, updated_chain_link.output)
  #     end)

  #   if anchor do
  #     case LangChain.Anchor.confirm(:query, result) do
  #       :yes -> result
  #       :no -> {:error, "User declined"}
  #     end
  #   else
  #     result
  #   end
  # end
end
