class User < ApplicationRecord
  has_secure_password

  belongs_to :invited_by, class_name: "User", optional: true
  has_many :invited_users, class_name: "User", foreign_key: :invited_by_id, dependent: :nullify

  has_many :created_entries, class_name: "Entry", foreign_key: :created_by_id, dependent: :nullify
  has_many :updated_entries, class_name: "Entry", foreign_key: :updated_by_id, dependent: :nullify
  has_many :requested_entries, class_name: "Entry", foreign_key: :requested_by_id, dependent: :nullify
  has_many :submitted_suggested_meanings,
           class_name: "SuggestedMeaning",
           foreign_key: :submitted_by_id,
           dependent: :nullify
  has_many :reviewed_suggested_meanings,
           class_name: "SuggestedMeaning",
           foreign_key: :reviewed_by_id,
           dependent: :nullify
  has_many :comments, dependent: :nullify

  enum :role, %i[contributor reviewer admin]

  validates :email, presence: true, uniqueness: true
  validates :password, length: { minimum: 12 }, if: -> { password.present? }

  scope :by_role, ->(role) { where(role: role) if role.present? }
  scope :search_email, ->(q) { where("email LIKE ?", "%#{sanitize_sql_like(q)}%") if q.present? }

  # Invitation token expires after 14 days
  INVITATION_TOKEN_EXPIRY = 14.days
  # Remember me token expires after 2 weeks
  REMEMBER_TOKEN_EXPIRY = 2.weeks

  def invitation_expired?
    return false if invitation_sent_at.nil?
    invitation_sent_at < INVITATION_TOKEN_EXPIRY.ago
  end

  def invitation_pending?
    invitation_token.present? && invitation_accepted_at.nil? && !invitation_expired?
  end

  def invite_by(invitee)
    self.invited_by = invitee if invitee && invited_by.nil?
    self.invitation_token = SecureRandom.urlsafe_base64(32)
    self.invitation_sent_at = Time.current
  end

  def invite_by!(invitee = nil)
    invite_by(invitee)
    save!
  end

  def self.find_by_valid_invitation_token(token)
    where(invitation_token: token)
      .where(invitation_accepted_at: nil)
      .where("invitation_sent_at > ?", INVITATION_TOKEN_EXPIRY.ago)
      .first
  end

  def remember_me
    self.remember_token = SecureRandom.urlsafe_base64(32)
    self.remember_created_at = Time.current
    save(validate: false)
    remember_token
  end

  def forget_me
    update_columns(remember_token: nil, remember_created_at: nil)
  end

  def remember_token_expired?
    return true if remember_created_at.nil?
    remember_created_at < REMEMBER_TOKEN_EXPIRY.ago
  end

  def self.find_by_valid_remember_token(token)
    user = find_by(remember_token: token)
    return nil if user.nil? || user.remember_token_expired?
    user
  end
end
