# frozen_string_literal: true

module Account::InteractionPolicyConcern
  extend ActiveSupport::Concern

  included do
    composed_of :feature_interaction_policy, class_name: 'InteractionPolicy', mapping: { feature_approval_policy: :bitmap }
  end

  def feature_policy_as_keys(kind)
    raise ArgumentError unless kind.in?(%i(automatic manual))
    return local_feature_policy(kind) if local?

    sub_policy = feature_interaction_policy.send(kind)
    sub_policy.as_keys
  end

  # Returns `:automatic`, `:manual`, `:unknown`, ':missing` or `:denied`
  def feature_policy_for_account(other_account)
    return :denied if other_account.nil? || (local? && !discoverable?)
    return locked? && !followed_by?(other_account) && self != other_account ? :denied : :automatic if local?

    # Post author is always allowed to feature themselves
    return :automatic if self == other_account
    return :missing if feature_approval_policy.zero?

    automatic_policy = feature_interaction_policy.automatic
    following_self = nil
    followed_by_self = nil

    return :automatic if automatic_policy.public?

    if automatic_policy.followers?
      following_self = followed_by?(other_account)
      return :automatic if following_self
    end

    if automatic_policy.following?
      followed_by_self = following?(other_account)
      return :automatic if followed_by_self
    end

    # We don't know we are allowed by the automatic policy, considering the manual one
    manual_policy = feature_interaction_policy.manual

    return :manual if manual_policy.public?

    if manual_policy.followers?
      following_self = followed_by?(other_account) if following_self.nil?
      return :manual if following_self
    end

    if manual_policy.following?
      followed_by_self = following?(other_account) if followed_by_self.nil?
      return :manual if followed_by_self
    end

    return :unknown if [automatic_policy, manual_policy].any?(&:unsupported_policy?)

    :denied
  end

  private

  def local_feature_policy(kind)
    return [] if kind == :manual || !discoverable?

    [locked? ? :followers : :public]
  end
end
