class User < ActiveRecord::Base
  extend Devise::Models

  self.table_name = align_with_adapter(Rails.application.config.app_stammdaten_schema + '.users')
  self.sequence_name = align_with_adapter(Rails.application.config.app_stammdaten_schema + '.users_seq')

  devise :database_authenticatable, :validatable, :recoverable

  # Default devise modules are:
  # :database_authenticatable, :registerable,
  # :recoverable, :rememberable, :trackable, :validatable
  # Others available are:
  # :confirmable, :lockable, :timeoutable and :omniauthable

  attr_accessor :login

  validates :username, presence: true, uniqueness: { case_sensitive: false }
  validates :first_name, presence: true
  validates :last_name, presence: true

  has_many :saved_filters, class_name: 'Pegelfilter::SavedFilter', foreign_key: 'user_id'

  def self.find_for_database_authentication(conditions)
    conditions = conditions.dup
    login = conditions.delete(:login)
    where(conditions).where(["lower(username) = :value OR lower(email) = :value and active = 1", { value: login.downcase }]).first
  end

  def full_name
    [last_name, first_name].select { |name| !name.blank? }.join(', ')
  end

  def fluent_full_name
    [first_name, last_name].select { |name| !name.blank? }.join(' ')
  end

  def organisationseinheiten_ids
    (organisationseinheiten || '').split(',').map { |it| it.to_i }
  end
  def organisationseinheiten_string
    (organisationseinheiten || '').split(',').map { |it| Enum::Organisationseinheit.where(organisationseinheit_nr: it.to_i).first.try(:name) }.join(', ')
  end

  def salutation_or_name
    if salutation.blank?
      return fluent_full_name
    end
    salutation
  end

  def active_for_authentication?
    super && active
  end

  def sees_all_export_products?
    return false
  end

  def w_editable_stations
    bearbeitbare_messstellen_nummern('wasserstand')
  end

  def q_editable_stations
    bearbeitbare_messstellen_nummern('abfluss')
  end

  def ak_editable_stations
    bearbeitbare_messstellen_nummern('abflusskurve')
  end

  def qm_editable_stations
    bearbeitbare_messstellen_nummern('abflussmessung')
  end

  def verwaltung_editable_stations
    bearbeitbare_messstellen_nummern('verwaltung')
  end

  def generate_token
    unless self.auth_token && self.auth_token_created_at > (DateTime.now - 1.day)
      self.auth_token = Devise.friendly_token
      self.auth_token_created_at = DateTime.now
      save
    end
    self.auth_token
  end

  def rollen_keys
    (rollen || '').split(',')
  end

  def berechtigungen_keys
    (berechtigungen || '').split(',')
  end

  def lade_rollen_und_berechtigungen
    alle = {rollen_keys: [], berechtigungen_keys: []}
    alle[:rollen_keys] += rollen_keys
    alle[:berechtigungen_keys] += berechtigungen_keys
    direkte_rollen = Rollen::Rolle.where(key: rollen_keys).to_a
    direkte_rollen.each do |rolle|
      teil_rollen_und_berechtigungen = rolle.alle_rollen_und_berechtigungen
      alle[:rollen_keys] += teil_rollen_und_berechtigungen[:rollen_keys]
      alle[:berechtigungen_keys] += teil_rollen_und_berechtigungen[:berechtigungen_keys]
    end
    alle
  end
  def alle_rollen_und_berechtigungen
    BerechtigungsCache.instance.alle_rollen_und_berechtigungen(self)
  end

  def hat_berechtigung?(berechtigungs_key)
    alle_rollen_und_berechtigungen[:berechtigungen_keys].include?(berechtigungs_key)
  end

  def hat_rolle?(rollen_key)
    alle_rollen_und_berechtigungen[:rollen_keys].include?(rollen_key)
  end

  def hat_tool_zugriff?(tool_key)
    alle_rollen_und_berechtigungen[:rollen_keys].each do |rolle_key|
      if matches_tool?(rolle_key,  tool_key)
        return true
      end
    end
    false
  end

  def darf_messstelle_bearbeiten_in(tool_key, messstellen_nummer)
    bearbeitbare_messstellen_nummern(tool_key).include?(messstellen_nummer)
  end

  def bearbeitbare_messstellen_nummern(tool_key)
    messnetz_ids = []
    betreiber_ids = []
    eigentuemer_ids = []
    einzel_messstellen_nummern = []
    alle = alle_rollen_und_berechtigungen
    alle[:rollen_keys].each do |rolle_key|
      unless matches_tool?(rolle_key, tool_key) && rolle_key.end_with?('-aktion:bearbeiten')
        next
      end
      if match = rolle_key.match(/-messnetz:([\da-z]+)-/)
        messnetz_ids << match.captures[0]
        next
      end
      if match = rolle_key.match(/-betreiber:([\da-z]+)-/)
        betreiber_ids << match.captures[0]
        next
      end
      if match = rolle_key.match(/-eigentuemer:([\da-z]+)-/)
        eigentuemer_ids << match.captures[0]
        next
      end
      if match = rolle_key.match(/-pegel:([\da-z]+)-/)
        einzel_messstellen_nummern << match.captures[0]
        next
      end
    end
    lade_messstellen_nummern(messnetz_ids, eigentuemer_ids, betreiber_ids, einzel_messstellen_nummern)
  end

  def ansehbare_messstellen(tool_key)
    messnetz_ids = []
    betreiber_ids = []
    eigentuemer_ids = []
    einzel_messstellen_nummern = []
    alle = alle_rollen_und_berechtigungen
    alle[:rollen_keys].each do |rolle_key|
      unless matches_tool?(rolle_key, tool_key) && (rolle_key.end_with?('-aktion:ansehen') || rolle_key.end_with?('-aktion:bearbeiten'))
        next
      end
      if match = rolle_key.match(/-messnetz:([\da-z]+)-/)
        messnetz_ids << match.captures[0]
        next
      end
      if match = rolle_key.match(/-betreiber:([\da-z]+)-/)
        betreiber_ids << match.captures[0]
        next
      end
      if match = rolle_key.match(/-eigentuemer:([\da-z]+)-/)
        eigentuemer_ids << match.captures[0]
        next
      end
      if match = rolle_key.match(/-pegel:([\da-z]+)-/)
        einzel_messstellen_nummern << match.captures[0]
        next
      end
    end
    lade_messstellen(messnetz_ids, eigentuemer_ids, betreiber_ids, einzel_messstellen_nummern)
  end

  private

  def bearbeitbare_messstellen_nummern_alt(tabelle_rechte_betreiberscharf, tabelle_rechte_messstellenscharf)
    view = Rails.configuration.use_new_base_data ? 'mv_sd_pegeldaten' : 'v_pegeldaten'
    query_bearbeitbar_betreiberscharf   = '(select distinct(p.messtellen_nr) messtellen_nr from ' + view + ' p left outer join konfiguration k on k.messtellen_nr=p.messtellen_nr where (k.gesamtsperrung is null or k.gesamtsperrung=0) and p.gwb_nr        in (select gwb_nr        from ' + tabelle_rechte_betreiberscharf   + ' where user_id=' + id.to_s + '))'
    query_bearbeitbar_messstellenscharf = '(select distinct(p.messtellen_nr) messtellen_nr from ' + view + ' p left outer join konfiguration k on k.messtellen_nr=p.messtellen_nr where (k.gesamtsperrung is null or k.gesamtsperrung=0) and p.messtellen_nr in (select messtellen_nr from ' + tabelle_rechte_messstellenscharf + ' where user_id=' + id.to_s + '))'
    query = "#{query_bearbeitbar_betreiberscharf} union #{query_bearbeitbar_messstellenscharf} order by messtellen_nr"
    ActiveRecord::Base.connection.exec_query(query).map {|record| record['messtellen_nr']}
  end

  def matches_tool?(rolle_key, tool_key)
    rolle_key.start_with?('auto-rolle-tool:' + tool_key + '-') || (rolle_key.start_with?('auto-rolle-tool:alle-') && !von_tools_alle_ausgeschlossen?(tool_key))
  end

  def von_tools_alle_ausgeschlossen?(tool_key)
    ['verwaltung', 'stammdaten'].include?(tool_key)
  end

  MessnetzEhemaligerLandespegel = 14

  def mit_ehemaligen_landespegeln?
    hat_berechtigung?(Rollen::Berechtigung::Ehemalige_Landespegel_bearbeiten)
  end

  def lade_messstellen_nummern(messnetz_ids, eigentuemer_ids, betreiber_ids, messstellen_nummern)
    view = Rails.configuration.use_new_base_data ? 'mv_sd_pegeldaten' : 'v_pegeldaten'
    query = %{
      SELECT DISTINCT(p.messtellen_nr)
        FROM #{view} p
        LEFT OUTER JOIN konfiguration k ON k.messtellen_nr=p.messtellen_nr
        WHERE
          (k.gesamtsperrung IS NULL OR k.gesamtsperrung=0) AND
          (p.messnetz_nr<>#{MessnetzEhemaligerLandespegel} OR #{mit_ehemaligen_landespegeln? ? '0=0' : '0=1' }) AND
          (#{in_clause('p.messtellen_nr', messstellen_nummern)} OR #{in_clause('p.gwd_nr', eigentuemer_ids)} OR #{in_clause('p.gwb_nr', betreiber_ids)} OR #{in_clause('p.messnetz_nr', messnetz_ids)})
        ORDER BY messtellen_nr}
    ActiveRecord::Base.connection.exec_query(query).map {|record| record['messtellen_nr']}
  end

  def lade_messstellen(messnetz_ids, eigentuemer_ids, betreiber_ids, messstellen_nummern)
    StammdatenContext::GaugingStation.where("#{in_clause('messtellen_nr', messstellen_nummern)} OR #{in_clause('gwd_nr', eigentuemer_ids)} OR #{in_clause('gwb_nr', betreiber_ids)} OR #{in_clause('messnetz_nr', messnetz_ids)}").order(messtellen_nr: :asc)
  end

  def in_clause(spaltenname, ids)
    if ids.empty?
      return '(1=0)'
    end
    if ids.include?('alle')
      return '(1=1)'
    end
    id_list = ids.join(',')
    "(#{spaltenname} IN (#{id_list}))"
  end
end