class BulletTrain::Themes::Light::CustomThemeFileReplacer

def adjust_directory_hierarchy(file_name, theme_name)

different after the file is ejected into the main application.
This addresses one specific file where the hierarchy is
def adjust_directory_hierarchy(file_name, theme_name)
  file_name.match?("lib/bullet_train/themes/#{theme_name}") ? file_name.gsub(/\/app/, "") : file_name
end

def build_main_app_file_name(original_theme, custom_theme, custom_gem_file)

files' contents. Then later on we actually rename the new gem's file names.
Here, we build the correct string that is in the main app to compare the
already been changed in the main app when the original theme was ejected.
theme stay the same, i.e. - tailwind.light.config.js. However, the names have
Since we're cloning a fresh gem, file names that contain the original
def build_main_app_file_name(original_theme, custom_theme, custom_gem_file)
  main_app_file = custom_gem_file
  custom_gem_file_hierarchy = custom_gem_file.split("/")
  if custom_gem_file_hierarchy.last.match?(original_theme)
    custom_gem_file_hierarchy.last.gsub!(original_theme, custom_theme)
    main_app_file = custom_gem_file_hierarchy.join("/")
  end
  main_app_file
end

def constantize_from_snake_case(str)

i.e. - foo_bar or foo-bar to FooBar
def constantize_from_snake_case(str)
  str.split(/[_|-]/).map(&:capitalize).join
end

def default_files_to_replace(original_theme)

aren't ejected to the developer's main app, but still need to be changed.
These files represent ones such as "./lib/bullet_train/themes/light.rb" which
def default_files_to_replace(original_theme)
  # TODO: Add this file and the FileReplacer module once they're added to the main branch.
  [
    "/bullet_train-themes-#{original_theme}.gemspec",
    "/app/assets/config/bullet_train_themes_#{original_theme}_manifest.js",
    "/lib/tasks/bullet_train/themes/#{original_theme}_tasks.rake",
    "/test/bullet_train/themes/#{original_theme}_test.rb"
  ].map { |file| @repo_path + file }
end

def directories_to_remove_from_main_app(custom_theme)

def directories_to_remove_from_main_app(custom_theme)
  [
    "./app/assets/stylesheets/#{custom_theme}/",
    "./app/views/themes/#{custom_theme}/",
    "./app/lib/"
  ].map { |directory| directory unless directory == "./app/lib/" && Dir.empty?(directory) }
end

def ejected_files_to_replace(original_theme, custom_theme)

so we use `original_theme` for specific file names below.
the custom theme name, but the FILE names are still the same from when they were cloned,
By the time we call this method we have already updated the new gem's directories with
def ejected_files_to_replace(original_theme, custom_theme)
  [
    Dir.glob("#{@repo_path}/app/assets/stylesheets/#{custom_theme}/**/*.css"),
    Dir.glob("#{@repo_path}/app/assets/stylesheets/#{custom_theme}/**/*.scss"),
    Dir.glob("#{@repo_path}/app/views/themes/#{custom_theme}/**/*.html.erb"),
    "/app/javascript/application.#{original_theme}.js",
    "/tailwind.#{original_theme}.config.js",
    "/app/lib/bullet_train/themes/#{original_theme}.rb",
    # The Glob up top doesn't grab the #{original_theme}.tailwind.css file, so we set that here.
    "/app/assets/stylesheets/#{original_theme}.tailwind.css",
    "/tailwind.mailer.#{original_theme}.config.js"
  ].flatten.map { |file| file.match?(/^#{@repo_path}/) ? file : @repo_path + file }
end

def files_to_remove_from_main_app(custom_theme)

def files_to_remove_from_main_app(custom_theme)
  [
    Dir.glob("./app/assets/stylesheets/#{custom_theme}/**/*.css"),
    Dir.glob("./app/assets/stylesheets/#{custom_theme}/**/*.scss"),
    "./app/assets/stylesheets/#{custom_theme}.tailwind.css",
    "./app/javascript/application.#{custom_theme}.js",
    "./app/lib/bullet_train/themes/#{custom_theme}.rb",
    Dir.glob("./app/views/themes/#{custom_theme}/**/*.html.erb"),
    "./tailwind.mailer.#{custom_theme}.config.js",
    "./tailwind.#{custom_theme}.config.js",
  ].flatten
end

def files_whose_contents_need_to_be_replaced(custom_theme)

def files_whose_contents_need_to_be_replaced(custom_theme)
  [
    "/app/assets/stylesheets/#{custom_theme}.tailwind.css",
    "/app/views/themes/#{custom_theme}/layouts/_account.html.erb",
    "/app/views/themes/#{custom_theme}/layouts/_devise.html.erb",
    "/bin/rails",
    "/lib/bullet_train/themes/#{custom_theme}/engine.rb",
    "/lib/bullet_train/themes/#{custom_theme}/version.rb",
    "/lib/bullet_train/themes/#{custom_theme}.rb",
    "/lib/tasks/bullet_train/themes/#{custom_theme}_tasks.rake",
    "/test/bullet_train/themes/#{custom_theme}_test.rb",
    "/test/dummy/app/views/layouts/mailer.html.erb",
    "/test/dummy/config/application.rb",
    "/bullet_train-themes-#{custom_theme}.gemspec",
    "/Gemfile",
    "/README.md"
  ].map { |file| @repo_path + file }
end

def initialize(custom_theme)

def initialize(custom_theme)
  @repo_path = "./local/bullet_train-themes-#{custom_theme}"
end

def replace_theme(original_theme, custom_theme)

def replace_theme(original_theme, custom_theme)
  # Rename the directories
  [
    "/app/assets/stylesheets/bullet_train/themes/#{original_theme}/",
    "/app/assets/stylesheets/#{original_theme}/",
    "/app/views/themes/#{original_theme}/",
    "/lib/bullet_train/themes/#{original_theme}/"
  ].map { |file| @repo_path + file }.each do |original_directory|
    custom_directory = original_directory.gsub(/(.*)(#{original_theme})(\/$)/, '\1' + custom_theme + '\3')
    FileUtils.mv(original_directory, custom_directory)
  end
  # Only compare ejected files.
  files_to_replace =
    ejected_files_to_replace(original_theme, custom_theme).map { |file| {file_name: file, must_compare: true} } +
    default_files_to_replace(original_theme).map { |file| {file_name: file, must_compare: false} }
  # Replace the file contents and rename the files.
  files_to_replace.each do |custom_gem_file|
    # All of the files we want to compare against the fresh gem are in the main app.
    main_app_file = build_main_app_file_name(original_theme, custom_theme, custom_gem_file[:file_name].gsub(@repo_path, "."))
    custom_gem_file[:file_name] = adjust_directory_hierarchy(custom_gem_file[:file_name], original_theme)
    # The content in the main app should replace the cloned gem files.
    begin
      if custom_gem_file[:must_compare] && !BulletTrain::Themes::Light::FileReplacer.files_have_same_content?(custom_gem_file[:file_name], main_app_file)
        BulletTrain::Themes::Light::FileReplacer.replace_content(old: custom_gem_file[:file_name], new: main_app_file)
      end
    rescue Errno::ENOENT => _
      puts "Skipping `#{main_app_file}` because it isn't present."
    end
    # Only rename file names that still have the original theme in them, i.e. - ./tailwind.config.light.js
    if File.basename(custom_gem_file[:file_name]).match?(original_theme)
      main_app_file = adjust_directory_hierarchy(main_app_file, custom_theme)
      new_file_name = main_app_file.gsub(/^\./, @repo_path).gsub(original_theme, custom_theme)
      File.rename(custom_gem_file[:file_name], new_file_name)
    end
  end
  # Change the content of specific files that contain the orignal theme's string.
  # i.e. - `module Light` and `tailwind.light.config`.
  constantized_original = constantize_from_snake_case(original_theme)
  constantized_custom = constantize_from_snake_case(custom_theme)
  files_whose_contents_need_to_be_replaced(custom_theme).each do |file|
    new_lines = []
    File.open(file, "r") do |f|
      new_lines = f.readlines
      new_lines = new_lines.map do |line|
        # We want the original theme it's being edited from when creating a new theme.
        # We also remove mattr_accessor in the eject task, so we need to add it back here.
        if f.path == "#{@repo_path}/lib/bullet_train/themes/#{custom_theme}.rb" && line.match?("class Theme < BulletTrain::Themes::")
          line = "      mattr_accessor :color, default: :blue\n      class Theme < BulletTrain::Themes::#{constantize_from_snake_case(original_theme)}::Theme\n"
        else
          # `_account.html.erb` and `_devise.html.erb` have tailwind classes that contain `light`.
          # We shouldn't be replacing the classes with the custom theme string, so we skip it here.
          # TODO: We should change this Regexp to check if the original theme is prefixed with `-`.
          # If it is, we ignore the string if it's not prefixed with `bullet_train-themes-`,
          line.gsub!(original_theme, custom_theme) unless line.match?("bg-light-gradient")
          line.gsub!(constantized_original, constantized_custom)
        end
        line
      end
    end
    File.open(file, "w") do |f|
      f.puts new_lines.join
    end
  end
  # The contents in this specific main app file don't have the require statements which the gem
  # originally has, so we add those back after moving the main app file contents to the gem.
  new_lines = nil
  File.open("#{@repo_path}/lib/bullet_train/themes/#{custom_theme}.rb", "r") do |file|
    new_lines = file.readlines
    require_lines =
      <<~RUBY
        require "bullet_train/themes/#{custom_theme}/version"
        require "bullet_train/themes/#{custom_theme}/engine"
        require "bullet_train/themes/#{original_theme}"
      RUBY
    new_lines.unshift(require_lines)
  end
  File.open("#{@repo_path}/lib/bullet_train/themes/#{custom_theme}.rb", "w") do |file|
    file.puts new_lines.flatten.join
  end
  # Since we're generating a new gem, it should be version 1.0
  File.open("#{@repo_path}/lib/bullet_train/themes/#{custom_theme}/version.rb", "r") do |file|
    new_lines = file.readlines
    new_lines = new_lines.map { |line| line.match?("VERSION") ? "      VERSION = \"1.0\"\n" : line }
  end
  File.open("#{@repo_path}/lib/bullet_train/themes/#{custom_theme}/version.rb", "w") do |file|
    file.puts new_lines.join
  end
  # Remove files and directories from the main application.
  files_to_remove_from_main_app(custom_theme).each { |file| File.delete(file) }
  directories_to_remove_from_main_app(custom_theme).each do |directory|
    FileUtils.rm_rf(directory) unless directory.nil?
  end
  # Update the author and email.
  # If the developer hasn't set these yet, this should simply return empty strings.
  author = `git config --global user.name`.chomp
  email = `git config --global user.email`.chomp
  File.open("#{@repo_path}/bullet_train-themes-#{custom_theme}.gemspec", "r") do |file|
    new_lines = file.readlines
    new_lines = new_lines.map do |line|
      if line.match?("spec.authors")
        "  spec.authors = [\"#{author}\"]\n"
      elsif line.match?("spec.email")
        "  spec.email = [\"#{email}\"]\n"
      else
        line
      end
    end
  end
  File.open("#{@repo_path}/bullet_train-themes-#{custom_theme}.gemspec", "w") do |file|
    file.puts new_lines.join
  end
end