module DataHelpers
  # common methods used by data helpers that need to use pre-converted templates due
  # to the limitations of excel and the spreadsheet gem
  #
  # example manual workflow:
  # 1. download .xls template
  # 2. populate with data
  # 3. save as a tab-delimited .txt
  # 4. upload
  #
  # however, spreadsheet gem can't convert documents, and excel for mac uses
  # incorrect EOL for tab-delimited .txt therefore, skip conversion altogether
  # and make pre-converted templates
  #
  # automated workflow:
  # 1. download .xls template
  # 2. compare with saved .xls template to make sure file hasn't updated recently
  # 3. get saved .txt template
  # 4. populate with data
  # 5. upload
  class TemplateBasedUpload < DataHelpers::Data
    class << self
      attr_reader :records

      # download template, compare it to a stored copy to check if it's been updated, and
      # get the related upload template path
      def get_template(template_url)
        return if @template_path

        downloaded_template = FileSystemHelpers::Downloader.download(template_url).first
        template_dir = File.join(Support::Paths.assets, "templates", snake_case_name)
        stored_download_template = File.join(template_dir, "download_template.xls")
        stored_upload_template = File.join(template_dir, "upload_template.txt")

        verify_download_matches_stored_template(
          downloaded_template, stored_download_template
        )

        fail(
          "upload template does not exist at #{stored_upload_template}"
        ) unless File.exist? stored_upload_template

        @template_path = stored_upload_template
      end

      # populate upload template with @records. only supports
      # tab-separated txt/csv, but this can be fixed without much difficulty
      def populate_template
        template = CSV.read(@template_path, col_sep: "\t")
        @records.each do |record|
          header = template.first
          new_line = []
          header.each do |column|
            new_line << record[column.downcase] # capitalizations break page#populate_page_with
          end
          template << new_line
        end
        upload_file = File.join(Support::Paths.uploads, "upload_file_#{Time.stamp}.txt")
        create_csv_from_ary(upload_file, template)
        upload_file
      end

      # create a record from yml using a symbol or from a hash
      def create_record(arg)
        if arg.is_a? Symbol # use yml
          record = all_data[arg]
          fail "cannot find #{yml_key} in #{yml_name}" if record.nil?
        elsif arg.is_a? Hash # custom data
          record = arg
        else
          fail "must pass a symbol or a hash to .create_record!"
        end
        @records << record
      end

      # class variables persist between scenarios, but data helpers aren't
      # used simultaneously in a single scenario, so instance variables aren't
      # necessary. instead just clear class variables before every scenario
      def clear_records
        @records = []
      end

      private

      def create_csv_from_ary(filename, data_ary)
        CSV.open(filename, "ab", col_sep: "\t") do |csv|
          data_ary.each do |row|
            csv << row
          end
        end
      end

      def verify_download_matches_stored_template(download, stored_template)
        files_match = FileUtils.compare_file(download, stored_template)
        fail(
          "downloaded template (#{download}) and stored template "\
          "(#{stored_template}) do not match! check if the template "\
          "has been updated, and remember to update the upload template as "\
          "well. remember to convert CR line endings to CRLF or LF if you are "\
          "using Excel for Mac!"
        ) unless files_match
      end
    end
  end
end
