#!/usr/bin/env ruby
require "thor"
require File.expand_path("../../config/environment", __FILE__)

class CollectionCLI < Thor
  desc "prune", "removes all empty collections"
  def prune
    Collection.find_each { |it| it.destroy if it.models.empty? && it.collections.empty? }
  end
end

class CreatorCLI < Thor
  desc "prune", "removes all creators that aren't associated with any models"
  def prune
    Creator.find_each { |it| it.destroy if it.models.empty? }
  end
end

class MailCLI < Thor
  desc "test_email", "sends test email"
  def test
    UserMailer.with(user: User.find(1)).account_approved.deliver_now # rubocop:disable Pundit/UsePolicyScope
  end
end

class ModelCLI < Thor
  desc "update_metadata", "reruns the metadata parser for all models"
  option :search, required: false, type: :string
  def update_metadata
    scope = Model
    scope = Search::ModelSearchService.new(scope).search(options[:search]) if options[:search]
    scope.find_each do |it|
      Scan::Model::ParseMetadataJob.perform_later(it.id)
      print "."
      sleep 0.01 # Slows down connections a bit so as not to saturate Redis
    end
    puts "\n#{scope.count} models queued for metadata parsing" # rubocop:disable Pundit/UsePolicyScope
  end

  desc "pregenerate_downloads", "generate downloadable ZIP files for all models"
  option :search, required: false, type: :string
  def pregenerate_downloads
    if !SiteSettings.pregenerate_downloads
      puts "ERROR: Enable proactive ZIP download creation in admin settings."
      return
    end
    scope = Model
    scope = Search::ModelSearchService.new(scope).search(options[:search]) if options[:search]
    scope.find_each do |it|
      it.pregenerate_downloads delay: 5.seconds, queue: :low
      print "."
      sleep 0.01 # Slows down connections a bit so as not to saturate Redis
    end
    puts "\n#{scope.count} models queued for download creation" # rubocop:disable Pundit/UsePolicyScope
  end
end

class ProblemCLI < Thor
  desc "prune", "removes any problems without an associated problematic object"
  def prune
    Upgrade::PruneOrphanedProblems.perform_now
  end

  desc "purge", "removes all problem records"
  option :type, required: false, type: :string, default: nil, aliases: :t, enum: Problem::CATEGORIES
  option :class, required: false, type: :string, default: nil, aliases: :c, enum: %w[Model ModelFile Library]
  def purge
    return unless ask("Are you sure you want to remove all problems", limited_to: %w[y n]) == "y"
    scope = Problem
    scope = scope.where(type: options[:type]) if options[:type]
    scope = scope.where(problematic_type: options[:class]) if options[:class]
    scope.destroy_all
  end
end

class TagCLI < Thor
  desc "purge", "removes all tags"
  def purge
    return unless ask("Are you sure you want to remove all tags?", limited_to: %w[y n]) == "y"
    ActsAsTaggableOn::Tagging.destroy_all
    ActsAsTaggableOn::Tag.destroy_all
  end
end

class UserCLI < Thor
  desc "approve", "approves a user"
  option :email, required: true, type: :string, aliases: :mail
  def approve
    u = User.find_by(email: options[:email])
    raise "User not found" if u.nil?
    u.update(approved: true)
    puts "\nUser #{u.email} approved"
  rescue RuntimeError
    puts "\nUser #{options[:email]} not found"
  end

  desc "password", "resets password for user"
  option :email, required: true, type: :string, aliases: :mail
  def password
    u = User.find_by(email: options[:email])
    raise "User not found" if u.nil?
    u.password = ask("Enter password: ", echo: false)
    puts "\n"
    u.password_confirmation = ask("Confirm password: ", echo: false)
    puts "\nPassword changed!" if u.save!
  rescue ActiveRecord::RecordInvalid => e
    puts "\n#{e}"
  rescue RuntimeError => e
    puts "\n#{e}"
  end
end

class LinksCommand < Thor
  desc "deduplicate", "removes duplicate links"
  def deduplicate
    Link.find_duplicated.each(&:remove_duplicates!)
  end
end

class ManyfoldCLI < Thor
  desc "creators", "manage creators"
  subcommand "creators", CreatorCLI

  desc "collections", "manage collections"
  subcommand "collections", CollectionCLI

  desc "email", "test email"
  subcommand "email", MailCLI

  desc "links", "manage links"
  subcommand "links", LinksCommand

  desc "models", "manage models"
  subcommand "models", ModelCLI

  desc "problems", "manage problems"
  subcommand "problems", ProblemCLI

  desc "tags", "manage tags"
  subcommand "tags", TagCLI

  desc "user", "manage users"
  subcommand "user", UserCLI
end

ManyfoldCLI.start(ARGV)
