# Add tracking of last changed attributes. Models including this module will be able to track attribute changes like:
#   record.last_changed[:backup_created] #=> timestamp or nil
#   record.last_changed.backup_created #=> timestamp or nil
module Dunlop::AttributeChangesTracking
  extend ActiveSupport::Concern

  included do
    attr_accessor :attribute_change_time # add ability to synchronize changed_at time for collections
    has_many :last_attribute_changes, as: :target, class_name: 'Dunlop::LastAttributeChange'
    after_update :update_last_attribute_changed_at
  end

  def update_last_attribute_changed_at
    changed_at = attribute_change_time || Time.now
    (saved_changes.keys - self.class.ignore_attributes_for_last_change).each do |attr|
      if existing = last_attribute_changes.find{|changed| changed.attribute_name == attr }
        existing.update(changed_at: changed_at)
      else
        last_attribute_changes.create(changed_at: changed_at, attribute_name: attr)
      end
    end
  end

  def last_changed
    @last_changed ||= LastChanged.new(self)
  end

  module ClassMethods
    def with_last_attribute_changes
      includes(:last_attribute_changes)
    end

    def ignore_attributes_for_last_change
      %w[id sti_type created_at updated_at notes]
    end
  end

  class LastChanged
    attr_reader :target
    def initialize(target)
      @target = target
    end

    def method_missing(m, *args)
      raise "#{target.class.name} has no attribute #{m}" unless target.has_attribute?(m)
      self[m]
    end

    def [](val)
      target.last_attribute_changes.find{|changed| changed.attribute_name == val.to_s }.try(:changed_at)
    end
  end
end
# owner_initialization.last_changed[attr]
