class Order
  include SimplyStored::Couch
  include ActiveModel::SerializerSupport

  property :state, default: 'placed' # placed, active, delivered, cancelled, closed

  belongs_to :list
  belongs_to :user
  belongs_to :supplier
  belongs_to :section
  belongs_to :table
  belongs_to :employee

  has_many :product_orders, dependent: :destroy
  #has_many :products, through: :product_orders
  validates :supplier_id, presence: true

  view :active_for_supplier_view, type: :custom, map_function: %[function(doc){
    if(doc.ruby_class == 'Order' && (doc.state == 'placed' || doc.state == 'active')){
      emit([doc.supplier_id, doc.list_id], 1);
    }
  }], reduce_function: '_sum'

  view :active_for_supplier_and_section_view, type: :custom, map_function: %[function(doc){
    if(doc.ruby_class == 'Order' && (doc.state == 'placed' || doc.state == 'active')){
      emit([doc.supplier_id, doc.section_id], 1);
    }
  }], reduce_function: '_sum'

  view :by_supplier_id_and_id, key: [:supplier_id, :_id] # Do not comment me out this is for security, TODO: make the security server side for speed and space optimization
  view :by_supplier_id_and_state, key: [:supplier_id, :state], reduce_function: '_sum'
  view :by_list_id, key: :list_id

  def self.for_supplier(supplier, options = {})
    total_entries = database.view(by_supplier_id_and_id({startkey: ["#{supplier.id}\u9999"], endkey: [supplier.id], include_docs: false, reduce: true, descending: true}))
    options[:total_entries] = total_entries
    with_pagination_options(options) do |options|
      database.view(by_supplier_id_and_id({startkey: ["#{supplier.id}\u9999"], endkey: [supplier.id], include_docs: true, reduce: false, descending: true}.merge(options)))
    end
  end

  # Return all currently active orders for a given supplier
  def self.active_for_supplier(supplier_id)
    database.view(active_for_supplier_view(startkey: [supplier_id], endkey: [supplier_id, {}], reduce: false, include_docs: true))
  end

  # Return all currently active orders for a given supplier and list
  def self.active_for_supplier_and_list(supplier_id, list_id)
    supplier_id = supplier_id.id if supplier_id.is_a?(SimplyStored::Couch)
    list_id = list_id.id if list_id.is_a?(SimplyStored::Couch)
    database.view(active_for_supplier_view(key: [supplier_id, list_id], reduce: false, include_docs: true))
  end

  def self.count_active_for_supplier_and_list(supplier_id, list_id)
    supplier_id = supplier_id.id if supplier_id.is_a?(SimplyStored::Couch)
    list_id = list_id.id if list_id.is_a?(SimplyStored::Couch)
    database.view(active_for_supplier_view(key: [supplier_id, list_id], reduce: true, include_docs: false))
  end

  # Return all currently active orders for a given section
  def self.active_for_supplier_and_section(supplier, section_id)
    supplier_id = supplier.is_a?(SimplyStored::Couch) ? supplier.id : supplier
    section_id = section_id.id if section_id.is_a?(SimplyStored::Couch)
    database.view(active_for_supplier_and_section_view(key: [supplier_id, section_id], reduce: false, include_docs: true))
  end

  def table_number
    list.table_number
  end
  alias table_nr table_number


  def placed?
    state == 'placed'
  end
  def active?
    state == 'active'
  end

  def is_being_processed!
    self.state = 'active'
    if save
      orders_in_process_count = supplier.increment_orders_in_process_count!
      orders_placed_count = supplier.decrement_orders_placed_count!
      for user_id in list.user_ids
        broadcast_user user_id, 'order_being_processed', id: id, list_id: list_id
        broadcast_user user_id, 'orders_in_process_count', count: orders_in_process_count
        broadcast_user user_id, 'orders_placed_count', count: orders_placed_count
      end
      broadcast_supplier supplier_id, 'order_being_processed', id: id, list_id: list_id
      broadcast_supplier supplier_id, 'orders_in_process_count', count: orders_in_process_count
      broadcast_supplier supplier_id, 'orders_placed_count', count: orders_placed_count
    end
  end

  def is_delivered!
    decrement_counter = placed? ? 'placed' : 'in_process'
    self.state = 'delivered'
    if save
      reduced_count = supplier.public_send "decrement_orders_#{decrement_counter}_count!"
      for user_id in list.user_ids
        broadcast_user user_id, 'order_being_delivered', id: id, list_id: list_id
        broadcast_user user_id, "orders_#{decrement_counter}_count", count: reduced_count
      end
      broadcast_supplier supplier_id, 'order_being_delivered', id: id, list_id: list_id
      broadcast_supplier supplier_id, "orders_#{decrement_counter}_count", count: reduced_count
    end
  end

  def cancel!
    original_state = state.inquiry
    self.state = 'cancelled' if placed? || active?
    if save
      broadcast_options = {id: id}
      if original_state.placed?
        reduced_count = supplier.decrement_orders_placed_count!
        broadcast_options[:supplier_orders_placed_count] = reduced_count
      elsif original_state.active?
        reduced_count = supplier.decrement_orders_in_process_count!
        broadcast_options[:supplier_orders_in_process_count] = reduced_count
      end
      list.broadcast_users 'order_cancelled', broadcast_options
      broadcast_supplier supplier_id, 'order_cancelled', broadcast_options
    end
  end

  def cancelled?
    state == 'cancelled'
  end

  #TODO fix me
  def close!

    if placed? || active?
      decrement_counter = placed? ? 'placed' : 'in_process'
      supplier.public_send "decrement_orders_#{decrement_counter}_count!"
    end
    self.state = 'closed'

    if save
      broadcast_user user.id, 'order_closed', id: id if user
      broadcast_supplier supplier_id, 'order_closed', id: id
    end
  end

  def as_json(*args)
    h = super.with_indifferent_access
    h[:id] = h[:_id]
    h[:table_number] = table_number
    h[:section_title] = list.table.section.try(:title)
    h
  end

  def with_products_as_json
    return @with_products_as_json if @with_products_as_json.present?
    product_orders.include_relation(:product)
    ho = as_json
    # products are depricated. It is a name for something it is not!!!!!
    ho[:products] = []
    ho[:product_orders] = []
    order_total = 0.0
    for product_order in product_orders
      order_total += (product_order.quantity * product_order.price).round(2)
      ho[:products] << {name: product_order.product.name, id: product_order.product_id, number: product_order.quantity, price: product_order.price}
      ho[:product_orders] << {product_name: product_order.product.name, id: product_order.id, quantity: product_order.quantity, price: product_order.price}
    end
    ho[:total_amount] = order_total.round(2)
    @with_products_as_json = ho
  end
end
