# frozen_string_literal: true
# (C) 2019-2020 GoodData Corporation
require_relative 'base_action'

# Migrate date dimension urn:gooddata:date or urn:custom:date to urn:custom_v2:date
module GoodData
  module LCM2
    class MigrateGdcDateDimension < BaseAction
      DESCRIPTION = 'Migrate Gdc Date Dimension'
      DATE_DIMENSION_CUSTOM_V2 = 'urn:custom_v2:date'
      DATE_DIMENSION_OLD = %w[urn:gooddata:date urn:custom:date]

      PARAMS = define_params(self) do
        description 'Client Used for Connecting to GD'
        param :gdc_gd_client, instance_of(Type::GdClientType), required: true

        description 'Specifies how to synchronize LDM and resolve possible conflicts'
        param :synchronize_ldm, instance_of(Type::SynchronizeLDM), required: false, default: 'diff_against_master_with_fallback'

        description 'Synchronization Info'
        param :synchronize, array_of(instance_of(Type::SynchronizationInfoType)), required: true, generated: true
      end

      RESULT_HEADER = %i[from to status]

      class << self
        def call(params)
          results = []
          params.synchronize.map do |segment_info|
            result = migrate_date_dimension(params, segment_info)
            results.concat(result)
          end

          {
            results: results
          }
        end

        def migrate_date_dimension(params, segment_info)
          results = []
          client = params.gdc_gd_client
          latest_blueprint = segment_info[:from_blueprint]
          # don't migrate when latest master doesn't contain custom v2 date.
          return results unless contain_v2?(latest_blueprint)

          previous_blueprint = segment_info[:previous_master]&.blueprint
          # check latest master and previous master
          master_upgrade_datasets = get_upgrade_dates(latest_blueprint, previous_blueprint) if params[:synchronize_ldm].downcase == 'diff_against_master' && previous_blueprint
          unless master_upgrade_datasets&.empty?
            segment_info[:to].pmap do |entry|
              pid = entry[:pid]
              to_project = client.projects(pid) || fail("Invalid 'to' project specified - '#{pid}'")
              GoodData.logger.info "Migrating date dimension, project: '#{to_project.title}', PID: #{pid}"
              to_blueprint = to_project.blueprint
              upgrade_datasets = get_upgrade_dates(latest_blueprint, to_blueprint)
              next if upgrade_datasets.empty?

              message = get_upgrade_message(upgrade_datasets)

              results << {
                from: segment_info[:from],
                to: pid,
                status: to_project.upgrade_custom_v2(message)
              }
            end
          end

          results
        end

        def get_upgrade_dates(src_blueprint, dest_blueprint)
          dest_dates = get_date_dimensions(dest_blueprint) if dest_blueprint
          src_dates = get_date_dimensions(src_blueprint) if src_blueprint

          upgrade_datasets = []
          return upgrade_datasets if dest_dates.empty? || src_dates.empty?

          dest_dates.each do |dest|
            src_dim = get_date_dimension(src_blueprint, dest[:id])
            next unless src_dim

            upgrade_datasets << src_dim[:identifier] if upgrade?(src_dim, dest) && src_dim[:identifier]
          end

          upgrade_datasets
        end

        def get_upgrade_message(upgrade_datasets)
          {
            upgrade: {
              dateDatasets: {
                upgrade: "exact",
                datasets: upgrade_datasets
              }
            }
          }
        end

        def upgrade?(src_dim, dest_dim)
          src_dim[:urn] == DATE_DIMENSION_CUSTOM_V2 && DATE_DIMENSION_OLD.any? { |e| dest_dim[:urn] == e }
        end

        def contain_v2?(blueprint)
          get_date_dimensions(blueprint).any? { |e| e[:urn] == DATE_DIMENSION_CUSTOM_V2 }
        end

        def get_date_dimension(blueprint, id)
          GoodData::Model::ProjectBlueprint.find_date_dimension(blueprint, id)
        end

        def get_date_dimensions(blueprint)
          GoodData::Model::ProjectBlueprint.date_dimensions(blueprint)
        end
      end
    end
  end
end