# frozen_string_literal: true

class TopicGroup < ActiveRecord::Base
  belongs_to :group
  belongs_to :topic

  def self.update_last_read(user, topic_id, post_number)
    updated_groups = update_read_count(user, topic_id, post_number)
    create_topic_group(user, topic_id, post_number, updated_groups.map(&:group_id))
    TopicTrackingState.publish_read_indicator_on_read(topic_id, post_number, user.id)
  end

  def self.new_message_update(user, topic_id, post_number)
    updated_groups = update_read_count(user, topic_id, post_number)
    create_topic_group(user, topic_id, post_number, updated_groups.map(&:group_id))
    TopicTrackingState.publish_read_indicator_on_write(topic_id, post_number, user.id)
  end

  def self.update_read_count(user, topic_id, post_number)
    update_query = <<~SQL
      UPDATE topic_groups tg
      SET
        last_read_post_number = GREATEST(:post_number, tg.last_read_post_number),
        updated_at = :now
      FROM topic_allowed_groups tag
      INNER JOIN group_users gu ON gu.group_id = tag.group_id
      WHERE gu.user_id = :user_id
      AND tag.topic_id = :topic_id
      AND tg.topic_id = :topic_id
      RETURNING
        tg.group_id
    SQL

    updated_groups =
      DB.query(
        update_query,
        user_id: user.id,
        topic_id: topic_id,
        post_number: post_number,
        now: DateTime.now,
      )
  end

  def self.create_topic_group(user, topic_id, post_number, updated_group_ids)
    query = <<~SQL
      INSERT INTO topic_groups (topic_id, group_id, last_read_post_number, created_at, updated_at)
      SELECT tag.topic_id, tag.group_id, :post_number, :now, :now
        FROM topic_allowed_groups tag
        INNER JOIN group_users gu ON gu.group_id = tag.group_id
        WHERE gu.user_id = :user_id
        AND tag.topic_id = :topic_id
    SQL

    query += "AND NOT(tag.group_id IN (:already_updated_groups))" if updated_group_ids.present?

    query += <<~SQL
      ON CONFLICT(topic_id, group_id)
      DO UPDATE SET last_read_post_number = :post_number, created_at = :now, updated_at = :now
    SQL

    DB.exec(
      query,
      user_id: user.id,
      topic_id: topic_id,
      post_number: post_number,
      now: DateTime.now,
      already_updated_groups: updated_group_ids,
    )
  end
end

# == Schema Information
#
# Table name: topic_groups
#
#  id                    :bigint           not null, primary key
#  group_id              :integer          not null
#  topic_id              :integer          not null
#  last_read_post_number :integer          default(0), not null
#  created_at            :datetime         not null
#  updated_at            :datetime         not null
#
# Indexes
#
#  index_topic_groups_on_group_id_and_topic_id  (group_id,topic_id) UNIQUE
#