namespace :katello do
  desc "Cleans backend objects (hosts) that are missing in one or more backend systems.  Run with COMMIT=true to commit changes."
  task :clean_backend_objects => ["environment", "check_ping"] do
    class BackendCleaner
      def initialize
        @candlepin_uuids = []
        @pulp_uuids = []
        @katello_candlepin_uuids = []
        @katello_pulp_uuids = []
      end

      def populate!
        @candlepin_uuids = Katello::Resources::Candlepin::Consumer.all_uuids
        @katello_candlepin_uuids = Katello::Host::SubscriptionFacet.pluck(:uuid).compact

        @pulp_uuids = ::Katello.pulp_server.extensions.consumer.retrieve_all.map { |consumer| consumer['id'] }
        @katello_pulp_uuids = Katello::Host::ContentFacet.pluck(:uuid).compact
      end

      def hosts_with_no_subscriptions
        ::Host.where(:id => Katello::Host::SubscriptionFacet.where(:uuid => @katello_candlepin_uuids - @candlepin_uuids).select(:host_id))
      end

      def hosts_with_no_content
        ::Host.where(:id => Katello::Host::ContentFacet.where(:uuid => @katello_pulp_uuids - @pulp_uuids).select(:host_id))
      end

      def hosts_with_nil_facets
        nil_sub = Katello::Host::SubscriptionFacet.where(:uuid => nil).select(:host_id).to_sql
        ::Host.where(" id in (#{nil_sub})")
      end

      def cp_orphaned_host_uuids
        @candlepin_uuids - @katello_candlepin_uuids
      end

      def pulp_orphaned_host_uuids
        @pulp_uuids - @katello_pulp_uuids
      end
    end

    def cleanup_hosts(cleaner)
      cleaner.hosts_with_nil_facets.each do |host|
        print "Host #{host.id} #{host.name} is partially missing subscription information.  Un-registering\n"
        execute("Failed to delete host") { Katello::RegistrationManager.unregister_host(host, host_unregister_options(host)) }
      end

      cleaner.hosts_with_no_subscriptions.each do |host|
        print "Host #{host.id} #{host.name} #{host.subscription_facet.try(:uuid)} is partially missing subscription information.  Un-registering\n"
        execute("Failed to delete host") { Katello::RegistrationManager.unregister_host(host, host_unregister_options(host)) }
      end

      cleaner.hosts_with_no_content.each do |host|
        print "Host #{host.id} #{host.name} #{host.content_facet.try(:uuid)} is partially missing content information.  Un-registering\n"
        execute("Failed to delete host") { Katello::RegistrationManager.unregister_host(host, host_unregister_options(host)) }
      end
    end

    def clean_backend_orphans(cleaner)
      cp_uuids = cleaner.cp_orphaned_host_uuids
      print "#{cp_uuids.count} orphaned consumer id(s) found in candlepin.\n"
      print "Candlepin orphaned consumers: #{cp_uuids}\n"
      cp_uuids.each do |consumer_id|
        execute("exception when destroying candlepin consumer #{consumer_id}") { Katello::Resources::Candlepin::Consumer.destroy(consumer_id) }
      end

      pulp_uuids = cleaner.pulp_orphaned_host_uuids
      print "#{pulp_uuids.count} orphaned consumer id(s) found in pulp.\n"
      print "Pulp orphaned consumers: #{pulp_uuids}\n"
      pulp_uuids.each do |consumer_id|
        execute("exception when destroying pulp consumer #{consumer_id}") { Katello.pulp_server.extensions.consumer.delete(consumer_id) }
      end
    end

    def host_unregister_options(host)
      if host.managed? || host.compute_resource
        print "Leaving provisioning record for #{host.name} in place, it is either managed or assigned to a compute resource."
        {:unregistering => true}
      else
        {}
      end
    end

    def commit?
      ENV['COMMIT'] == 'true' || ENV['FOREMAN_UPGRADE'] == '1'
    end

    # rubocop:disable Lint/SuppressedException
    def execute(error_msg)
      if commit?
        yield
      end
    rescue RestClient::ResourceNotFound
    rescue => e
      print error_msg
      print e.inspect
    end

    unless commit?
      print "The following changes will not actually be performed.  Rerun with COMMIT=true to apply the changes\n"
    end

    SETTINGS[:katello][:candlepin][:bulk_load_size] = 1_500
    User.current = User.anonymous_admin
    cleaner = BackendCleaner.new
    cleaner.populate!

    cleanup_hosts(cleaner)
    clean_backend_orphans(cleaner)
  end
end