class Generators::Avo::EjectGenerator

def add_scope?(component)

def add_scope?(component)
  (component.starts_with?("avo/views/") || component.starts_with?("avo/fields/")) && options[:scope].present?
end

def confirm_ejection_on(path, is_directory: false)

def confirm_ejection_on(path, is_directory: false)
  say("By ejecting the '#{path}'#{" directory" if is_directory} \033[1myou'll take on the responsibility for maintain it.", :yellow)
  yes?("Are you sure you want to eject the '#{path}'#{" directory" if is_directory}? [y/N]", :yellow)
end

def dir_exists?(path)

def dir_exists?(path)
  path.present? && Dir.exist?(::Avo::Engine.root.join(path))
end

def eject(path, dest_path = nil, is_directory: false)

def eject(path, dest_path = nil, is_directory: false)
  method = is_directory ? :directory : :copy_file
  send method, ::Avo::Engine.root.join(path), ::Rails.root.join(dest_path || path)
end

def eject_component(component_to_eject = options[:component], confirmation: true)

def eject_component(component_to_eject = options[:component], confirmation: true)
  # Underscore the component name
  # Example: Avo::Views::ResourceIndexComponent => avo/views/resource_index_component
  component = component_to_eject.underscore
  # Get the component path for both, the rb and erb files
  rb, erb = ["app/components/#{component}.rb", "app/components/#{component}.html.erb"]
  # Return if one of the components doesn't exist
  if !path_exists?(rb) || !path_exists?(erb)
    return say("Failed to find the `#{component_to_eject}` component.", :yellow)
  end
  # Add the scope to the component if it's possible
  if add_scope? component
    component = if component.starts_with?("avo/views/")
      component.gsub("avo/views/", "avo/views/#{options[:scope].underscore}/")
    elsif component.starts_with?("avo/fields/")
      component.gsub("avo/fields/", "avo/fields/#{options[:scope].underscore}/")
    end
    added_scope = true
  end
  # Confirm the ejection
  if confirmation
    return if !confirm_ejection_on(component.camelize)
  end
  # Get the destination path for both, the rb and erb files
  dest_rb = "#{::Avo.configuration.view_component_path}/#{component}.rb"
  dest_erb = "#{::Avo.configuration.view_component_path}/#{component}.html.erb"
  # Eject the component
  eject rb, dest_rb
  eject erb, dest_erb
  # Remame the component class if scope was added
  # Example: Avo::Views::ResourceIndexComponent => Avo::Views::Admins::ResourceIndexComponent
  if added_scope
    [dest_rb, dest_erb].each do |path|
      if component.starts_with?("avo/views/")
        modified_content = File.read(path).gsub("Avo::Views::", "Avo::Views::#{options[:scope].camelize}::")
      elsif component.starts_with?("avo/fields/") && options["field-components"].present?
        modified_content = File.read(path).gsub("#{options["field-components"].camelize}Field", "#{options[:scope].camelize}::#{options["field-components"].camelize}Field")
      end
      File.open(path, "w") do |file|
        file.puts modified_content
      end
    end
    if component.starts_with?("avo/views/")
      say "You can now use this component on any resource by configuring the 'self.components' option.\n" \
          "  self.components = {\n" \
          "    #{component.split("/").last}: #{component.camelize}\n" \
          "  }", :green
    elsif component.starts_with?("avo/fields/")
      say "You can now use this component on any field by configuring the 'components' option.\n" \
          "  field :name, as: :#{options["field-components"]}, components: {\n" \
          "    #{component.split("/").last}: #{component.camelize}\n" \
          "  }", :green
    end
  end
end

def eject_field_components

def eject_field_components
  # Check if the field exists
  field_path = "lib/avo/fields/#{options["field-components"]}_field.rb"
  return say("Failed to find the `#{options["field-components"]}` field.", :yellow) if !path_exists?(field_path)
  # Eject single component if view is specified
  if options[:view].present?
    return eject_component "Avo::Fields::#{options["field-components"].camelize}Field::#{options[:view].camelize}Component"
  end
  # Check if the field components directory exist
  components_path = "app/components/avo/fields/#{options["field-components"]}_field"
  return say("Failed to find the `#{options["field-components"]}` field components.", :yellow) if !dir_exists?(components_path)
  # Build the destination path for the components directory add the scope
  destination_components_path = "#{::Avo.configuration.view_component_path}/#{components_path.gsub("app/components/", "")}"
  if options[:scope].present?
    destination_components_path = destination_components_path.gsub("avo/fields/", "avo/fields/#{options[:scope].underscore}/")
  end
  # Confirm the ejection
  confirm_ejection_on destination_components_path, is_directory: true
  # Eject the components directory
  eject components_path, destination_components_path, is_directory: true
  # Rename the component classes if scope was added
  if options[:scope].present?
    Dir.glob("#{destination_components_path}/*").each do |file|
      modified_content = File.read(file).gsub("#{options["field-components"].camelize}Field", "#{options[:scope].camelize}::#{options["field-components"].camelize}Field")
      File.open(file, "w") do |open_file|
        open_file.puts modified_content
      end
    end
  end
end

def eject_partial

def eject_partial
  if options[:partial].starts_with?(":")
    template_id = path_to_sym options[:partial]
    template_path = TEMPLATES[template_id]
    if path_exists? template_path
      return unless confirm_ejection_on template_path
      eject template_path
    else
      say("Failed to find the `#{template_id.to_sym}` template.", :yellow)
    end
  elsif path_exists? options[:partial]
    return unless confirm_ejection_on template_path
    eject options[:partial]
  else
    say("Failed to find the `#{options[:partial]}` template.", :yellow)
  end
end

def handle

def handle
  if options[:partial].present?
    eject_partial
  elsif options[:component].present?
    eject_component
  elsif options["field-components"].present?
    eject_field_components
  else
    say "Please specify a partial or a component to eject.\n" \
        "Examples: rails g avo:eject --partial :logo\n" \
        "          rails g avo:eject --partial app/views/layouts/avo/application.html.erb\n" \
        "          rails g avo:eject --component Avo::Index::TableRowComponent\n" \
        "          rails g avo:eject --component avo/index/table_row_component\n" \
        "          rails g avo:eject --field-components trix\n" \
        "          rails g avo:eject --field-components trix --scope users\n" \
        "          rails g avo:eject --field-components text --scope users --view edit\n" \
        "          rails g avo:eject --component Avo::Views::ResourceIndexComponent --scope users\n" \
        "          rails g avo:eject --component avo/views/resource_index_component --scope users", :yellow
  end
end

def path_exists?(path)

def path_exists?(path)
  path.present? && File.file?(::Avo::Engine.root.join(path))
end

def path_to_sym(filename)

def path_to_sym(filename)
  template_id = filename.dup
  template_id[0] = ""
  template_id.to_sym
end