# frozen_string_literal: true

require "rails_helper"

describe ChatTranscriptService do
  let(:acting_user) { Fabricate(:user) }
  let(:user1) { Fabricate(:user, username: "martinchat") }
  let(:user2) { Fabricate(:user, username: "brucechat") }
  let(:channel) { Fabricate(:category_channel, name: "The Beam Discussions") }

  def service(message_ids, opts: {})
    described_class.new(channel, acting_user, messages_or_ids: Array.wrap(message_ids), opts: opts)
  end

  it "generates a simple chat transcript from one message" do
    message =
      Fabricate(
        :chat_message,
        user: user1,
        chat_channel: channel,
        message: "an extremely insightful response :)",
      )

    expect(service(message.id).generate_markdown).to eq(<<~MARKDOWN)
    [chat quote="martinchat;#{message.id};#{message.created_at.iso8601}" channel="The Beam Discussions" channelId="#{channel.id}"]
    an extremely insightful response :)
    [/chat]
    MARKDOWN
  end

  it "generates a single chat transcript from multiple subsequent messages from the same user" do
    message1 =
      Fabricate(
        :chat_message,
        user: user1,
        chat_channel: channel,
        message: "an extremely insightful response :)",
      )
    message2 =
      Fabricate(:chat_message, user: user1, chat_channel: channel, message: "if i say so myself")
    message3 = Fabricate(:chat_message, user: user1, chat_channel: channel, message: "yay!")

    rendered = service([message1.id, message2.id, message3.id]).generate_markdown
    expect(rendered).to eq(<<~MARKDOWN)
    [chat quote="martinchat;#{message1.id};#{message1.created_at.iso8601}" channel="The Beam Discussions" channelId="#{channel.id}" multiQuote="true"]
    an extremely insightful response :)

    if i say so myself

    yay!
    [/chat]
    MARKDOWN
  end

  it "generates chat messages in created_at order no matter what order the message_ids are passed in" do
    message1 =
      Fabricate(
        :chat_message,
        created_at: 10.minute.ago,
        user: user1,
        chat_channel: channel,
        message: "an extremely insightful response :)",
      )
    message2 =
      Fabricate(
        :chat_message,
        created_at: 5.minutes.ago,
        user: user1,
        chat_channel: channel,
        message: "if i say so myself",
      )
    message3 =
      Fabricate(
        :chat_message,
        created_at: 1.minutes.ago,
        user: user1,
        chat_channel: channel,
        message: "yay!",
      )

    rendered = service([message3.id, message1.id, message2.id]).generate_markdown
    expect(rendered).to eq(<<~MARKDOWN)
    [chat quote="martinchat;#{message1.id};#{message1.created_at.iso8601}" channel="The Beam Discussions" channelId="#{channel.id}" multiQuote="true"]
    an extremely insightful response :)

    if i say so myself

    yay!
    [/chat]
    MARKDOWN
  end

  it "generates multiple chained chat transcripts for interleaving messages from different users" do
    message1 =
      Fabricate(
        :chat_message,
        user: user1,
        chat_channel: channel,
        message: "an extremely insightful response :)",
      )
    message2 = Fabricate(:chat_message, user: user2, chat_channel: channel, message: "says you!")
    message3 = Fabricate(:chat_message, user: user1, chat_channel: channel, message: "aw :(")

    expect(service([message1.id, message2.id, message3.id]).generate_markdown).to eq(<<~MARKDOWN)
    [chat quote="martinchat;#{message1.id};#{message1.created_at.iso8601}" channel="The Beam Discussions" channelId="#{channel.id}" multiQuote="true" chained="true"]
    an extremely insightful response :)
    [/chat]

    [chat quote="brucechat;#{message2.id};#{message2.created_at.iso8601}" chained="true"]
    says you!
    [/chat]

    [chat quote="martinchat;#{message3.id};#{message3.created_at.iso8601}" chained="true"]
    aw :(
    [/chat]
    MARKDOWN
  end

  it "generates image / attachment / video / audio markdown inside the [chat] bbcode for upload-only messages" do
    SiteSetting.authorized_extensions = "mp4|mp3|pdf|jpg"
    message = Fabricate(:chat_message, user: user1, chat_channel: channel, message: "")
    video = Fabricate(:upload, original_filename: "test_video.mp4", extension: "mp4")
    audio = Fabricate(:upload, original_filename: "test_audio.mp3", extension: "mp3")
    attachment = Fabricate(:upload, original_filename: "test_file.pdf", extension: "pdf")
    image =
      Fabricate(
        :upload,
        width: 100,
        height: 200,
        original_filename: "test_img.jpg",
        extension: "jpg",
      )
    UploadReference.create(target: message, created_at: 10.seconds.ago, upload: video)
    UploadReference.create(target: message, created_at: 9.seconds.ago, upload: audio)
    UploadReference.create(target: message, created_at: 8.seconds.ago, upload: attachment)
    UploadReference.create(target: message, created_at: 7.seconds.ago, upload: image)
    video_markdown = UploadMarkdown.new(video).to_markdown
    audio_markdown = UploadMarkdown.new(audio).to_markdown
    attachment_markdown = UploadMarkdown.new(attachment).to_markdown
    image_markdown = UploadMarkdown.new(image).to_markdown

    expect(service(message.id).generate_markdown).to eq(<<~MARKDOWN)
    [chat quote="martinchat;#{message.id};#{message.created_at.iso8601}" channel="The Beam Discussions" channelId="#{channel.id}"]
    #{video_markdown}
    #{audio_markdown}
    #{attachment_markdown}
    #{image_markdown}
    [/chat]
    MARKDOWN
  end

  it "generates the correct markdown if a message has text and an upload" do
    SiteSetting.authorized_extensions = "mp4|mp3|pdf|jpg"
    message =
      Fabricate(
        :chat_message,
        user: user1,
        chat_channel: channel,
        message: "this is a cool and funny picture",
      )
    image =
      Fabricate(
        :upload,
        width: 100,
        height: 200,
        original_filename: "test_img.jpg",
        extension: "jpg",
      )
    UploadReference.create(target: message, created_at: 7.seconds.ago, upload: image)
    image_markdown = UploadMarkdown.new(image).to_markdown

    expect(service(message.id).generate_markdown).to eq(<<~MARKDOWN)
    [chat quote="martinchat;#{message.id};#{message.created_at.iso8601}" channel="The Beam Discussions" channelId="#{channel.id}"]
    this is a cool and funny picture

    #{image_markdown}
    [/chat]
    MARKDOWN
  end

  it "generates a transcript with the noLink option" do
    message =
      Fabricate(
        :chat_message,
        user: user1,
        chat_channel: channel,
        message: "an extremely insightful response :)",
      )

    expect(service(message.id, opts: { no_link: true }).generate_markdown).to eq(<<~MARKDOWN)
    [chat quote="martinchat;#{message.id};#{message.created_at.iso8601}" channel="The Beam Discussions" channelId="#{channel.id}" noLink="true"]
    an extremely insightful response :)
    [/chat]
    MARKDOWN
  end

  it "generates reaction data for single and subsequent messages" do
    message =
      Fabricate(
        :chat_message,
        user: user1,
        chat_channel: channel,
        message: "an extremely insightful response :)",
      )
    message2 = Fabricate(:chat_message, user: user1, chat_channel: channel, message: "wow so tru")
    message3 =
      Fabricate(:chat_message, user: user2, chat_channel: channel, message: "a new perspective")

    ChatMessageReaction.create!(
      chat_message: message,
      user: Fabricate(:user, username: "bjorn"),
      emoji: "heart",
    )
    ChatMessageReaction.create!(
      chat_message: message,
      user: Fabricate(:user, username: "sigurd"),
      emoji: "heart",
    )
    ChatMessageReaction.create!(
      chat_message: message,
      user: Fabricate(:user, username: "hvitserk"),
      emoji: "+1",
    )
    ChatMessageReaction.create!(
      chat_message: message2,
      user: Fabricate(:user, username: "ubbe"),
      emoji: "money_mouth_face",
    )
    ChatMessageReaction.create!(
      chat_message: message3,
      user: Fabricate(:user, username: "ivar"),
      emoji: "sob",
    )

    expect(
      service(
        [message.id, message2.id, message3.id],
        opts: {
          include_reactions: true,
        },
      ).generate_markdown,
    ).to eq(<<~MARKDOWN)
    [chat quote="martinchat;#{message.id};#{message.created_at.iso8601}" channel="The Beam Discussions" channelId="#{channel.id}" multiQuote="true" chained="true" reactions="+1:hvitserk;heart:bjorn,sigurd;money_mouth_face:ubbe"]
    an extremely insightful response :)

    wow so tru
    [/chat]

    [chat quote="brucechat;#{message3.id};#{message3.created_at.iso8601}" chained="true" reactions="sob:ivar"]
    a new perspective
    [/chat]
    MARKDOWN
  end
end
