module Dunlop::ExecutionBatchModel
  extend ActiveSupport::Concern

  included do
    include Dunlop::Loggable

    state_machine initial: :new do
      after_transition { |o| o.log_state_transition }

      event(:processing) { transition :new        => :processing }
      event(:completed)  { transition :processing => :completed  }
      event(:aborted)    { transition any         => :aborted    }
      event(:failed)     { transition any         => :failed     }
    end
  end

  def execute_process(options={})
    with_nested_logger_and_catch_failed do
      processing!
      logger.benchmark { process_steps }
      completed!
    end
  end

  def abort!(message = '')
    with_nested_logger_and_catch_failed do
      logger.info(message) if message.present?
      aborted!
    end
  end

  def process_steps
    raise ImplementInSubclass.new(self)
  end

  module ClassMethods
    def batch_pid_id
      :global
    end

    def latest
      where(state: :completed).order(identifier: :desc).order(created_at: :desc).first
    end

    def execute_if_required
      execute! if execution_required?
    end

    def execution_required?
      #updated_ats = [
      #  SourceFile.maximum(:updated_at),
      #  FunctionalConfiguration.maximum(:updated_at),
      #]

      #latest_batch_created_at = latest.try(:created_at) || 1.year.ago

      #!!updated_ats.detect do |updated_at|
      #  updated_at >= latest_batch_created_at
      #end
      true
    end

    def execute!
      return if Dunlop::ExecutionBatchPid.new(batch_pid_id).locked?
      batch = nil
      Dunlop::ExecutionBatchPid.new(batch_pid_id).lock do
        batch = create
        batch.execute_process
      end
      batch
    end

    def execute
      execute!
    end
    deprecate execute: "Please use execute! in stead of execute. This will be removed in dunlop v0.2.0"

    def cleanup!(older_than = 1.month.ago)
      older_than = older_than.ago if older_than.is_a?(ActiveSupport::Duration)
      where(arel_table[:created_at].lt older_than).destroy_all
    end
  end
end
