# frozen_string_literal: true

require "rails_helper"

RSpec.describe DiscourseAi::Configuration::Feature do
  fab!(:llm_model)
  fab!(:ai_persona) { Fabricate(:ai_persona, default_llm_id: llm_model.id) }

  def allow_configuring_setting(&block)
    DiscourseAi::Completions::Llm.with_prepared_responses(["OK"]) { block.call }
  end

  describe "#llm_model" do
    context "when persona is not found" do
      it "returns nil when persona_id is invalid" do
        ai_feature =
          described_class.new(
            "topic_summaries",
            "ai_summarization_persona",
            DiscourseAi::Configuration::Module::SUMMARIZATION_ID,
            DiscourseAi::Configuration::Module::SUMMARIZATION,
          )

        SiteSetting.ai_summarization_persona = 999_999
        expect(ai_feature.llm_models).to eq([])
      end
    end

    context "with summarization module" do
      let(:ai_feature) do
        described_class.new(
          "topic_summaries",
          "ai_summarization_persona",
          DiscourseAi::Configuration::Module::SUMMARIZATION_ID,
          DiscourseAi::Configuration::Module::SUMMARIZATION,
        )
      end

      it "returns the configured llm model" do
        SiteSetting.ai_summarization_persona = ai_persona.id
        allow_configuring_setting { SiteSetting.ai_summarization_model = "custom:#{llm_model.id}" }
        expect(ai_feature.llm_models).to eq([llm_model])
      end
    end

    context "with AI helper module" do
      let(:ai_feature) do
        described_class.new(
          "proofread",
          "ai_helper_proofreader_persona",
          DiscourseAi::Configuration::Module::AI_HELPER_ID,
          DiscourseAi::Configuration::Module::AI_HELPER,
        )
      end

      it "returns the persona's default llm when no specific helper model is set" do
        SiteSetting.ai_helper_proofreader_persona = ai_persona.id
        SiteSetting.ai_helper_model = ""

        expect(ai_feature.llm_models).to eq([llm_model])
      end
    end

    context "with translation module" do
      fab!(:translation_model) { Fabricate(:llm_model) }

      let(:ai_feature) do
        described_class.new(
          "locale_detector",
          "ai_translation_locale_detector_persona",
          DiscourseAi::Configuration::Module::TRANSLATION_ID,
          DiscourseAi::Configuration::Module::TRANSLATION,
        )
      end

      it "uses translation model when configured" do
        SiteSetting.ai_translation_locale_detector_persona = ai_persona.id
        ai_persona.update!(default_llm_id: nil)
        allow_configuring_setting do
          SiteSetting.ai_translation_model = "custom:#{translation_model.id}"
        end

        expect(ai_feature.llm_models).to eq([translation_model])
      end
    end
  end

  describe "#enabled?" do
    it "returns true when no enabled_by_setting is specified" do
      ai_feature =
        described_class.new(
          "topic_summaries",
          "ai_summarization_persona",
          DiscourseAi::Configuration::Module::SUMMARIZATION_ID,
          DiscourseAi::Configuration::Module::SUMMARIZATION,
        )

      expect(ai_feature.enabled?).to be true
    end

    it "respects the enabled_by_setting when specified" do
      ai_feature =
        described_class.new(
          "gists",
          "ai_summary_gists_persona",
          DiscourseAi::Configuration::Module::SUMMARIZATION_ID,
          DiscourseAi::Configuration::Module::SUMMARIZATION,
          enabled_by_setting: "ai_summary_gists_enabled",
        )

      SiteSetting.ai_summary_gists_enabled = false
      expect(ai_feature.enabled?).to be false

      SiteSetting.ai_summary_gists_enabled = true
      expect(ai_feature.enabled?).to be true
    end
  end

  describe ".bot_features" do
    fab!(:bot_llm) { Fabricate(:llm_model, enabled_chat_bot: true) }
    fab!(:non_bot_llm) { Fabricate(:llm_model, enabled_chat_bot: false) }
    fab!(:chat_persona) do
      Fabricate(
        :ai_persona,
        default_llm_id: bot_llm.id,
        allow_chat_channel_mentions: true,
        allow_chat_direct_messages: false,
      )
    end
    fab!(:dm_persona) do
      Fabricate(
        :ai_persona,
        default_llm_id: bot_llm.id,
        allow_chat_channel_mentions: false,
        allow_chat_direct_messages: true,
      )
    end
    fab!(:topic_persona) do
      Fabricate(
        :ai_persona,
        default_llm_id: bot_llm.id,
        allow_topic_mentions: true,
        allow_personal_messages: false,
      )
    end
    fab!(:pm_persona) do
      Fabricate(:ai_persona, allow_topic_mentions: false, allow_personal_messages: true)
    end
    fab!(:inactive_persona) do
      Fabricate(
        :ai_persona,
        enabled: false,
        allow_chat_channel_mentions: false,
        allow_chat_direct_messages: false,
        allow_topic_mentions: false,
        allow_personal_messages: true,
      )
    end

    let(:bot_feature) { described_class.bot_features.first }

    it "returns bot features with correct configuration" do
      expect(bot_feature.name).to eq("bot")
      expect(bot_feature.persona_setting).to be_nil
      expect(bot_feature.module_id).to eq(DiscourseAi::Configuration::Module::BOT_ID)
      expect(bot_feature.module_name).to eq(DiscourseAi::Configuration::Module::BOT)
    end

    it "returns only LLMs with enabled_chat_bot" do
      expect(bot_feature.llm_models).to contain_exactly(bot_llm)
      expect(bot_feature.llm_models).not_to include(non_bot_llm)
    end

    it "returns only personas with at least one bot permission enabled" do
      expected_ids = [chat_persona.id, dm_persona.id, topic_persona.id, pm_persona.id]
      AiPersona.where("id not in (:ids)", ids: expected_ids).update_all(enabled: false)
      expect(bot_feature.persona_ids).to match_array(expected_ids)
      expect(bot_feature.persona_ids).not_to include(inactive_persona.id)
    end

    it "includes personas with multiple permissions enabled" do
      multi_permission_persona =
        Fabricate(
          :ai_persona,
          enabled: true,
          default_llm_id: bot_llm.id,
          allow_chat_channel_mentions: true,
          allow_chat_direct_messages: true,
          allow_topic_mentions: true,
          allow_personal_messages: true,
        )

      expect(bot_feature.persona_ids).to include(multi_permission_persona.id)
    end
  end

  describe "#persona_ids" do
    it "returns the persona id from site settings" do
      ai_feature =
        described_class.new(
          "topic_summaries",
          "ai_summarization_persona",
          DiscourseAi::Configuration::Module::SUMMARIZATION_ID,
          DiscourseAi::Configuration::Module::SUMMARIZATION,
        )

      SiteSetting.ai_summarization_persona = ai_persona.id
      expect(ai_feature.persona_ids).to eq([ai_persona.id])
    end
  end

  describe ".find_features_using" do
    it "returns all features using a specific persona" do
      SiteSetting.ai_summarization_persona = ai_persona.id
      SiteSetting.ai_helper_proofreader_persona = ai_persona.id
      SiteSetting.ai_translation_locale_detector_persona = 999

      features = described_class.find_features_using(persona_id: ai_persona.id)

      expect(features.map(&:name)).to include("topic_summaries", "proofread")
      expect(features.map(&:name)).not_to include("locale_detector")
    end
  end
end
