class EasyEntityAction < ActiveRecord::Base
  include Redmine::SafeAttributes
  include Rails.application.routes.url_helpers

  belongs_to :project
  belongs_to :author, :class_name => 'User'
  belongs_to :execute_as_user, :class_name => 'User', :foreign_key => 'execute_as_user_id'

  has_many :histories, :class_name => 'EasyEntityActionHistory', :dependent => :destroy

  scope :active, lambda { where(:active => true) }
  scope :run_at, lambda { |time| where(["#{EasyEntityAction.table_name}.nextrun_at IS NULL OR #{EasyEntityAction.table_name}.nextrun_at <= ?", time]) }
  scope :run_now, lambda { run_at(Time.now) }

  set_associated_query_class EasyEntityActionQuery

  serialize :easy_query_settings, Hash
  serialize :period_options, Hash

  attr_protected :id

  store :settings, accessors: [:target_project_id], coder: JSON

  safe_attributes 'name', 'action_name', 'active', 'author_id', 'project_id', 'entity_type',
                  'entity_id', 'easy_query_settings', 'execute_as', 'execute_as_user_id',
                  'mail', 'mail_sender', 'mail_cc', 'mail_bcc', 'mail_subject', 'mail_html_body',
                  'repeatedly', 'period_options', 'use_journal', 'target_project_id'
  safe_attributes 'type', :if => lambda { |easy_entity_action, user| easy_entity_action.new_record? }

  class_attribute :registered_actions
  self.registered_actions = {}

  def self.map(&block)
    yield self
  end

  def self.disabled_sti_class
    EasyDisabledEntityAction
  end

  def self.add(klass_name, *action_names)
    registered_actions[klass_name] ||= Set.new
    registered_actions[klass_name].merge(action_names)
  end

  def self.default_url_options
    Mailer.default_url_options
  end

  def self.caption(klass_name = self.name)
    l(:caption, :scope => [:easy_entity_action, klass_name.underscore])
  end

  def action_caption(action_name)
    l(action_name, :scope => [:easy_entity_action, self.class.name.underscore, :actions])
  end

  def self.format_html_entity_name
    'easy_entity_action'
  end

  def self.css_icon
    'icon icon-workflow'
  end

  def action_names
    registered_actions[self.class.name]
  end

  def create_easy_query
    create_easy_query_from_associated_entity
  end

  def editable?(user = nil)
    user ||= User.current
    true
  end

  def visible?(user = nil)
    user ||= User.current
    true
  end

  def executable_user
    @executable_user ||= case self.execute_as
    when 'author'
      self.author
    when 'user'
      self.execute_as_user
    end

    @executable_user || User.current
  end

  def execute_all
    ret_val = false

    self.executable_user.execute do
      query = create_easy_query_from_associated_entity

      if query
        entities = query.entities
        entities.each do |entity|

          ret_val = self.execute(entity)

        end
      end
    end

    ret_val
  end

  def execute(entity)
    return false if !entity

    if self.use_journal?
      entity.clear_current_journal if entity.respond_to?(:clear_current_journal)
      t = '<p>'
      t << l(:text_easy_entity_action_journal, :link => "<a href='#{easy_entity_action_url(self)}'>#{self.name}</a>")
      t << '<p>'
      journal = entity.init_journal(self.executable_user, t) if entity.respond_to?(:init_journal)
    end

    ret_status = do_action_on(entity) || false

    self.histories.create(:entity => entity) if ret_status

    begin
      entity.save(:validate => false)
    rescue ActiveRecord::StaleObjectError
      # do it next time
    end

    ret_status
  end

  def do_action_on(entity)
    # to override for custom action
  end

  protected

  def create_easy_query_from_associated_entity
    query_class = associated_entity_class.try(:associated_query_class)
    return nil if !query_class

    query = create_easy_query_from_klass(query_class)
    query
  end

  def create_easy_query_from_klass(klass)
    query = klass.new
    query.project = project
    query.from_params(easy_query_settings)

    if !self.repeatedly?
      query.add_additional_statement("NOT EXISTS(SELECT #{EasyEntityActionHistory.table_name}.id FROM #{EasyEntityActionHistory.table_name} WHERE #{EasyEntityActionHistory.table_name}.easy_entity_action_id = #{self.id} AND #{EasyEntityActionHistory.table_name}.entity_type = '#{self.associated_entity_class.name}' AND #{EasyEntityActionHistory.table_name}.entity_id = #{self.associated_entity_class.table_name}.id)")
    end

    query
  end

end
