namespace :units do
  task clean_unece20_source: :environment do
    base_unit_entries = []

    un_ece_20_units = YAML.safe_load(ERB.new(File.read(File.expand_path('config/units-of-measure/un-ece-20.yml',
                                                                        Rails.root))).result)
    re = /^(?:([, 0-9]*)(?: x )!?)?([, 0-9⁰-⁹⁻¹²³]*)?(.*)?$/
    un_ece_20_units.each do |unit|
      fixed_conversion_factor = fix_conversion_factor(unit['ConversionFactor'])
      md = fixed_conversion_factor.match(re)
      multiplier = md[1]
      potency = md[2]
      base_unit = md[3]

      multiplier&.strip!
      potency&.strip!
      base_unit&.strip!

      if multiplier.blank? && (!potency.nil? && !/[⁰-⁹⁻¹²³]+/.match(potency))
        multiplier = potency
        potency = ''
      end

      multiplier&.gsub!(',', '.')
      multiplier&.gsub!(' ', '')
      multiplier = multiplier.blank? ? 1 : BigDecimal(multiplier)

      unit['conversion'] = {}
      unit['conversion']['unit'] = base_unit

      unit['Symbol'] = '' if unit['Symbol'] == unit['CommonCode']

      power_of_ten = potency.match(/^10 *?([⁰-⁹⁻¹²³]+)$/)&.[](1)
      power_of_ten = superscript_to_number(power_of_ten) unless power_of_ten.nil?

      base_unit_multiplier = multiplier
      base_unit_multiplier *= (10**power_of_ten) unless power_of_ten.nil?
      unit['conversion']['factor'] = base_unit_multiplier.to_s.to_f
      is_base_unit = base_unit.present? && potency.blank? && multiplier == 1

      base_unit_entries << unit if is_base_unit
    end

    # rubocop:disable Style/CombinableLoops
    un_ece_20_units.each do |unit|
      next if unit['conversion']['unit'].blank?

      base_units = base_unit_entries.select { |entry| entry['conversion']['unit'] == unit['conversion']['unit'] }
      unit['conversion']['base_units'] = base_units.pluck('CommonCode')
    end

    un_ece_20_units.each do |unit|
      unit['conversion'].delete('unit')
    end
    # rubocop:enable Style/CombinableLoops

    result = "# This file has been autogenerated by `rake units:clean_unece20_source`\n#{un_ece_20_units.to_yaml}"
    File.write(File.expand_path('config/units-of-measure/un-ece-20-remastered.yml', Rails.root), result)
  end

  task build_i18n_from_csv: :environment do
    languages = %i[en de nl]
    translations = languages.index_with { {} }
    csv_options = { csv_options: { col_sep: ',' } }
    SpreadsheetFile.parse 'config/units-of-measure/translations_piece.csv', csv_options do |row, index|
      next if index == 0

      code = row[0]
      next if code.nil? # empty csv row

      languages.each_with_index do |locale, lang_index|
        i = 2 + (lang_index * 3)
        current_translation = { name: row[i].strip }
        current_translation[:abbreviation] = row[i + 1].strip if row[i + 1].present?
        current_translation[:aliases] = row[i + 2].split(', ') if row[i + 2].present?
        translations[locale][code] = current_translation
      end
    end

    languages.each do |locale|
      SpreadsheetFile.parse "config/units-of-measure/translations_scalar-#{locale}.csv", csv_options do |row, index|
        next if index == 0

        code = row[0]
        next if code.nil? # empty csv row

        translation = { name: row[2].strip, long_name: row[1].strip }
        translation[:symbols] = []
        translation[:symbols] << row[3].strip if row[3].present?
        alternate_symbols = row[4]&.strip
        if alternate_symbols.present?
          alternate_symbols.split(', ').each do |symbol|
            translation[:symbols] << symbol.strip
          end
        end
        translation[:aliases] = row[5].split(', ') if row[5].present?
        translations[locale][code] = translation
      end
      result = "# This file has been autogenerated by `rake units:build_i18n_from_csv`\n#{{ unece_units: translations[locale] }.deep_stringify_keys.to_yaml}"
      File.write(File.expand_path("config/units-of-measure/locales/unece_#{locale}.yml", Rails.root), result)
    end
  end
end

def superscript_hash
  {
    '⁻' => '-', '⁰' => '0', '¹' => '1', '²' => '2', '³' => '3', '⁴' => '4', '⁵' => '5', '⁶' => '6', '⁷' => '7', '⁸' => '8', '⁹' => '9'
  }
end

# I know this is stupid, but I couldn't find a default ruby/rails method for this and wouldn't be
# bothered to write a nicer unicode mapper for these few characters:
def superscript_to_number(str)
  str = str.chars.map { |c| superscript_hash[c] }.join

  BigDecimal(str) unless str == ''
end

def number_to_superscript(str)
  conversion_hash = superscript_hash.invert
  str.chars.map { |c| conversion_hash[c] }.join
end

def fix_conversion_factor(conversion_factor)
  # m2 -> m²:
  conversion_factor = conversion_factor.gsub(%r{(\s|^|/)m2(\s|$|/)}, '\1m²\2')

  # m3 -> m³
  conversion_factor = conversion_factor.gsub(%r{(\s|^|/)m3(\s|$|/)}, '\1m³\2')

  # 10-15 m³ -> 10⁻¹⁵ m³:
  conversion_factor.gsub(%r{(\s|^|/)10 ?(- ?[0-9]+)(\s|$|/)}) do
    Regexp.last_match[1] + '10' + number_to_superscript(Regexp.last_match[2]) + Regexp.last_match[3]
  end
end
