class UserDeletion
  class ValidationError < Exception ; end

  attr_reader :user, :password

  def self.remove_favorites_for(user_id)
    user = User.find(user_id)
    Post.without_timeout do
      Post.raw_tag_match("fav:#{user_id}").where("true /* UserDeletion.remove_favorites_for */").find_each do |post|
        Favorite.remove(post: post, user: user)
      end
    end
  end

  def initialize(user, password)
    @user = user
    @password = password
  end

  def delete!
    validate
    clear_user_settings
    remove_favorites
    clear_tag_subscriptions
    clear_saved_searches
    rename
    reset_password
    create_mod_action
  end

private
  
  def create_mod_action
    ModAction.log("user ##{user.id} deleted")
  end

  def clear_tag_subscriptions
    TagSubscription.where(:creator_id => user.id).destroy_all
  end

  def clear_saved_searches
    SavedSearch.where(user_id: user.id).destroy_all
  end

  def clear_user_settings
    user.email = nil
    user.last_logged_in_at = nil
    user.last_forum_read_at = nil
    user.recent_tags = ''
    user.favorite_tags = ''
    user.blacklisted_tags = ''
    user.hide_deleted_posts = false
    user.show_deleted_children = false
    user.time_zone = "Eastern Time (US & Canada)"
    user.save!
  end

  def reset_password
    random = SecureRandom.hex(16)
    user.password = random
    user.password_confirmation = random
    user.old_password = password
    user.save!
  end

  def remove_favorites
    UserDeletion.delay(:queue => "default").remove_favorites_for(user.id)
  end

  def rename
    name = "user_#{user.id}"
    n = 0
    while User.where(:name => name).exists? && (n < 10)
      name += "~"
    end

    if n == 10
      raise ValidationError.new("New name could not be found")
    end

    user.name = name
    user.save!
  end

  def validate
    if !User.authenticate(user.name, password)
      raise ValidationError.new("Password is incorrect")
    end

    if user.level >= User::Levels::ADMIN
      raise ValidationError.new("Admins cannot delete their account")
    end
  end
end
