require "dunlop/generators"
require "dunlop/generators/generator_helpers"
require "csv_builder"


class Dunlop::SourceFileGenerator < Rails::Generators::NamedBase
  include Dunlop::Generators::GeneratorHelpers
  source_root File.expand_path('../templates', __FILE__)
  class_option :sql, type: :boolean
  class_option :source_record, type: :boolean
  class_option :attributes, type: :array, default: []

  def create_source_file
    add_to_symbol_list "app/models/source_file.rb", 'setup_source_files', file_name

    template "model.rb.erb", "app/models/source_file/#{file_name}.rb"
    template "model_spec.rb.erb", "spec/models/source_file/#{file_name}_spec.rb"
    if options.sql
      create_file "app/models/source_file/sql_templates/load_#{file_name}.sql.erb" do
        columns = '@dummy'
        custom_set_rulings = []
        if attributes.present?
          columns_ary = []
          attributes.each do |attr|
            if attr.column_name == 'zipcode' # strip whitespace
              columns_ary.push "@#{attr.column_name}"
              custom_set_rulings.push "#{attr.column_name}=REPLACE(@#{attr.column_name}, ' ', '')"
            elsif attr.boolean?
              columns_ary.push "@#{attr.column_name}"
              custom_set_rulings.push "#{attr.column_name}=IF(@#{attr.column_name}='true' OR @#{attr.column_name}='1', 1, 0)"
            elsif attr.date?
              columns_ary.push "@#{attr.column_name}"
              # NULLIF(STR_TO_DATE(@due_date, '%d-%m-%Y'), '0000-00-00')
              custom_set_rulings.push "#{attr.column_name}=NULLIF(@#{attr.column_name}, '')"
            else
              # no custom sql conversion
              columns_ary.push attr.column_name
            end
          end
          columns = columns_ary.in_groups_of(6).map{|g| g.compact.join(', ')}.join(",\n              ")
        end
        output = <<-SQL.strip_heredoc
          LOAD DATA LOCAL INFILE '<%= working_file.path %>' IGNORE
            INTO TABLE source_record_#{file_name.pluralize}
            FIELDS TERMINATED BY '#{CsvBuilder.default_csv_options[:col_sep] || ','}' OPTIONALLY ENCLOSED BY '"'
            IGNORE 1 LINES (
              #{columns}
            )
        SQL
        if custom_set_rulings.any?
          output += <<-SQL.strip_heredoc
            SET
              #{custom_set_rulings.join(",\n    ")}
          SQL
        end
        output
      end
      create_file "app/models/source_file/sql_templates/post_process_#{file_name}.sql.erb"
    end
    create_file "spec/fixtures/source_files/#{file_name}_1.csv" do
      headers = ''
      if attributes.present?
        headers = attributes.map(&:name).join(CsvBuilder.default_csv_options[:col_sep] || ',')
      end
      _csv = <<-CSV.strip_heredoc.strip
        #{headers}
      CSV
    end
  end

  def add_factory
    if behavior == :revoke
      gsub_file "spec/factories/source_files.rb", /^s+factory 'source_file/#{file_name}'.*$/, ''
    else
      gsub_file "spec/factories/source_files.rb", /end\s*\z/m do |match_data|
        "  factory 'source_file/#{file_name}', class: 'SourceFile::#{class_name}', parent: :source_file\nend"
      end
    end
  end

  def add_translations
    gsub_file "config/locales/source_files.yml", /^      plural:\s*$/, "      source_file/#{file_name}: #{file_name.humanize}\n      plural:"
    gsub_file "config/locales/source_files.yml", /^    attributes:\s*$/, "        source_file/#{file_name}: #{file_name.humanize.pluralize}\n    attributes:"
    return unless options.source_record
    # Preserve column mapping by I18N
    append_to_file "config/locales/source_files.yml", <<-YML
      source_record/#{file_name}:
        #{attributes.map{|a| "#{a.column_name}: #{a.name}"}.join("\n        ")}
    YML
  end

  def generate_source_record_additions
    return unless options.source_record
    return unless has_workflow?
    inject_into_file "app/models/workflow_instance/data_setup.rb", after: "module ClassMethods\n" do <<-RUBY
    # create_or_update callback from app/models/source_file/#{file_name}
    def create_or_update_from_#{file_name}
    end

    RUBY
    end
  end

  def has_workflow?
    Dunlop.has_workflow?
  end

  def output_helper_messages
    if options.source_record
      if attributes.present?
        attrs = attributes.map{|a| [a.column_name, a.type].join(':')}.join(' ')
      else
        attrs = ''
      end
      if behavior == :invoke
        puts "Source record itself is not created. Hint for creation is:"
        puts "rails generate model SourceRecord::#{class_name} #{attrs}"
      end
    end
  end
end
