# ActsAsAddressable

module ActsAsAddressable
  extend ActiveSupport::Concern

  module ActiveRecord
    def acts_as_addressable(*options)
      @acts_as_addressable_opts = options || []
      include ::ActsAsAddressable
    end
  end

  included do
    has_many :addresses, :as => :addressable, :class_name => 'Effective::Address', :dependent => :delete_all

    # Setup validations and methods
    categories = @acts_as_addressable_opts.try(:flatten) || []

    if categories.first.kind_of?(Hash) # We were passed some validation requirements
      categories = categories.first

      categories.each do |category, validation| # billing, shipping
        category = category.to_s.gsub('_address', '')

        self.send(:define_method, "#{category}_address") { effective_address(category) }
        self.send(:define_method, "#{category}_addresses") { effective_addresses(category) }
        self.send(:define_method, "#{category}_address=") { |atts| set_effective_address(category, atts) }

        validates "#{category}_address", :effective_address_valid => true

        if validation.kind_of?(Hash)
          validates "#{category}_address", :presence => validation.fetch(:presence, false)
          validates "#{category}_address", :effective_address_full_name_presence => validation.fetch(:use_full_name, EffectiveAddresses.use_full_name)
        elsif validation == true
          validates "#{category}_address", :presence => true
          validates "#{category}_address", :effective_address_full_name_presence => EffectiveAddresses.use_full_name
        end
      end
    else # No validation requirements passed
      categories.each do |category|
        category = category.to_s.gsub('_address', '')

        self.send(:define_method, "#{category}_address") { effective_address(category) }
        self.send(:define_method, "#{category}_addresses") { effective_addresses(category) }
        self.send(:define_method, "#{category}_address=") { |atts| set_effective_address(category, atts) }

        validates "#{category}_address", :effective_address_valid => true
        validates "#{category}_address", :effective_address_full_name_presence => EffectiveAddresses.use_full_name
      end
    end
  end

  module ClassMethods
  end

  def effective_addresses(category)
    category = category.to_s
    addresses.select { |address| address.category == category }
  end

  def effective_address(category)
    effective_addresses(category).last
  end

  def set_effective_address(category, atts)
    raise ArgumentError.new("Effective::Address #{category}_address= expecting an Effective::Address or Hash of attributes") unless (atts.kind_of?(Effective::Address) || atts.kind_of?(Hash) || atts == nil)

    atts = HashWithIndifferentAccess.new(atts.kind_of?(Effective::Address) ? atts.attributes : atts)

    add = Effective::Address.new(
      :category     => category,
      :full_name    => atts[:full_name],
      :address1     => atts[:address1],
      :address2     => atts[:address2],
      :city         => atts[:city],
      :state_code   => atts[:state_code],
      :country_code => atts[:country_code],
      :postal_code  => atts[:postal_code]
    )

    self.addresses << add unless (add.empty? || add == effective_address(category))
  end

end