class Customer < ActiveRecord::Base



  
  has_many :thing_conversations, :as => :thing
  
  has_many :conversations, :through => :thing_conversations



  has_many :domains, :through => :domain_customers
  has_many :domain_customers, :dependent => :destroy
  
  has_many :reseaux_customers
  has_many :reseauxes, :through => :reseaux_customers
  
  has_many :own_reseauxes, :class_name => "Reseaux", :foreign_key => :chef_reseau_id
  has_many :own_customers, :through => :own_reseauxes, :source => :customers
  
  
  
  

  scope :search, -> (search) {
    where('name LIKE ? OR firstname LIKE ? OR organisation LIKE ?', "%#{search}%", "%#{search}%", "%#{search}%")
  }

  # Relationships

  has_many :owned_needs, foreign_key: 'author_id', class_name: 'Need'
  has_many :wishes,  dependent: :destroy
  has_many :accepted_offers,  dependent: :destroy
  has_many :needs, -> { uniq }, through: :wishes

  has_many :customer_favs
  has_many :annonce_favs, :through => :customer_favs, :class_name => "Annonce", :source => :annonce

  has_many :annonces
  has_many :annonce_photos, :through => :annonces

  has_many :customer_newsgroups
  has_many :newsgroups, :through => :customer_newsgroups

  
  has_many :orders
  has_many :commissions
  has_many :virements

  has_many :inbox_messages, :class_name => "CustomerMessage", :foreign_key => :destinataire_id

  has_secure_password

  # Validation

  validates_presence_of :name
  validates_presence_of :firstname




  validates_presence_of :organisation

  validates_presence_of :phone

  #validates_presence_of :parent_code

  validates :capital, :numericality => true, :presence => true, :if => :step2
  validates :role_signataire, :presence => true, :if => :step2

  validates_presence_of :password, :on => :create
  validates :email, :presence => true, :uniqueness => true, :format => /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\z/i

  validates :siret, :presence => true, :if => :step2
  validates :address, :presence => true, :if => :step2
  validates :cp, :presence => true, :if => :step2
  validates :city, :presence => true, :if => :step2

  validates :need_1 , :presence => true, :if =>  :step3


  # Geocoder

  reverse_geocoded_by :latitude, :longitude
  geocoded_by :full_address

  # Callbacks

  # Get lat & lng of the customer only if address has changed
  after_validation :geocode, if: ->(customer){
    customer.address_changed? or
    customer.address2_changed? or
    customer.cp_changed?  or
    customer.city_changed?
  }

  attr_accessor :force_address, :step2, :step3

  def force_address?
    self.force_address
  end


  mount_uploader :avatar, AvatarUploader

  SOND = [["Sans importance",0], ["Peu important", 1],[ "Important", 2], ["Très important", 3]]

  acts_as_tree
  before_create do
    self.generate_mlm_token
    self.generate_token

  end
  
  
  
  before_validation do


    if !self.id
      if self.reseaux_token?
        
        if reseaux = Reseaux.find_by_token(self.reseaux_token) 
          self.reseaux_token = reseaux.token
          
        else
          errors.add(:reseaux_token, "Ce code de réseau n'est pas valide, merci de vérifier son exactitude. ") 
        end
      end
    end


    if !self.id
      if self.parent_code?

        if mlm_parent = Customer.find_parrain(self.parent_code)
          self.parent_id = mlm_parent.id
          self.parent_at_create = true
        else
          errors.add(:parent_code, "Ce code de recommandation n'est pas valide, merci de vérifier son exactitude. ")
        end
      end
    end

  end

  after_create do
    if self.reseaux_token?
      
      if reseaux = Reseaux.find_by_token(self.reseaux_token) 
        self.reseauxes << reseaux
        
      else
        
      end
    end
    
    

    newsgroups = Newsgroup.where(:default_checked => true).all


    self.newsgroups << newsgroups


  end


  

  def anonyme_nick
    "Utilisateur#{id}"
  end

  

  def max_virement
    self.commissions.sum(:amount).floor - 5.0

  end

  def send_password_reset


    begin
      self[:reset_password_token] = SecureRandom.urlsafe_base64
    end while Customer.exists?(:reset_password_token => self[:reset_password_token])

    self.reset_password_sent_at = Time.now




    self.save(:validate => false)
    CustomerMailer.password_reset(self).deliver
  end


  def self.find_parrain(token)

    token = "B458AV" if token.upcase == "B458A0"
    if token != ""
      Customer.find_by_mlm_token(token.downcase)
    else
      nil
    end
  end

  def inscription_binaire

    if self.parent and !self.binary_parent_id

      parrain = self.parent

      puts parrain.id

      if parrain.binary_preferences == 1

        self.binary_side = 1
      elsif parrain.binary_preferences == 2
        self.binary_side = 2
      else
        self.binary_side = parrain.less_leg

      end

      puts self.binary_side

      binary_filieul = find_binary_empty(parrain.id,self.binary_side )

      self.binary_parent_id = binary_filieul.id
      self.save(:validate => false)

    end
  end

  def full_address
    "#{address} #{address2} #{cp} #{city}"
  end

  def fullname
    "#{firstname.capitalize} #{name.upcase}"
  end

  def pseudo
    if self.pro
      self.organisation
    else
      self.firstname+" "+self.name[0..0].to_s+"."
    end
  end

  def pseudo_admin
    if self.pro
      self.organisation
    else
      self.firstname+" "+self.name
    end
  end

  def avatar_url
    self.avatar? ? self.avatar.square.url : "/default.png"
  end


  def self.get_tree(customer)

        [customer, get_tree(Customer.where(:binary_side => 1, :binary_parent_id => customer.id).first), get_tree(Customer.where(:binary_side => 2, :binary_parent_id => customer.id).first)] if customer

  end



  def binary_parent
    Customer.find(self.binary_parent_id) if self.binary_parent_id

  end


  def find_binary_empty(id, side)
    customer = Customer.find(id)
    if !customer.find_binary(side)
      return customer
    else
      self.find_binary_empty(customer.find_binary(side).id, side)

    end



  end

  def find_binary(side)
    Customer.where(:binary_side => side, :binary_parent_id => self.id).first
  end


  def generate_token
    begin
      self[:token] = SecureRandom.urlsafe_base64
    end while Customer.exists?(:token => self[token])
  end

  def generate_mlm_token
     self.mlm_token = loop do

    mlm_token = SecureRandom.hex(3)
      break mlm_token unless Customer.exists?(mlm_token: mlm_token)
    end
  end



  def credit_paid(cost, piece_id=nil, piece_type= nil, note="Achat option annonce" )
    if self.solde_credits(Date.today) >= cost

      expense = Expense.create(:customer_id => self.id,:piece_id => piece_id, :piece_type => piece_type, :note => note, :value => cost)
      solde_cost = cost
      credits_to_use = self.credits.between(Date.today, Date.today).order("expire_after ASC")



      credits_to_use.each do |credit|
        if solde_cost > 0

          if solde_cost <= credit.solde

            CreditExpense.create(:value => solde_cost, :credit_id => credit.id, :customer_id => self.id, :expense_id => expense.id)
            solde_cost = 0

          else

            partial_solde = credit.solde
            CreditExpense.create(:value => partial_solde, :credit_id => credit.id, :customer_id => self.id, :expense_id => expense.id)

            solde_cost = solde_cost - partial_solde



          end


        end

      end

    else
      false
    end

  end

  def free_credits(date)
    credits_valides(date) - credits_boughts(date)
  end

  def credits_valides(date)
    self.credits.between(date, date).plus.sum(:value)
  end

  def credits_boughts(date)
    self.credits.between(date, date).plus.boughts.sum(:value)
  end


  def solde_credits(date)
    s = 0

    self.credits.between(date, date).each do |credit|
      s += credit.solde

    end

    return s

  end

  def update_left_binary_points
    self.left_binary_points = self.binary_points.left.sum(:value)
    self.save
  end

  def update_right_binary_points
    self.right_binary_points = self.binary_points.right.sum(:value)
    self.save
  end

  def binary_points_side(side)
    if side == 1
      self.left_binary_points
    else
      self.right_binary_points
    end
  end

  def less_leg
    if self.left_binary_points.to_i > self.right_binary_points.to_i

      return 2
    else
      return 1

    end
  end

  def strong_leg
    if self.left_binary_points.to_i < self.right_binary_points.to_i

      return 2
    else
      return 1

    end
  end
  def self.mlm_small_percents
    [0,10,6,4,4,4,4]
  end

  def self.mlm_big_percents
    [0,12,8,6,4,4,4,3,3,3,3]
  end


  def mlm_nbr_niveaux
    if self.callif_now
      if binary_active_count > 5
        self.callif_now[6]
      else
        self.callif_now[5]
      end
    else
      0
    end
  end

  CALLIFS = [["start", 40, 10,0,mlm_small_percents, 2,4], ["bronze", 120, 20,1, mlm_small_percents,3,5], ["silver", 260,30,3, mlm_small_percents,3,6], ["gold", 550, 40,8, mlm_big_percents,4,8], ["platinium", 1200,50,20, mlm_big_percents,5,10],["access", 15, 5,0,mlm_small_percents,2,3]]

  def callif_now
    self.callif(Date.today)
  end

  def callif(date)

    self.callif_credits(self.credits_boughts(date))

  end

  def callif_credits(credits_boughts)
    if credits_boughts >= 1200
      CALLIFS[4]
    elsif credits_boughts >= 550
      CALLIFS[3]
    elsif credits_boughts >= 260
      CALLIFS[2]
    elsif credits_boughts >= 120
      CALLIFS[1]
    elsif credits_boughts >= 40
      CALLIFS[0]
    elsif credits_boughts >= 15
      CALLIFS[5]
    end
  end

  def binary_percentage
    self.callif_now[2]
  end

  def commission_binary_now(order_ref=nil)
    if self.binary_active? and 1== 2
      less_value = self.binary_points_side(self.less_leg).to_i

      if less_value > 0


        commission_value = (less_value.to_f() * (self.binary_percentage.to_f()/100).to_f())



        com_object = self.commissions.create(:order => order_ref, :commission_type_id => 2, :amount => commission_value)

        self.binary_points.create(:value => less_value*(-1), :side => less_leg, :point_type => 2, :commission_id => com_object.id)
        self.binary_points.create(:value => less_value*(-1), :side => strong_leg, :point_type => 3, :commission_id => com_object.id)


      end

    end

  end
  def binary_active_count
    self.children.where("binary_parent_id is not null").count
  end
  def binary_active?
    self.children.where("binary_parent_id is not null").count >= 2


  end

  def add_binary_child_ids(child_id)


      Customer.where(:binary_parent_id => child_id).each do |ac|
        @ids << ac.id
        add_binary_child_ids(ac.id)
      end



  end

  def binary_child_ids

    @ids = []
    child_id = self.id

    add_binary_child_ids(child_id)

    return @ids

  end

end
