class Supplier
  include SimplyStored::Couch
  include ActiveModel::SerializerSupport

  view :by_confirmation_token, key: :confirmation_token # devise confirmable
  devise :database_authenticatable, :recoverable, :rememberable, :trackable, :registerable, :confirmable
  property :unconfirmed_email

  property :name
  property :open, type: :boolean, default: false
  property :time_zone, default: 'UTC'
  property :night_offset, type: Fixnum, default: 0 # Minutes

  #LOCATION
  property :lat, type: Float, default: 52.08062426379751
  property :lng, type: Float, default: 4.312562942504883

  #WIFI
  property :offer_wifi
  property :wifi_ssid
  property :wifi_type
  property :wifi_password

  #REVIEWS
  property :iens_profile

  #has_many :orders, through: :lists
  has_many :products, dependent: :destroy
  has_many :product_categories, dependent: :destroy
  has_many :tables, dependent: :destroy
  has_many :lists, dependent: :destroy
  #has_many :lists, through: :tables
  has_many :orders, dependent: :destroy
  has_many :sections, dependent: :destroy
  has_many :employees

  after_create :add_section_on_create

  view :by_email, key: :email

  validates :name, presence: true
  validates :iens_profile, numericality: {allow_blank: true}
  validates :password, confirmation: true

  def location=(val)
    lat, lng = val.is_a?(Array) ? val : val.strip.split(/[ ,]+/).map(&:to_f)
    self.lat = lat
    self.lng = lng
  end

  def location
    [lat, lng].join(',')
  end

  def active_orders(options = {})
    return @active_orders if @active_orders && @active_orders_options == options
    @active_orders_options = options
    @active_orders = options[:section_id] ? Order.active_for_supplier_and_section(self, options[:section_id]) : Order.active_for_supplier(id)
    @active_orders.include_relation(list: {table: :section}, product_orders: :order)
    @active_orders
  end

  def active_lists(options = {})
    return @active_lists if @active_lists
    @active_lists = options[:section_id].present? ? List.active_for_supplier_and_section(self, options[:section_id]) : List.active_for_supplier(id)
    @active_lists.include_relations(table: :section, orders: {product_orders: :product})
    @active_lists
  end


  # Return the currently active tables for the supplier
  def active_tables(options = {})
    options[:section_id].present? ? tables.select{|t| t.section_id == options[:section_id]} : tables
  end

  def non_placed_tables
    tables.reject{|t| t.section_id.present? }
  end

  def open?
    open
  end
  def closed?
    !open?
  end

  def mark_as_open!
    self.open = true
    save
  end
  
  def mark_as_closed!
    self.open = false
    save
  end

  def serializable_hash(*)
    {
      id: id,
      name: name
    }
  end

  def as_json(*)
    serializable_hash
  end


  # Find a user by its confirmation token and try to confirm it.
  # If no user is found, returns a new user with an error.
  # If the user is already confirmed, create an error for the user
  # Options must have the confirmation_token
  #
  # Overwrite devise method for mail sending
  def self.confirm_by_token(confirmation_token)
    confirmable = find_or_initialize_with_error_by(:confirmation_token, confirmation_token)
    send_creation_mail = confirmable.errors.empty? && !confirmable.confirmed?
    confirmable.confirm! if confirmable.persisted?
    confirmable.send_creation_notifications if send_creation_mail
    confirmable
  end

  def self.reset_counters!
    # Set all known counters to zero
    Qwaiter::Couchbase.design_doc('supplier').counters(reduce: false).each{|counter| Qwaiter::Counter.set counter.key, 0}

    spec = Order.by_supplier_id_and_state(reduce: true, group_level: 2)
    reset_order_counters_with_spec spec
  end

  def reset_counters!
    spec = Order.by_supplier_id_and_state(startkey: [id], endkey: [id, {}], reduce: true, group_level: 2)
    self.class.reset_order_counters_with_spec spec
  end

  def self.reset_order_counters_with_spec(spec)
    # taken from the couch_potato source since we want a model/custom mix here (hmmmm, something that should be fixed in the couchbase version)
    results = CouchPotato::View::ViewQuery.new(
      database.couchrest_database,
      spec.design_document,
      {spec.view_name => { map: spec.map_function, reduce: spec.reduce_function} },
      ({spec.list_name => spec.list_function} unless spec.list_name.nil?),
      spec.language
    ).query_view!(spec.view_parameters)
    Array.wrap(results['rows']).each do |result|
      supplier_id, state = result['key']
      case state
      when 'placed' then Qwaiter::Counter.set "supplier_counter:#{supplier_id}:orders_placed", result['value']
      when 'active' then Qwaiter::Counter.set "supplier_counter:#{supplier_id}:orders_in_process", result['value']
      end
    end
  end


  # Send confirmation instructions by email
  def send_confirmation_instructions(*args)
    self.confirmation_token = nil if reconfirmation_required?
    @reconfirmation_required = false

    @bypass_postpone = true and generate_confirmation_token! if self.confirmation_token.blank?
    self.devise_mailer.confirmation_instructions(self, confirmation_token).deliver
  end

  def find_order(id)
    order = Order.find(id)
    raise SimplyStored::RecordNotFound unless order.supplier_id == self.id
    order
  end

  def send_creation_notifications
    SupplierMailer.creation(self).deliver
  end

  def week_starts_on_monday?
    true
  end

  # COUNTER SECTION. Can be a concern in a future
  def increment_orders_in_process_count!
    Qwaiter::Counter.incr self.class.orders_in_process_counter_key(id)
  end

  def increment_orders_placed_count!
    Qwaiter::Counter.incr self.class.orders_placed_counter_key(id)
  end

  def decrement_orders_in_process_count!
    Qwaiter::Counter.decr self.class.orders_in_process_counter_key(id)
  end

  def decrement_orders_placed_count!
    Qwaiter::Counter.decr self.class.orders_placed_counter_key(id)
  end

  def orders_in_process_count
    Qwaiter::Counter.get self.class.orders_in_process_counter_key(id)
  end

  def orders_placed_count
    Qwaiter::Counter.get self.class.orders_placed_counter_key(id)
  end

  def self.orders_in_process_counter_key(id)
    "supplier_counter:#{id}:orders_in_process"
  end

  def self.orders_placed_counter_key(id)
    "supplier_counter:#{id}:orders_placed"
  end

  def active_order_count
    orders_in_process_count + orders_placed_count
  end

  private

  def add_section_on_create
    @section = Section.create supplier: self, title: I18n.t('supplier.section.first_section_title')
  end


end
