<commit_before># rubocop:disable Metrics/ClassLength
module ShopifyImport
  module Creators
    class OrderCreator < BaseCreator
      delegate :user, :attributes, :timestamps, to: :parser

      # rubocop:disable Metrics/MethodLength
      def save!
        Spree::Order.transaction do
          @spree_order = create_spree_order
          assign_spree_order_to_data_feed
          create_spree_line_items
          create_spree_payments
          create_spree_shipments
          create_spree_taxes
          create_spree_promotions
          create_spree_addresses
          # TODO: refunds
        end
        @spree_order.update_columns(timestamps)
      end
      # rubocop:enable Metrics/MethodLength

      private

      # TODO: create user if missing
      def create_spree_order
        order = Spree::Order.new(user: user)
        order.assign_attributes(attributes)
        order.save!
        order
      end

      def create_spree_line_items
        shopify_order.line_items.each do |shopify_line_item|
          ShopifyImport::Creators::LineItemCreator.new(shopify_line_item, shopify_order, @spree_order).save
        end
      end

      def create_spree_payments
        transactions = shopify_order.transactions.reject { |t| t.kind.eql?('refund') }

        # TODO: to verify
        if children_transactions?(transactions)
          ids = transactions.map(&:id)

          transactions.each do |t|
            check_transaction_is_not_duplicate?(ids, t) && create_spree_payment(t)
          end
        else
          transactions.each { |t| create_spree_payment(t) }
        end
      end

      def check_transaction_is_not_duplicate?(ids, t)
        (!t.kind.eql?('authorization') && ids.include?(t.parent_id))
      end

      def children_transactions?(transactions)
        check_transactions_kinds?(transactions) && check_transactions_parents?(transactions)
      end

      def check_transactions_kinds?(transactions)
        kinds = transactions.map(&:kind)

        kinds.include?('authorization') && kinds.include?('capture')
      end

      def check_transactions_parents?(transactions)
        ids = transactions.map(&:id)
        parent_ids = transactions.map(&:parent_id)

        (parent_ids - ids).compact.empty?
      end

      def create_spree_payment(transaction)
        ShopifyImport::Importers::PaymentImporter.new(transaction, @shopify_data_feed, @spree_order).import!
      end

      def create_spree_shipments
        shopify_order.fulfillments.each do |fulfillment|
          ShopifyImport::Importers::ShipmentImporter.new(fulfillment, @shopify_data_feed, @spree_order).import!
        end
      end

      def create_spree_taxes
        shopify_order.tax_lines.each do |shopify_tax_line|
          spree_tax_rate = ShopifyImport::Creators::TaxRateCreator.new(shopify_tax_line, billing_address).create!
          ShopifyImport::Creators::Adjustments::TaxCreator.new(shopify_tax_line, @spree_order, spree_tax_rate).save!
        end
      end

      def create_spree_promotions
        shopify_order.discount_codes.each do |shopify_discount_code|
          promotion = PromotionCreator.new(@spree_order, shopify_discount_code).create!
          Adjustments::PromotionCreator.new(@spree_order, promotion, shopify_discount_code).save!
        end
      end

      def create_spree_addresses
        create_bill_addreess
        create_ship_address
      end

      def create_bill_addreess
        return if billing_address.blank?

        # HACK: shopify order address does not have id, so i'm not saving data feed.
        address_data_feed = Shopify::DataFeed.new(data_feed: billing_address.to_json)
        @spree_order.bill_address = AddressCreator.new(address_data_feed, user, true).create!
        @spree_order.save!(validate: false)
      end

      def create_ship_address
        return if ship_address.blank?

        # HACK: shopify order address does not have id, so i'm not saving data feed.
        address_data_feed = Shopify::DataFeed.new(data_feed: ship_address.to_json)
        @spree_order.ship_address = AddressCreator.new(address_data_feed, user, true).create!
        @spree_order.save!(validate: false)
      end

      def billing_address
        @billing_address ||= shopify_order.billing_address
      end

      def ship_address
        @shipping_address ||= shopify_order.shipping_address
      end<commit_msg>Refactor order creator to use new address creator<commit_after># rubocop:disable Metrics/ClassLength
module ShopifyImport
  module Creators
    class OrderCreator < BaseCreator
      delegate :user, :attributes, :timestamps, to: :parser

      # rubocop:disable Metrics/MethodLength
      def save!
        Spree::Order.transaction do
          @spree_order = create_spree_order
          assign_spree_order_to_data_feed
          create_spree_line_items
          create_spree_payments
          create_spree_shipments
          create_spree_taxes
          create_spree_promotions
          create_spree_addresses
          # TODO: refunds
        end
        @spree_order.update_columns(timestamps)
      end
      # rubocop:enable Metrics/MethodLength

      private

      # TODO: create user if missing
      def create_spree_order
        order = Spree::Order.new(user: user)
        order.assign_attributes(attributes)
        order.save!
        order
      end

      def create_spree_line_items
        shopify_order.line_items.each do |shopify_line_item|
          ShopifyImport::Creators::LineItemCreator.new(shopify_line_item, shopify_order, @spree_order).save
        end
      end

      def create_spree_payments
        transactions = shopify_order.transactions.reject { |t| t.kind.eql?('refund') }

        # TODO: to verify
        if children_transactions?(transactions)
          ids = transactions.map(&:id)

          transactions.each do |t|
            check_transaction_is_not_duplicate?(ids, t) && create_spree_payment(t)
          end
        else
          transactions.each { |t| create_spree_payment(t) }
        end
      end

      def check_transaction_is_not_duplicate?(ids, t)
        (!t.kind.eql?('authorization') && ids.include?(t.parent_id))
      end

      def children_transactions?(transactions)
        check_transactions_kinds?(transactions) && check_transactions_parents?(transactions)
      end

      def check_transactions_kinds?(transactions)
        kinds = transactions.map(&:kind)

        kinds.include?('authorization') && kinds.include?('capture')
      end

      def check_transactions_parents?(transactions)
        ids = transactions.map(&:id)
        parent_ids = transactions.map(&:parent_id)

        (parent_ids - ids).compact.empty?
      end

      def create_spree_payment(transaction)
        ShopifyImport::Importers::PaymentImporter.new(transaction, @shopify_data_feed, @spree_order).import!
      end

      def create_spree_shipments
        shopify_order.fulfillments.each do |fulfillment|
          ShopifyImport::Importers::ShipmentImporter.new(fulfillment, @shopify_data_feed, @spree_order).import!
        end
      end

      def create_spree_taxes
        shopify_order.tax_lines.each do |shopify_tax_line|
          spree_tax_rate = ShopifyImport::Creators::TaxRateCreator.new(shopify_tax_line, billing_address).create!
          ShopifyImport::Creators::Adjustments::TaxCreator.new(shopify_tax_line, @spree_order, spree_tax_rate).save!
        end
      end

      def create_spree_promotions
        shopify_order.discount_codes.each do |shopify_discount_code|
          promotion = PromotionCreator.new(@spree_order, shopify_discount_code).create!
          Adjustments::PromotionCreator.new(@spree_order, promotion, shopify_discount_code).save!
        end
      end

      def create_spree_addresses
        create_bill_addreess
        create_ship_address
      end

      def create_bill_addreess
        return if billing_address.blank?

        # HACK: shopify order address does not have id, so i'm not saving data feed.
        address_data_feed = Shopify::DataFeed.new(data_feed: billing_address.to_json)
        @spree_order.bill_address = address_creator.new(address_data_feed, user, true).create!
        @spree_order.save!(validate: false)
      end

      def create_ship_address
        return if ship_address.blank?

        # HACK: shopify order address does not have id, so i'm not saving data feed.
        address_data_feed = Shopify::DataFeed.new(data_feed: ship_address.to_json)
        @spree_order.ship_address = address_creator.new(address_data_feed, user, true).create!
        @spree_order.save!(validate: false)
      end

      def address_creator
        ShopifyImport::DataSavers::Addresses::AddressCreator
      end

      def billing_address
        @billing_address ||= shopify_order.billing_address
      end

      def ship_address
        @shipping_address ||= shopify_order.shipping_address
      end
{'fraction_non_alphanumeric': 0.07609427609427609, 'fraction_numerical': 0.0, 'mean_word_length': 2.882788671023965, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '8855', 'n_tokens_mistral': 2716, 'n_tokens_neox': 2672, 'n_words': 472}