class Tiktok::MessageService
  include Tiktok::MessagingHelpers

  pattr_initialize [:channel!, :content!, :outgoing_echo]

  def perform
    if outgoing_message?
      message = find_message(tt_conversation_id, tt_message_id)
      return if message.present?
    end

    create_message
  end

  private

  def contact_inbox
    @contact_inbox ||= create_contact_inbox(channel, tt_conversation_id, incoming_message? ? from : to, incoming_message? ? from_id : to_id)
  end

  def contact
    contact_inbox.contact
  end

  def conversation
    @conversation ||= contact_inbox.conversations.first || create_conversation(channel, contact_inbox, tt_conversation_id)
  end

  def create_message
    message = conversation.messages.build(
      content: message_content,
      account_id: channel.inbox.account_id,
      inbox_id: channel.inbox.id,
      message_type: incoming_message? ? :incoming : :outgoing,
      content_attributes: message_content_attributes,
      source_id: tt_message_id,
      created_at: tt_message_time,
      updated_at: tt_message_time
    )

    message.sender = contact_inbox.contact if incoming_message? && !outgoing_echo
    message.status = :delivered if outgoing_message?

    create_message_attachments(message)
    message.save!
  end

  def message_content
    return unless text_message?

    tt_text_body
  end

  def create_message_attachments(message)
    create_image_message_attachment(message) if image_message?
    create_share_post_message_attachment(message) if share_post_message?
  end

  def create_image_message_attachment(message)
    return unless image_message?

    attachment_file = fetch_attachment(channel, tt_conversation_id, tt_message_id, tt_image_media_id)

    message.attachments.new(
      account_id: message.account_id,
      file_type: :image,
      file: {
        io: attachment_file,
        filename: attachment_file.original_filename,
        content_type: attachment_file.content_type
      }
    )
  end

  def create_share_post_message_attachment(message)
    return unless share_post_message?

    message.attachments.new(
      account_id: message.account_id,
      file_type: :embed,
      external_url: tt_share_post_embed_url
    )
  end

  def supported_message?
    text_message? || image_message? || share_post_message?
  end

  def message_content_attributes
    attributes = {}
    attributes[:in_reply_to_external_id] = tt_referenced_message_id if tt_referenced_message_id
    attributes[:is_unsupported] = true unless supported_message?
    attributes[:external_echo] = true if outgoing_echo
    attributes
  end

  def text_message?
    tt_message_type == 'text'
  end

  def image_message?
    tt_message_type == 'image'
  end

  def sticker_message?
    tt_message_type == 'sticker'
  end

  def share_post_message?
    tt_message_type == 'share_post'
  end

  def tt_text_body
    return unless text_message?

    content[:text][:body]
  end

  def tt_image_media_id
    return unless image_message?

    content[:image][:media_id]
  end

  def tt_share_post_embed_url
    return unless share_post_message?

    content[:share_post][:embed_url]
  end

  def tt_referenced_message_id
    content[:referenced_message_info]&.[](:referenced_message_id)
  end

  def tt_message_type
    content[:type]
  end

  def tt_message_id
    content[:message_id]
  end

  def tt_message_time
    Time.zone.at(content[:timestamp] / 1000).utc
  end

  def tt_conversation_id
    content[:conversation_id]
  end

  def from
    content[:from]
  end

  def from_id
    content[:from_user][:id]
  end

  def to
    content[:to]
  end

  def to_id
    content[:to_user][:id]
  end

  def incoming_message?
    channel.business_id == to_id
  end

  def outgoing_message?
    !incoming_message?
  end
end
