# frozen_string_literal: true

module RubyLLM
  # Represents the content sent to or received from an LLM.
  class Content
    attr_reader :text, :attachments

    def initialize(text = nil, attachments = nil)
      @text = text
      @attachments = []

      process_attachments(attachments)
      raise ArgumentError, 'Text and attachments cannot be both nil' if @text.nil? && @attachments.empty?
    end

    def add_attachment(source, filename: nil)
      @attachments << build_attachment(source, filename:)
      self
    end

    def format
      if @text && @attachments.empty?
        @text
      else
        self
      end
    end

    def empty?
      attachments.empty? && (@text.nil? || (@text.respond_to?(:empty?) && @text.empty?))
    end

    # For Rails serialization
    def to_h
      { text: @text, attachments: @attachments.map(&:to_h) }
    end

    private

    def build_attachment(source, filename: nil)
      if source.is_a?(Attachment)
        return source unless filename

        return Attachment.new(source.source, filename:)
      end

      Attachment.new(source, filename:)
    end

    def process_attachments_array_or_string(attachments)
      Utils.to_safe_array(attachments).each do |file|
        next if blank_attachment_entry?(file)

        add_attachment(file)
      end
    end

    def blank_attachment_entry?(file)
      file.nil? || (file.is_a?(String) && file.strip.empty?)
    end

    def process_attachments(attachments)
      if attachments.is_a?(Hash)
        attachments.each_value { |attachment| process_attachments_array_or_string(attachment) }
      else
        process_attachments_array_or_string attachments
      end
    end
  end

  class Content
    # Represents provider-specific payloads that should bypass RubyLLM formatting.
    class Raw
      attr_reader :value

      def initialize(value)
        raise ArgumentError, 'Raw content payload cannot be nil' if value.nil?

        @value = value
      end

      def format
        @value
      end

      def to_h
        @value
      end
    end
  end
end
