# This migration comes from spree (originally 20150819154308)
class AddDiscontinuedToProductsAndVariants < ActiveRecord::Migration[4.2]
  def up
    add_column :spree_products, :discontinue_on, :datetime, after: :available_on
    add_column :spree_variants, :discontinue_on, :datetime, after: :deleted_at

    add_index :spree_products, :discontinue_on
    add_index :spree_variants, :discontinue_on

    puts "Warning: This migration changes the meaning of 'deleted'. Before this change, 'deleted' meant products that were no longer being sold in your store. After this change, you can only delete a product or variant if it has not already been sold to a customer (a model-level check enforces this). Instead, you should use the new field 'discontinue_on' for products or variants which were sold in the past but no longer for sale. This fixes bugs when other objects are attached to deleted products and variants. (Even though acts_as_paranoid gem keeps the records in the database, most associations are automatically scoped to exclude the deleted records.) In thew meaning of 'deleted,' you can still use the delete function on products & variants which are *truly user-error mistakes*, specifically before an order has been placed or the items have gone on sale. You also must use the soft-delete function (which still works after this change) to clean up slug (product) and SKU (variant) duplicates. Otherwise, you should generally over ever need to discontinue products.

Data Fix: We will attempt to reverse engineer the old meaning of 'deleted' (no longer for sale) to the new database field 'discontinue_on'. However, since Slugs and SKUs cannot be duplicated on Products and Variants, we cannot gaurantee this to be foolproof if you have deteled Products and Variants that have duplicate Slugs or SKUs in non-deleted records. In these cases, we recommend you use the additional rake task to clean up your old records (see rake db:fix_orphan_line_items). If you have such records, this migration will leave them in place, preferring the non-deleted records over the deleted ones. However, since old line items will still be associated with deleted objects, you will still the bugs in your app until you run:

rake db:fix_orphan_line_items

We will print out a report of the data we are fixing now: "

    Spree::Product.only_deleted.each do |product|
      # determine if there is a slug duplicate
      the_dup = Spree::Product.find_by(slug: product.slug)
      if the_dup.nil?
        # check to see if there are line items attached to any variants
        if Spree::Variant.with_deleted.where(product_id: product.id).map(&:line_items).any?
          puts "recovering deleted product id #{product.id} ... this will un-delete the record and set it to be discontinued"

          old_deleted = product.deleted_at
          product.update_column(:deleted_at, nil) # for some reason .recover doesn't appear to be a method
          product.update_column(:discontinue_on, old_deleted)
        else
          puts "leaving product id #{product.id} deleted because there are no line items attached to it..."
        end
      else
        puts "leaving product id #{product.id} deleted because there is a duplicate slug for '#{product.slug}' (product id #{the_dup.id}) "
        if product.variants.map(&:line_items).any?
          puts "WARNING: You may still have bugs with product id #{product.id} (#{product.name}) until you run rake db:fix_orphan_line_items"
        end
      end
    end

    Spree::Variant.only_deleted.each do |variant|
      # determine if there is a slug duplicate
      the_dup = Spree::Variant.find_by(sku: variant.sku)
      if the_dup.nil?
        # check to see if there are line items attached to any variants
        if variant.line_items.any?
          puts "recovering deleted variant id #{variant.id} ... this will un-delete the record and set it to be discontinued"
          old_deleted = variant.deleted_at
          variant.update_column(:deleted_at, nil) # for some reason .recover doesn't appear to be a method
          variant.update_column(:discontinue_on, old_deleted)
        else
          puts "leaving variant id #{variant.id} deleted because there are no line items attached to it..."
        end
      else
        puts "leaving variant id #{variant.id} deleted because there is a duplicate SKU for '#{variant.sku}' (variant id #{the_dup.id}) "
        if variant.line_items.any?
          puts "WARNING: You may still have bugs with variant id #{variant.id} (#{variant.name}) until you run rake db:fix_orphan_line_items"
        end
      end
    end
  end

  def down
    execute "UPDATE spree_products SET deleted_at = discontinue_on WHERE deleted_at IS NULL"
    execute "UPDATE spree_variants SET deleted_at = discontinue_on WHERE deleted_at IS NULL"

    remove_column :spree_products, :discontinue_on
    remove_column :spree_variants, :discontinue_on
  end
end
