class Assistant::External < Assistant::Base
  Config = Struct.new(:url, :token, :agent_id, :session_key, keyword_init: true)
  MAX_CONVERSATION_MESSAGES = 20

  class << self
    def for_chat(chat)
      new(chat)
    end

    def configured?
      config.url.present? && config.token.present?
    end

    def available_for?(user)
      configured? && allowed_user?(user)
    end

    def allowed_user?(user)
      allowed = ENV["EXTERNAL_ASSISTANT_ALLOWED_EMAILS"]
      return true if allowed.blank?
      return false if user&.email.blank?

      allowed.split(",").map { |e| e.strip.downcase }.include?(user.email.downcase)
    end

    def config
      Config.new(
        url: ENV["EXTERNAL_ASSISTANT_URL"].presence || Setting.external_assistant_url.presence,
        token: ENV["EXTERNAL_ASSISTANT_TOKEN"].presence || Setting.external_assistant_token.presence,
        agent_id: ENV["EXTERNAL_ASSISTANT_AGENT_ID"].presence || Setting.external_assistant_agent_id.presence || "main",
        session_key: ENV.fetch("EXTERNAL_ASSISTANT_SESSION_KEY", "agent:main:main")
      )
    end
  end

  def respond_to(message)
    response_completed = false

    unless self.class.configured?
      raise Assistant::Error,
        "External assistant is not configured. Set the URL and token in Settings > Self-Hosting or via environment variables."
    end

    unless self.class.allowed_user?(chat.user)
      raise Assistant::Error, "Your account is not authorized to use the external assistant."
    end

    assistant_message = AssistantMessage.new(
      chat: chat,
      content: "",
      ai_model: "external-agent"
    )

    client = build_client
    messages = build_conversation_messages

    model = client.chat(
      messages: messages,
      user: "sure-family-#{chat.user.family_id}"
    ) do |text|
      if assistant_message.content.blank?
        stop_thinking
        assistant_message.content = text
        assistant_message.save!
      else
        assistant_message.append_text!(text)
      end
    end

    if assistant_message.new_record?
      stop_thinking
      raise Assistant::Error, "External assistant returned an empty response."
    end

    response_completed = true
    assistant_message.update!(ai_model: model) if model.present?
  rescue Assistant::Error, ActiveRecord::ActiveRecordError => e
    cleanup_partial_response(assistant_message) unless response_completed
    stop_thinking
    chat.add_error(e)
  rescue => e
    Rails.logger.error("[Assistant::External] Unexpected error: #{e.class} - #{e.message}")
    cleanup_partial_response(assistant_message) unless response_completed
    stop_thinking
    chat.add_error(Assistant::Error.new("Something went wrong with the external assistant. Check server logs for details."))
  end

  private

    def cleanup_partial_response(assistant_message)
      assistant_message&.destroy! if assistant_message&.persisted?
    rescue ActiveRecord::ActiveRecordError => e
      Rails.logger.warn("[Assistant::External] Failed to clean up partial response: #{e.message}")
    end

    def build_client
      Assistant::External::Client.new(
        url: self.class.config.url,
        token: self.class.config.token,
        agent_id: self.class.config.agent_id,
        session_key: self.class.config.session_key
      )
    end

    def build_conversation_messages
      chat.conversation_messages.ordered.last(MAX_CONVERSATION_MESSAGES).map do |msg|
        { role: msg.role, content: msg.content }
      end
    end
end
