module Notifiable
  extend ActiveSupport::Concern

  included do
    helper_method :render_flash_notifications
    helper_method :flash_notification_stream_items
  end

  private
    def render_flash_notifications
      notifications = flash.flat_map { |type, data| resolve_notifications(type, data) }.compact

      view_context.safe_join(
        notifications.map { |notification| view_context.render(**notification) }
      )
    end

    def flash_notification_stream_items
      items = flash.flat_map do |type, data|
        notifications = resolve_notifications(type, data)

        if type == "cta"
          notifications.map { |notification| turbo_stream.replace("cta", **notification) }
        else
          notifications.map { |notification| turbo_stream.append("notification-tray", **notification) }
        end
      end.compact

      # If rendering flash notifications via stream, we mark them as used to avoid
      # them being rendered again on the next page load
      flash.clear

      items
    end

    def resolve_cta(cta)
      case cta[:type]
      when "category_rule"
        { partial: "rules/category_rule_cta", locals: { cta: } }
      end
    end

    def resolve_notifications(type, data)
      case type
      when "alert"
        [ { partial: "shared/notifications/alert", locals: { message: data } } ]
      when "cta"
        [ resolve_cta(data) ]
      when "notice"
        messages = Array(data)
        messages.map { |message| { partial: "shared/notifications/notice", locals: { message: message } } }
      else
        []
      end
    end
end
