class User < ApplicationRecord
  # Flag used to identify if the user was found or created from find_or_create
  attr_accessor :was_created
  attr_accessor :team_slug

  JSON_ATTRIBUTES = %w[id name initials username email finished_tour].freeze
  AUTHENTICATION_KEYS = %i[email].freeze
  ROLES = %w[manager developer guest].freeze

  before_validation :set_random_password_if_blank

  after_save :set_team

  before_destroy :remove_story_association

  has_many :enrollments
  has_many :teams, through: :enrollments
  has_many :memberships, dependent: :destroy
  has_many :projects, -> { distinct }, through: :memberships do
    def not_archived
      where(archived_at: nil)
    end
  end

  validates :name, :username, :initials, presence: true
  validates :username, uniqueness: true

  extend Enumerize
  extend ActiveModel::Naming
  enumerize :role, in: ROLES

  include Gravtastic
  gravtastic default: 'identicon'

  # FIXME: - DRY up, repeated in Story model
  # Include default devise modules. Others available are:
  # :token_authenticatable, :confirmable, :lockable and :timeoutable
  devise :authy_authenticatable, :database_authenticatable, :registerable, :confirmable,
         :recoverable, :rememberable, :trackable, :validatable,
         authentication_keys: AUTHENTICATION_KEYS,
         strip_whitespace_keys: AUTHENTICATION_KEYS,
         confirmation_keys: AUTHENTICATION_KEYS,
         reset_password_keys: AUTHENTICATION_KEYS
  # unlock_keys: AUTHENTICATION_KEYS

  def password_required?
    # Password is required if it is being set, but not for new records
    if !persisted?
      false
    else
      !password.nil? || !password_confirmation.nil?
    end
  end

  def guest?
    role == 'guest'
  end

  def to_s
    "#{name} (#{initials}) <#{email}>"
  end

  # Sets :reset_password_token encrypted by Devise
  # returns the raw token to pass into mailer
  def set_reset_password_token
    raw, enc = Devise.token_generator.generate(self.class, :reset_password_token)
    self.reset_password_token   = enc
    self.reset_password_sent_at = Time.current.utc
    save(validate: false)
    raw
  end

  def tour_steps
    WelcomeTour::STEPS.to_json
  end

  def as_json(options = {})
    super(**options, only: JSON_ATTRIBUTES, methods: %i[tour_steps guest?])
  end

  def self.find_first_by_auth_conditions(warden_conditions)
    if warden_conditions[:reset_password_token]
      find_by(reset_password_token: warden_conditions[:reset_password_token])
    elsif warden_conditions[:confirmation_token]
      find_by(confirmation_token: warden_conditions[:confirmation_token])
    else
      find_by(email: warden_conditions[:email])
    end
  end

  def requested?(story)
    story.requested_by_id == id
  end

  def owns?(story)
    story.owned_by_id == id
  end

  def team_from_project(project)
    user_team_ids = teams.pluck(:id)
    project.teams.find_by(id: user_team_ids)
  end

  def set_random_password_if_blank
    if new_record? && password.blank? && password_confirmation.blank?
      self.password = self.password_confirmation = Digest::SHA1.hexdigest(
        "--#{Time.current}--#{email}--"
      )[0, 8]
    end
  end

  def set_team
    if team_slug
      team = Team.not_archived.find_by(slug: team_slug)
      enrollments.create(team: team) if team
    end
  end

  def remove_story_association
    Story.where(requested_by_id: id).update_all(requested_by_id: nil, requested_by_name: nil)
    Story.where(owned_by_id: id).update_all(owned_by_id: nil, owned_by_name: nil)
    Membership.where(user_id: id).delete_all
  end

  def early_v2_user?
    ENV['EARLY_V2_EMAIL'] && email.include?(ENV['EARLY_V2_EMAIL'])
  end
end
