# frozen_string_literal: true

class ActivityPub::Activity::FeatureRequest < ActivityPub::Activity
  include Payloadable

  def perform
    return if non_matching_uri_hosts?(@account.uri, @json['id'])

    @collection = find_or_fetch_collection
    @featured_account = ActivityPub::TagManager.instance.uris_to_local_accounts([value_or_id(@json['object'])]).first

    return if @collection.nil? || @featured_account.nil?

    if AccountPolicy.new(@account, @featured_account).feature?
      accept_request!
    else
      reject_request!
    end
  end

  private

  def accept_request!
    collection_item = @collection.collection_items.create!(
      collection_item_attributes(:accepted)
    )

    notify_local_user!(collection_item)
    queue_delivery!(collection_item, ActivityPub::AcceptFeatureRequestSerializer)
  end

  def reject_request!
    collection_item = @collection.collection_items.build(
      collection_item_attributes(:rejected)
    )

    queue_delivery!(collection_item, ActivityPub::RejectFeatureRequestSerializer)
  end

  def find_or_fetch_collection
    uri = value_or_id(@json['instrument'])
    collection = @account.collections.find_by(uri:)
    return collection if collection.present?

    collection = ActivityPub::FetchRemoteFeaturedCollectionService.new.call(uri)
    return collection if collection.present? && collection.account == @account

    nil
  end

  def collection_item_attributes(state = :accepted)
    { account: @featured_account, activity_uri: @json['id'], state: }
  end

  def notify_local_user!(collection_item)
    LocalNotificationWorker.perform_async(collection_item.account_id, collection_item.id, collection_item.class.name, 'added_to_collection')
  end

  def queue_delivery!(collection_item, serializer)
    json = JSON.generate(serialize_payload(collection_item, serializer))
    ActivityPub::DeliveryWorker.perform_async(json, @featured_account.id, @account.inbox_url)
  end
end
