# frozen_string_literal: true

module DiscourseAi
  module AiBot
    class QuestionConsolidator
      attr_reader :llm, :messages, :user, :max_tokens

      def self.consolidate_question(llm, messages, user)
        new(llm, messages, user).consolidate_question
      end

      def initialize(llm, messages, user)
        @llm = llm
        @messages = messages
        @user = user
        @max_tokens = 2048
      end

      def consolidate_question
        @llm.generate(revised_prompt, user: @user, feature_name: "question_consolidator")
      end

      def revised_prompt
        max_tokens_per_model = @max_tokens / 5

        conversation_snippet = []
        tokens = 0

        messages.reverse_each do |message|
          # skip tool calls
          next if message[:type] != :user && message[:type] != :model

          row = +""
          row << ((message[:type] == :user) ? "user" : "model")

          content = message[:content]
          current_tokens = @llm.tokenizer.tokenize(content).length

          allowed_tokens = @max_tokens - tokens
          allowed_tokens = [allowed_tokens, max_tokens_per_model].min if message[:type] == :model

          truncated_content = content

          if current_tokens > allowed_tokens
            truncated_content = @llm.tokenizer.truncate(content, allowed_tokens)
            current_tokens = allowed_tokens
          end

          row << ": #{truncated_content}"
          tokens += current_tokens
          conversation_snippet << row

          break if tokens >= @max_tokens
        end

        history = conversation_snippet.reverse.join("\n")

        system_message = <<~TEXT
          You are Question Consolidation Bot: an AI assistant tasked with consolidating a user's latest question into a self-contained, context-rich question.

          - Your output will be used to query a vector database. DO NOT include superflous text such as "here is your consolidated question:".
          - You interact with an API endpoint, not a user, you must never produce denials, nor conversations directed towards a non-existent user.
          - You only produce automated responses to input, where a response is a consolidated question without further discussion.
          - You only ever reply with consolidated questions. You never try to answer user queries.

          If for any reason there is no discernable question (Eg: thank you, or good job) reply with the text NO_QUESTION.
        TEXT

        message = <<~TEXT
          Given the following conversation snippet, craft a self-contained context-rich question (if there is no question reply with NO_QUESTION):

          {{{
          #{history}
          }}}

          Only ever reply with a consolidated question. Do not try to answer user queries.
        TEXT

        response =
          DiscourseAi::Completions::Prompt.new(
            system_message,
            messages: [{ type: :user, content: message }],
          )

        if response == "NO_QUESTION"
          nil
        else
          response
        end
      end
    end
  end
end
