class Kit < ActiveRecord::Base
  include ActiveRecord::Transitions
  include Ext::Integrations::Kit
  default_scope :order => 'created_at DESC'
  belongs_to :organization
  validates_presence_of :organization

  class_attribute :requires_approval, :ability_proc, :configurable, :restricted_to_admins

  def self.visible
    where(Kit.arel_table[:state].eq("activated").or(Kit.arel_table[:state].eq('pending')))
  end

  def self.acts_as_kit(options = {}, &block)
    self.requires_approval = options.delete(:with_approval) || false
    self.restricted_to_admins = options.delete(:admin_only) || false

    state_machine do
      state :fresh
      state :pending, :enter => :on_pending
      state :activated, :enter => :on_activation
      state :cancelled

      event(:activate, :success => :record_activation)   { transitions :from => [:fresh, :pending], :to => :activated, :guard => :activatable? }
      event(:approve, :success => :record_approval)    { transitions :from => :pending, :to => :activated, :guard => :approvable? }
      event(:cancel)     { transitions :from => [:activated, :pending, :rejected ], :to => :cancelled }
      event(:reactivate) { transitions :from => :cancelled, :to => :activated, :guard => :activatable? }
      event(:activate_without_pending) { transitions :from => [:fresh, :pending, :cancelled], :to => :activated }
    end

    if self.requires_approval
      state_machine do
        event(:submit_for_approval) { transitions :from => :fresh, :to => :pending }
      end
    end

    class_eval(&block)
    self
  end

  def self.activate(options)
    activation_requirements[:unless] << options.delete(:unless) if options.has_key?(:unless)
    activation_requirements[:if] << options.delete(:if) if options.has_key?(:if)
  end

  def self.approve(options)
    approval_requirements[:unless] << options.delete(:unless) if options.has_key?(:unless)
    approval_requirements[:if] << options.delete(:if) if options.has_key?(:if)
  end

  def self.activation_requirements
    @requirements ||= Hash.new { |h,k|  h[k] = [] }
  end

  def self.approval_requirements
    @approval_requirements ||= Hash.new { |h,k|  h[k] = [] }
  end

  def self.when_active(&block)
    self.ability_proc = Proc.new(&block)
  end

  def self.subklasses
    @subklasses ||= [ TicketingKit, RegularDonationKit, SponsoredDonationKit, ResellerKit, MailchimpKit, MembershipKit, PassesKit, ScannableTicketsKit ].freeze
  end

  def self.pad_with_new_kits(kits = [])
    types = kits.collect(&:type)
    alternatives = kits.collect(&:alternatives).flatten.uniq

    padding = subklasses.reject{ |klass| klass.to_s == "SponsoredDonationKit" }.reject{ |klass| (types.include? klass.to_s) or (alternatives.include? klass) }.collect(&:new)
    kits + padding
  end

  def self.mailchimp
    find_by_type("MailchimpKit")
  end

  def abilities
    activated? ? self.class.ability_proc : Proc.new {}
  end

  def has_alternatives?
    alternatives.any?
  end

  def alternatives
    []
  end

  def requirements_met?
    check_requirements
  end

  def activatable?
    return false if organization.nil?

    if needs_approval?
      check_requirements
      submit_for_approval!
      return false
    end

    check_requirements
  end

  def approvable?
    check_approval
  end

  class DuplicateError < StandardError
  end

  protected
    def on_activation; end
    def on_pending; end

  private
    def check_requirements
      check_unlesses(self.class.activation_requirements[:unless]) and check_ifs(self.class.activation_requirements[:if])
    end

    def check_approval
      check_unlesses(self.class.approval_requirements[:unless]) and check_ifs(self.class.approval_requirements[:if])
    end

    def check_unlesses(unlesses)
      return true if unlesses.empty?
      unlesses.all? { |req| !self.send(req) }
    end

    def check_ifs(ifs)
      return true if ifs.empty?
      ifs.all? { |req| self.send(req) }
    end

    def needs_approval?
      self.class.requires_approval and fresh?
    end
end