# frozen_string_literal: true namespace :rmu do

config_path = "#{Rails.root}/config/initializers/rails_module_unification"
config_exists = File.exist?(config_path)
require config_path if config_exists

# @example
#  rake rmu:migrate_resource Post
# @example
#  rake rmu:migrate_resource Api::Event

desc 'Moves all files related to a resource to the RMU directory'
task :migrate_resource, [:klass_name] => :environment do |_t, args|
  klass_name = args[:klass_name]

  # Given klass_name,
  # check known places where related files could be
  singular = possible_classes(klass_name)
  plural = possible_classes(klass_name, plural: true)

  possibilities = singular + plural

  possibilities.each do |possible_class|
    klass = possible_class.safe_constantize

    next unless klass

    location = location_of(klass)

    unless location
      puts "#{klass.name} could not be found"
      next
    end

    next if already_moved?(location)

    destination = destination_for(location)
    move_file(location, to: destination)
  end
end

def destination_for(path)
  # Rails.root does not include 'app/'
  project_root = Rails.root.to_s
  relative_path = path.sub(project_root, '')
  relative_path_parts = relative_path.split('/').reject(&:blank?)

  # remove app dir
  # ["app", "serializers", "hosted_event_serializer.rb"]
  # => ["serializers", "hosted_event_serializer.rb"]
  relative_path_parts.shift

  return if relative_path_parts.length < 2

  # resource type (controller, serializer, etc)
  # ["serializers", "hosted_event_serializer.rb"]
  # => serializer
  resource_type = relative_path_parts.shift.singularize

  # ["hosted_event_serializer.rb"]
  # => hosted_event_serializer.rb
  file_name = relative_path_parts.pop

  resource_name, extension = file_name.split("_#{resource_type}")

  namespace = relative_path_parts.join('/')

  destination = [
    project_root,
    'app',
    RailsModuleUnification.directory,
    'resources',
    namespace,
    resource_name.pluralize,
    resource_type
  ].reject(&:blank?).join('/')

  destination + extension
end

def move_file(from, to: nil)
  puts "Moving #{from} to #{to}"
  return unless to && from

  matches = /.+\/(.+\.\w+)/.match(to)
  file = matches[1]
  path = to.sub(file, '')

  unless File.directory?(path)
    puts 'creating directory...'
    FileUtils.mkdir_p(path)
  end

  FileUtils.move(from, to)
end

# See RESOURCE_SUFFIX_NAMES for total options
# PostSerializer
SINGULAR_RESOURCE_SUFFIXES = %w(
  Serializer
  Operations
  Presenters
  Policy
  Policies
).freeze

# PostsController
PLURAL_RESOURCE_SUFFIXES = %w(
  Controller
).freeze

def possible_classes(resource_name, plural: false)
  klass_name = plural ? resource_name.pluralize : resource_name
  suffixes = plural ? PLURAL_RESOURCE_SUFFIXES : SINGULAR_RESOURCE_SUFFIXES
  suffixes.map { |suffix| "#{klass_name}#{suffix}" }
end

def location_of(klass)
  # Flat default rails structure
  guessed_path = guess_file_path(klass)
  return guessed_path if File.exist?(guessed_path)

  # Try to find the file based on method source location
  # - will not work if a file doesn't define any methods
  #   ( empty sub classes )
  root = Rails.root.to_s
  possible_paths = klass.instance_methods(false).map do |m|
    klass.instance_method(m).source_location.first
  end.uniq

  possible_paths.select { |path| path.include?(root) }.first
end

def already_moved?(location)
  location.include?("#{RailsModuleUnification.directory}/resources")
end

def guess_file_path(klass)
  underscored = klass.name.underscore
  file_name = underscored + '.rb'
  resource_type = underscored.split('_').last

  guessed_path = File.join(
    Rails.root,
    'app',
    resource_type.pluralize,
    file_name
  )

  guessed_path
end

end