# frozen_string_literal: true

module Velour
  class InstallGenerator < Rails::Generators::Base
    MIN_REQUIRED_NODE_MAJOR = 18

    source_root File.expand_path("files", __dir__)

    def check_node
      unless tool_exists?("node")
        fail "Nodejs does not appear to be installed. Please install Nodejs v#{MIN_REQUIRED_NODE_MAJOR}+ to continue."
      end

      version = `node --version`
      major, minor, patch = version.delete_prefix("v").split(".").map(&:to_i)

      if major < MIN_REQUIRED_NODE_MAJOR
        fail "Vite requires Nodejs v#{MIN_REQUIRED_NODE_MAJOR}+, found v#{major}.#{minor}.#{patch} instead."
      end
    end

    def install_cssbundling_rails
      if Gem.loaded_specs.include?('cssbundling-rails')
        Rails.logger.info "cssbundling-rails gem already installed, skipping"
        return
      end

      Bundler.with_unbundled_env do
        gem "cssbundling-rails", "~> 1.0"
      end
    end

    def install_postcss
      rails_command "css:install:postcss"
    end

    def install_vite_gem
      if Gem.loaded_specs.include?('vite_rails')
        Rails.logger.info "vite_rails gem already installed, skipping"
        return
      end

      Bundler.with_unbundled_env do
        gem "vite_rails", "~> 3.0"
      end
    end

    def install_vite
      run "bundle exec vite install --package-manager #{js_package_manager}"
    end

    # Vite adds an extra web: entry to Procfile.dev, so let's remove it
    # see: https://github.com/ElMassimo/vite_ruby/issues/541
    def clean_up_vite
      return unless File.exist?("Procfile.dev")

      lines = File.readlines("Procfile.dev")
      indices = lines.each_with_index.filter_map do |line, index|
        line.strip.start_with?("web:") ? index : nil
      end

      return if indices.size < 1

      lines.delete_at(indices.last)

      File.write("Procfile.dev", lines.join)
    end

    def install_overmind
      if Gem.loaded_specs.include?('overmind')
        Rails.logger.info "overmind gem already installed, skipping"
        return
      end

      Bundler.with_unbundled_env do
        gem_group :development, :test do
          gem "overmind", "~> 2.0"
        end

        # not sure why this is necessary
        run "bundle install --quiet"
      end
    end

    def create_overmind_binstub
      Bundler.with_unbundled_env do
        run "bundle binstubs overmind"
      end
    end

    def copy_dev_script
      copy_file(
        File.join("bin", "dev"),
        File.join("bin", "dev")
      )

      chmod File.join("bin", "dev"), 0755
    end

    private

    # We support bun and yarn because that's what cssbundling-rails supports
    def js_package_manager
      using_bun? ? "bun" : "yarn"
    end

    def using_bun?
      tool_exists?('bun') && (
        File.exist?('bun.lockb') ||
        File.exist?('bun.lock') ||
        File.exist?('yarn.lock')
      )
    end

    def tool_exists?(tool)
      system "command -v #{tool} > /dev/null"
    end
  end
end
