# typed: strict
# frozen_string_literal: true

class ApplicationPolicy
  extend T::Sig

  sig { returns(T.nilable(T.any(User, IpAddressRole))) }
  attr_reader :user

  sig { returns(T.untyped) }
  attr_reader :record

  sig do
    params(user: T.nilable(T.any(User, IpAddressRole)), record: T.untyped).void
  end
  def initialize(user, record)
    @user = user
    @record = record
  end

  sig { returns(String) }
  def cache_key
    # find all the policy methods that the subclass defines up to ApplicationPolicy
    klass = T.let(self.class, T.class_of(ApplicationPolicy))
    methods = []

    while klass < ApplicationPolicy
      methods.concat(klass.instance_methods(false))
      klass = T.cast(klass.superclass, T.class_of(ApplicationPolicy))
    end
    methods.uniq!
    methods.sort!
    method_values_string =
      methods.map { |method| "#{method}:#{send(method)}" }.join("/")
    "#{self.class.name}::#{Digest::SHA256.hexdigest(method_values_string)[0..16]}"
  end

  sig(:final) { returns(T::Boolean) }
  def is_role_admin?
    user&.admin? || false
  end

  sig(:final) { returns(T::Boolean) }
  def is_role_moderator?
    user&.moderator? || false
  end

  sig(:final) { returns(T::Boolean) }
  def is_role_at_least_moderator?
    is_role_moderator? || is_role_admin?
  end

  sig(:final) { returns(T::Boolean) }
  def is_role_user?
    user&.user? || false
  end

  sig(:final) { returns(T::Boolean) }
  def is_role_at_least_user?
    is_role_user? || is_role_moderator? || is_role_admin?
  end

  sig(:final) { returns(T::Boolean) }
  def is_real_user?
    user&.is_a?(User) || false
  end

  sig { returns(T::Boolean) }
  def index?
    false
  end

  sig { returns(T::Boolean) }
  def show?
    false
  end

  sig { returns(T::Boolean) }
  def create?
    false
  end

  sig { returns(T::Boolean) }
  def new?
    create?
  end

  sig { returns(T::Boolean) }
  def update?
    false
  end

  sig { returns(T::Boolean) }
  def edit?
    update?
  end

  sig { returns(T::Boolean) }
  def destroy?
    false
  end

  sig { returns(T::Boolean) }
  def view_ip_address?
    is_role_admin?
  end

  class Scope
    extend T::Sig

    sig do
      params(user: T.nilable(T.any(User, IpAddressRole)), scope: T.untyped).void
    end
    def initialize(user, scope)
      @user = user
      @scope = scope
    end

    sig { returns(T.untyped) }
    def resolve
      raise NoMethodError, "You must define #resolve in #{self.class}"
    end

    private

    sig { returns(T.nilable(T.any(User, IpAddressRole))) }
    attr_reader :user

    sig { returns(T.untyped) }
    attr_reader :scope
  end
end
