module Dunlop::Generators::GeneratorHelpers
  extend ActiveSupport::Concern

  def inject_before_last_end(file_path, code)
    code << "\n" unless code.last == "\n"
    code = "  #{code}" unless code.first =~ /^\s/
    inject_into_file file_path, code, before: /^end/
  end

  module ClassMethods
    def next_migration_number(path)
      ActiveRecord::Generators::Base.next_migration_number(path)
    end
  end

  class DunlopGeneratorAttribute
    attr_reader :name
    def initialize(spec)
      @name, @type = spec.to_s.strip.split(':')
    end

    def type
      @type || 'string'
    end

    def column_name
      name.to_s.underscore.gsub(/\W/, '_')
    end

    def to_s
      name
    end

    def form_type
      case type
      when 'boolean' then 'boolean'
      else 'input'
      end
    end

    def boolean?
      type == 'boolean'
    end

    def integer?
      type == 'integer'
    end

    def float?
      %w[decimal float].include?(type)
    end

    def numeric?
      integer? or float?
    end

    def date?
      type == 'date'
    end
  end

  private

  def attributes
    options.attributes.map{|a| DunlopGeneratorAttribute.new(a) }
  end

  # Taken from base rails and modified for gsub block support
  def gsub_file(path, flag, *args, &block)
    config = args.last.is_a?(Hash) ? args.pop : {}

    path = File.expand_path(path, destination_root)
    if not File.exist? path
      say_status :gsub, set_color("The file #{path} cannot be found", :yellow)
      return
    end
    say_status :gsub, relative_to_original_destination_root(path), config.fetch(:verbose, true)

    unless options[:pretend]
      content = File.binread(path)
      if block.present? # modification from rails standard to support match data in supplied blocks
        content.gsub!(flag, *args){ block.call( Regexp.last_match ) }
      else
        content.gsub!(flag, *args)
      end
      File.open(path, "wb") { |file| file.write(content) }
    end
  end

  ##
  # Add a name to a definition list. eg:
  #   setup_secnarios %i[
  #     existing_scenario
  #   ]
  # at the bottom.
  def add_to_symbol_list(file_path, setup_method, name)
    if behavior == :revoke
      gsub_file file_path, /(#{setup_method} %i\[.*)\n\s+#{name}(.*)\]/m, '\1\2]'
    else
      return if File.read(file_path) =~ /^  #{setup_method} %i\[[^\]]*\W#{name}\W[^\]]*\]/m # only add once
      gsub_file file_path, /(^  #{setup_method} %i\[\n[^\]]*)]/m, "\\1  #{name}\n  ]"
    end
  end
end
