class User < ActiveRecord::Base
  include ActiveModel::AttributeAssignment
  include ActiveModel::ForbiddenAttributesProtection
  belongs_to :team
  has_many :sortings, -> { order(:priority) }
  has_and_belongs_to_many :federal_states, -> { distinct }, join_table: 'federal_states_users'

  require 'digest/md5'

  attr_accessor :password, :password_confirmation #keine Datenbankspalte, aber zum Erstellen von hashed_password nötig

  validates_length_of :loginname, :within => 3..40
  validates_uniqueness_of :loginname
  validates_presence_of :loginname, :team_id

  #proc is used as this point because the method/data_field hashed_password is out of scope for the validation methods
  validates_presence_of :password, :if => Proc.new { |u| u.hashed_password.nil?  }
  validates_length_of :password, :within => 5..40, :unless => Proc.new { |u| u.password.nil?  }
  validates_presence_of :password_confirmation, :unless => Proc.new { |u| u.password.nil?  }
  validates_confirmation_of :password, :unless => Proc.new { |u| u.password.nil?  }

  def self.authenticate(loginname, pass)
    user = where(loginname: loginname).take
    return nil if user.nil?
    return user if User.encrypt(pass, user.salt)==user.hashed_password rescue nil
    nil
  end

  def update_lastlogin
    self.update_attribute(:lastlogin, DateTime.current)
  end

  def has_perm?(perm_id)
    return self.team.permissions.exists?(perm_id)
  end

  def is_admin?
    return self.admin_level >= 20
  end

  def is_team_admin?
    return self.admin_level >= 10
  end

  def is_global_data_admin?
    return self.team.permissions_teams.any? { |pt| pt.permission.permission == 'administer' && pt.global.to_i == 1 }
    #return self.team.permissions.any? { |perm| perm.permission == 'administer' && perm.global.to_i == 1 }
  end

  def can_read?
    return true if can_read_global?
    return self.team.permissions.any? { |perm| perm.permission == 'read' } && !self.federal_states.empty?
  end

  def can_read_global?
    return self.team.permissions_teams.any? { |pt| pt.permission.permission == 'read' && pt.global.to_i == 1 }
    #return self.team.permissions.any? { |perm| perm.permission == 'read' && perm.global.to_i == 1 }
  end

  def get_states_for_read
    return Array.new(17) {|i| i + 1} if self.can_read_global?
    #return self.federal_states.collect { |fs| fs.id } if self.can_read?
    return self.federal_states.map(&:id) if self.can_read?
    return ['-1']
  end

  def can_write?
    return true if can_write_global?
    return self.team.permissions.any? { |perm| perm.permission == 'write' } && !self.federal_states.empty?
  end

  def can_write_on?(row)
    return self.get_states_for_write.include?(row['fed_state_for_perm'])
  end

  def can_write_global?
    return self.team.permissions_teams.any? { |pt| pt.permission.permission == 'write' && pt.global.to_i == 1 }
    #return self.team.permissions.any? { |perm| perm.permission == 'write' && perm.global.to_i == 1 }
  end
  
  def can_export_any?
    return self.team.permissions.any? { |perm| perm.permission == 'export' }
  end
  
  def can_export_global?
    return self.team.permissions_teams.any? { |pt| pt.permission.permission == 'export' && pt.global.to_i == 1 }
    #return self.team.permissions.any? { |perm| perm.permission == 'export' && perm.global.to_i == 1 }
  end

  def can_import_any?
    return self.team.permissions.any? { |perm| perm.permission == 'import' }
  end
  
  def can_import?(fs_id)
    #if self.team.permissions.any?{ |perm| perm.permission == 'import' && perm.global.to_i == 1 }
    if self.team.permissions_teams.any? { |pt| pt.permission.permission == 'import' && pt.global.to_i == 1 }
      # puts "Global Import Permission detected"
      return true
    end
    if self.team.permissions.any? { |perm| perm.permission == 'import' }
      # puts "Local Import Permission detected"
      if self.federal_states.any? {|fs| fs['id'] == fs_id }
        # puts "State detected"
        return true
      end
    else
      puts "No import permission!"
      return false
    end
    # puts "No import permission for federal_state #{fs_id}. Only got the following states:"
    # self.federal_states.each {|fs| puts "#{fs['id']}, #{fs['federal_key']}, #{fs['name']}" }
    return false
  end

  def get_states_for_write
    return Array.new(17) {|i| (i + 1)} if self.can_write_global?
    #return self.federal_states.collect { |fs| fs.id } if self.can_write?
    return self.federal_states.map(&:id) if self.can_write?
    return ['-1']
  end

  def includes_states?(states)
    for state in states do
      return false unless self.federal_states.include?(state)
    end
    return true
  end

  def is_master_to?(user)
    return user.team_id == self.team_id && user.admin_level == 0 && self.includes_states?(user.federal_states)
  end

  def password=(pass)
    @password=pass
    self.salt = User.random_string(10) unless pass.nil?
    self.hashed_password = User.encrypt(@password, self.salt) unless pass.nil?
  end

  def get_default_federal_state
    relations = ActiveRecord::Base.execute_sql("SELECT federal_state_id FROM model.federal_states_users WHERE user_id = ?", self.id)
    if relations.count == 1
      return relations.first['federal_state_id']
    else
      return ""
    end
  end

  protected

  def self.encrypt(pass, salt)
    Digest::MD5.hexdigest(pass+salt)
  end

  def self.random_string(len)
    #generat a random password consisting of strings and digits
    chars = ("a".."z").to_a + ("A".."Z").to_a + ("0".."9").to_a
    newpass = ""
    1.upto(len) { |i| newpass << chars[rand(chars.size-1)] }
    return newpass
  end

end
