# frozen_string_literal: true

module Loco
  class Notification
    class Fetcher
      attr_accessor :max_size

      def initialize(
        synced_at:,
        permissions: [],
        recipient_token: nil,
        max_size: nil
      )
        @synced_at = synced_at
        @permissions = permissions
        @recipient_token = recipient_token
        @notifications = nil
        @max_size = max_size || Loco::Config.notifications_size
      end

      def formatted_notifications
        notifications.map(&:compact)
      end

      def next_sync_time
        if notifications.size == max_size
          notifications.last.created_at
        else
          Time.current
        end
      end

      private

      def sync_time
        Time.zone.parse @synced_at
      end

      def default_scope
        Notification.order('created_at ASC')
                    .where('created_at > ?', sync_time)
      end

      # OPTIMIZE: one query
      def notifications
        return @notifications if @notifications

        notifications = notifications_for_all
        notifications += notifications_behind_permissions
        notifications += notifications_behind_token if @recipient_token
        @notifications = notifications.sort_by(&:created_at)[0, max_size]
      end

      def notifications_for_all
        default_scope.where(
          recipient_class: nil,
          recipient_id: nil,
          recipient_token: nil
        ).first max_size
      end

      def notifications_behind_permissions
        notifications = []
        @permissions.each do |resource|
          next unless resource

          notifications += notification_for_resource resource
        end
        notifications
      end

      def notifications_behind_token
        default_scope.where(recipient_token: @recipient_token).first max_size
      end

      def notification_for_resource(resource)
        if resource.instance_of? Class
          sql = 'recipient_class = ? AND recipient_id IS NULL'
          return default_scope.where(sql, resource.to_s).first max_size
        end
        klass = resource.class.name
        cond1 = '(recipient_class = ? AND recipient_id = ?)'
        cond2 = '(recipient_class = ? AND recipient_id IS NULL)'
        sql = "#{cond1} OR #{cond2}"
        default_scope.where(sql, klass, resource.id, klass).first max_size
      end
    end
  end
end