# frozen_string_literal: true

module Migrations::Uploader
  module Tasks
    class Fixer < Base
      def run!
        return if max_count.zero?

        puts "Fixing missing uploads..."

        status_thread = start_status_thread
        consumer_threads = start_consumer_threads
        producer_thread = start_producer_thread

        producer_thread.join
        work_queue.close
        consumer_threads.each(&:join)
        status_queue.close
        status_thread.join
      end

      private

      def max_count
        @max_count ||=
          uploads_db.db.query_single_splat("SELECT COUNT(*) FROM uploads WHERE upload IS NOT NULL")
      end

      def enqueue_jobs
        uploads_db
          .db
          .query(
            "SELECT id, upload FROM uploads WHERE upload IS NOT NULL ORDER BY rowid DESC",
          ) { |row| work_queue << row }
      end

      def instantiate_task_resource
        OpenStruct.new(url: "")
      end

      def handle_status_update(result)
        @current_count += 1

        case result[:status]
        when :ok
          # ignore
        when :error
          @error_count += 1
          puts " Error in #{result[:id]}"
        when :missing
          @missing_count += 1
          puts " Missing #{result[:id]}"

          uploads_db.db.execute("DELETE FROM uploads WHERE id = ?", result[:id])
          Upload.delete_by(id: result[:upload_id])
        end
      end

      def process_upload(row, fake_upload)
        upload = JSON.parse(row[:upload], symbolize_names: true)
        fake_upload.url = upload[:url]
        path = add_multisite_prefix(discourse_store.get_path_for_upload(fake_upload))

        status = file_exists?(path) ? :ok : :missing

        update_status_queue(row, upload, status)
      rescue StandardError => error
        puts error.message
        status = :error
        update_status_queue(row, upload, status)
      end

      def update_status_queue(row, upload, status)
        status_queue << { id: row[:id], upload_id: upload[:id], status: status }
      end

      def log_status
        error_count_text = error_count > 0 ? "#{error_count} errors".red : "0 errors"
        print "\r%7d / %7d (%s, %s missing)" %
                [current_count, max_count, error_count_text, missing_count]
      end
    end
  end
end