# frozen_string_literal: true

require 'yaml'

namespace :sync_tenants do
  desc 'Aggressively overwrites all multiloc translations for which a corresponding instance could be found'
  task :overwrite_multilocs, [:hosts] => [:environment] do |_t, args|
    template_path = Rails.root.join('config/tenant_templates/base.yml')
    template = MultiTenancy::Templates::Utils.parse_yml_file(template_path)

    Tenant.where(host: args[:hosts].split(';')).each do |tenant|
      Apartment::Tenant.switch(tenant.schema_name) do
        template['models'].each do |model_name, fields|
          classname = model_name.classify
          fields.each do |attributes|
            object = object_from_template classname, attributes
            next if object.blank?

            attributes.each do |field_name, field_value|
              next unless (field_name =~ /_multiloc$/) && (field_value.is_a? String)

              value = CL2_SUPPORTED_LOCALES.to_h do |locale|
                translation = I18n.with_locale(locale) { I18n.t!(field_value) }
                [locale, translation]
              end
              object.update_columns(field_name => value)
            end
          end
        end
      end
    end
  end

  desc 'List updates that may have to be synced'
  task :output_updates, [:hosts] => [:environment] do |_t, args|
    # Example row generated by the scripts:
    # Tenant host,         Content type,  ID,                                    Property,        Changed or customized?,  New value,             Old value
    # habay.citizenlab.co, CustomField,   066d1963-902d-431d-b937-f6d095fa34fb,  title_multiloc,  TRUE,                    {"fr-BE"=>"Localité"}, {"fr-BE"=>"Domicile"}

    template_path = Rails.root.join('config/tenant_templates/base.yml')
    template = MultiTenancy::Templates::Utils.parse_yml_file(template_path)
    sheet ||= []

    Tenant.where(host: args[:hosts].split(';')).each do |tenant|
      Apartment::Tenant.switch(tenant.schema_name) do
        template['models'].each do |model_name, fields|
          classname = model_name.classify
          fields.each do |attributes|
            object = object_from_template classname, attributes
            next if object.blank?

            attributes.each do |field_name, field_value|
              value = if (field_name =~ /_multiloc$/) && (field_value.is_a? String)
                CL2_SUPPORTED_LOCALES.to_h do |locale|
                  translation = I18n.with_locale(locale) { I18n.t!(field_value) }
                  [locale, translation]
                end
              elsif field_name.end_with?('_ref', '_timediff') ||
                    (model_name.exclude?('image') && field_name.start_with?('remote_') && field_name.end_with?('_url') && field_name.exclude?('file'))
                nil
              else
                field_value
              end
              next unless value && value_changed(value, object.send(field_name), field_name)

              sheet += [{
                'Tenant host' => tenant.host,
                'Content type' => classname,
                'ID' => object.id,
                'Property' => field_name,
                'Changed or customized?' => object.created_at != object.updated_at,
                'New value' => value.to_s,
                'Old value' => object.send(field_name)
              }]
            end
          end
        end
      end
    end

    CSV.open('tmp/requesting_updates.csv', 'wb') do |csv|
      csv << sheet.first.keys
      sheet.each do |d|
        csv << d.values
      end
    end
  end

  desc 'Apply updates from file'
  task :apply_updates, [:sheet] => [:environment] do |_t, args|
    template_path = Rails.root.join('config/tenant_templates/base.yml')
    template = MultiTenancy::Templates::Utils.parse_yml_file(template_path)
    instructions = CSV.parse(open(args[:sheet]).read, headers: true, col_sep: ',', converters: [])

    Tenant.where(host: instructions.pluck('Tenant host').uniq).each do |tenant|
      Apartment::Tenant.switch(tenant.schema_name) do
        template['models'].each do |model_name, fields|
          classname = model_name.classify
          fields.each do |attributes|
            object = object_from_template classname, attributes
            next if object.blank?

            attributes.each do |field_name, field_value|
              value = if (field_name =~ /_multiloc$/) && (field_value.is_a? String)
                CL2_SUPPORTED_LOCALES.to_h do |locale|
                  translation = I18n.with_locale(locale) { I18n.t!(field_value) }
                  [locale, translation]
                end
              elsif field_name.end_with?('_ref', '_timediff') ||
                    (model_name.exclude?('image') && field_name.start_with?('remote_') && field_name.end_with?('_url') && field_name.exclude?('file'))
                nil
              else
                field_value
              end
              next unless value

              instruction = instructions.find do |d|
                d['ID'] == object.id && d['Property'] == field_name && d['Tenant host'] == tenant.host && d['Content type'] == classname
              end
              next unless instruction

              # In a later iteration, we could first try to parse
              # the new (string) value provided in the sheet.
              object.send :"#{field_name}=", value
              object.save!
            end
          end
        end
      end
    end
  end
end

def object_from_template(classname, attributes)
  case classname
  when 'IdeaStatus'
    IdeaStatus.where(code: attributes['code']).first unless attributes['code'] == 'custom'
  when 'Topic'
    Topic.where(code: attributes['code']).first unless attributes['code'] == 'custom'
  when 'StaticPage'
    if code == 'custom'
      StaticPage.where(slug: attributes['slug']).first
    else
      StaticPage.where(code: attributes['code']).first
    end
  when 'Project', 'Event'
    nil
  when 'CustomField'
    CustomField.registration.where(code: attributes['code']).first
  when 'CustomFieldOption'
    CustomFieldOption.where(key: attributes['key'],
      custom_field: CustomField.registration.where(code: attributes['custom_field_ref']['code'])).first
  end
end

def value_changed(value1, value2, field_name)
  case field_name
  when /_multiloc$/
    value1 = value1.stringify_keys
    value2 = value2.stringify_keys
    (value1.keys & value2.keys & AppConfiguration.instance.settings('core', 'locales')).any? do |key|
      value1[key] != value2[key]
    end
  when 'ordering'
    # don't consider ordering changes
    false
  else
    value1 != value2
  end
end
