app/models/ruby_conversations/message.rb



# frozen_string_literal: true

require 'active_model'

module RubyConversations
  # Represents a message in a conversation, either from the user or AI
  class Message
    include ActiveModel::Model
    include Concerns::MessageAttributes
    include Concerns::MessageApiAttributes

    # Define attributes
    attr_accessor :id, :conversation_id, :llm,
                  :temperature, :tool, :metadata, :created_at, :updated_at,
                  :message_prompts

    # Constants
    ROLES = {
      user: 'user',
      assistant: 'assistant'
    }.freeze

    def initialize(attributes = {})
      @message_prompts = []
      prompts_attributes = extract_nested_attributes!(attributes, :message_prompts)
      # Also check for Rails-style nested attributes
      prompts_attributes ||= extract_nested_attributes!(attributes, :ai_message_prompts_attributes)

      super
      initialize_message_prompts(prompts_attributes)
    end

    def initialize_message_prompts(attributes_array)
      (attributes_array || []).each do |attrs|
        next if attrs.blank?

        @message_prompts << RubyConversations::MessagePrompt.new(attrs)
      end
    end

    def message_prompts_attributes=(attributes_array)
      @message_prompts = []
      initialize_message_prompts(attributes_array)
    end

    # Alias for Rails nested attributes convention
    alias ai_message_prompts_attributes= message_prompts_attributes=

    # Attributes method for serialization/logging
    def attributes
      base_attributes.merge(
        'llm' => llm,
        'temperature' => temperature,
        'tool' => tool,
        'ai_message_prompts_attributes' => message_prompts.map(&:attributes)
      )
    end

    # Method for API serialization
    def attributes_for_api
      {
        id: id,
        conversation_id: conversation_id,
        metadata: metadata,
        llm: llm,
        tool: tool,
        ai_message_prompts_attributes: message_prompts.map(&:attributes_for_api)
      }.merge(message_attributes_for_api).compact
    end

    # Helper methods for role checking
    def user?
      request.present? && response.blank?
    end

    def assistant?
      response.present?
    end

    def prompt_inputs
      message_prompts.flat_map(&:message_inputs)
    end

    private

    def base_attributes
      {
        'id' => id,
        'conversation_id' => conversation_id,
        'metadata' => metadata,
        'created_at' => created_at,
        'updated_at' => updated_at
      }.merge(message_base_attributes)
    end

    def extract_nested_attributes!(attributes, key)
      nested = attributes.delete(key)
      nested ||= attributes.delete(key.to_s)
      nested
    end
  end

  # Alias for compatibility with Zeitwerk
  AIMessage = Message
end