module BeefCake
  class User < BeefCake::Base
    attributes :name, :ldap_login, :email, :active, :attached_permissions
    associations :roles, :memberships, :permissions

    self.primary_attribute = :ldap_login

    validates :ldap_login, presence: true

    def self.all(options = {})
      return empty_response if options[:text].blank?

      page = options[:page].presence || 1
      search_term = options[:text].downcase

      users = Guardian::User.all(options).map do |user|
        from_attributes(ldap_login: user.ldap_login, name: user.name, email: user.email)
      end

      users = users.select do |user|
        !user.search_string.index(search_term).nil?
      end

      users_count = users.length
      index = (page.to_i - 1) * PER_PAGE
      users = users.sort_by(&:ldap_login)[index...index + PER_PAGE]

      paginate users, per_page: PER_PAGE, total_count: users_count
    end

    def self.find(id, email: nil)
      data = twirp_data(client.get_user(
                          Twitch::Fulton::Beefcake::GetUserRequest.new(id: id.to_s)
      ))

      from_attributes(
        ldap_login: id,
        email: email,
        active: data.active,
        roles: data.role_memberships
          .map do |m|
            Role.from_attributes(id: m.id, name: m.name)
          end,
        attached_permissions: data.permissions
          .select { |p| p.permission.legacy }
          .each_with_object({}) do |p, m|
            m[p.permission.legacy.id] = AttachedPermission.from_attributes(
              id: p.id,
              permission: Permission.from_attributes(
                id: p.permission.legacy.id,
                canonical_name: p.permission.legacy.id,
                name: p.permission.legacy.name
              ),
              scope: p.scope
            )
          end,
        permissions: data.permissions
          .select { |p| p.permission.legacy }
          .map { |p| p.permission.legacy }
          .map do |p|
            Permission.from_attributes(
              id: p.id,
              canonical_name: p.id
            )
          end,
        memberships: data.role_memberships
          .map do |m|
            Membership.from_attributes(
              id: Membership.composite_key(role_id: m.id, uid: data.id),
              uid: data.id,
              role_id: m.id,
              role_name: m.name,
              expires_at: m.membership_expiration.nil? ? nil : Time.at(m.membership_expiration.seconds).to_date
            )
          end
      )
    end

    def reactivate
      resp = twirp_data(client.reactivate_user(
                          Twitch::Fulton::Beefcake::ReactivateUserRequest.new(id: ldap_login)
      ))
      return !resp.nil?
    end

    def self.empty_response
      paginate []
    end

    def exists?
      return !Guardian::User.find(ldap_login).blank?
    end

    def search_string
      [ldap_login, name, email].join(' ').downcase
    end

    def permitted?(permission_name)
      permission_names.include?(permission_name)
    end

    def permitted_on_twitch_user?(permission_name, twitch_user)
      ap = attached_permissions[permission_name]
      return false if ap.nil?
      ap.permitted_on_twitch_user?(twitch_user)
    end

    def permission_names
      permissions
        .map(&:id)
    end

    def role_ids=(new_role_ids)
      @roles = new_role_ids.map do |new_role_id|
        {id: new_role_id}
      end
    end

    def twitch_ldap_user_name
      # TODO: temporary fix since backends are expecting this.
      # See https://twitch.slack.com/archives/C69A8EJFK/p1578536107081700
      ldap_login.start_with?("#{BeefCake::Realm::TITAN_SUPPORT.id}:") ? 'titan-user' : ldap_login
    end

    def any_permission?
      permissions.any?
    end

    def admin?
      return permitted?(Permission.for(:admin_permissions))
    end

    def save
      return false unless valid?

      roles.each do |role|
        handle_error(client.add_user_to_role(
                       Twitch::Fulton::Beefcake::AddUserToRoleRequest.new(
                         role_id: role.id,
                         user_id: ldap_login
                       )
        ))
      end
      true
    end
  end
end
