class User
  include Mongoid::Document
  include Mongoid::Timestamps
  include GlobalID::Identification
  include UserGithubHelper
  include Mongoid::Slug
  ROLES = {admin: 'Admin'}

  # Include default devise modules. Others available are:
  # :confirmable, :lockable, :timeoutable and :omniauthable, :registerable
  devise :database_authenticatable,
    :rememberable, :trackable, :validatable, :omniauthable

  ## Database authenticatable
  field :email,              type: String, default: ""
  field :encrypted_password, type: String, default: ""

  ## Rememberable
  field :remember_created_at, type: Time

  ## Trackable
  field :sign_in_count,      type: Integer, default: 0
  field :current_sign_in_at, type: Time
  field :last_sign_in_at,    type: Time
  field :current_sign_in_ip, type: String
  field :last_sign_in_ip,    type: String
  field :blocked,            type: Boolean, default: false

  field :github_handle,      type: String
  field :twitter_handle,     type: String
  field :active,             type: Boolean, default: true
  field :is_judge,           type: Boolean, default: false
  field :is_sponsorer,       type: Boolean, default: false
  field :name,               type: String
  field :provider,           type: String
  field :uid,                type: String
  field :avatar_url,         type: String
  field :points,             type: Integer, default: 0
  field :level,              type: Integer, default: 1
  field :auto_created,       type: Boolean, default: false
  field :notify_monthly_progress,    type: Boolean, default: true
  field :notify_monthly_points,    type: Boolean, default: true

  field :activities_count,   type: Integer, default: 0
  field :commits_count,      type: Integer, default: 0
  field :celebrity,          type: Boolean, default: false

  # Github profile info
  field :followers,          type: Integer, default: 0
  field :public_repos,       type: Integer, default: 0
  field :github_user_since,  type: Date
  field :repos_star_count,   type: Integer, default: 0
  field :auth_token,         type: String

  # Background sync
  field :last_repo_sync_at,  type: Time
  field :last_gh_data_sync_at, type: Time

  # User account deletion
  field :deleted_at, type: Time

  # for accepting terms and conditions
  field :terms_and_conditions, type: Boolean, default: false

  # for language wise badges
  field :badges, type: Hash, default: {}

  has_many :commits, dependent: :destroy
  has_many :transactions, dependent: :destroy
  has_many :comments, dependent: :destroy
  has_many :redeem_requests, dependent: :destroy
  has_and_belongs_to_many :repositories, class_name: 'Repository', inverse_of: 'users'
  has_and_belongs_to_many :roles, inverse_of: nil

  slug  :github_handle

  index(uid: 1)
  index(github_handle: 1)
  index(auto_created: 1)

  scope :contestants, -> { where(auto_created: false) }
  scope :blocked,   -> { where(blocked: true) }
  scope :allowed,   -> { where(blocked: false) }
  scope :judges, -> { where(is_judge: true) }

  validates :email, :github_handle, :name, :uid, presence: true
  validates :uid, uniqueness: true
  validates :twitter_handle, presence: true, format: { with: /\A@\w{1,15}\z/, message: "invalid Twitter handle"}, allow_nil: true

  before_validation :append_twitter_prefix

  def self.from_omniauth(auth)
    user = where(provider: auth.provider, uid: auth.uid).first_or_create do |user|
      user.password = Devise.friendly_token[0, 20]
    end

    user.set({
      email: auth.info.email,
      name: auth.info.name,
      avatar_url: auth.info.image,
      github_handle: auth.extra.raw_info.login,
      followers: auth.extra.raw_info.followers,
      public_repos: auth.extra.raw_info.public_repos,
      auto_created: false,
      github_user_since: auth.extra.raw_info.created_at,
      deleted_at: nil,
      active: true,
      auth_token: User.encrypter.encrypt_and_sign(auth.credentials.token)
    })

    user.save
    user
  end

  def create_transaction(attrs = {})
    transaction = self.transactions.create(attrs)
    return false if transaction.errors.any?
  end

  def is_admin?
    roles.where(name: ROLES[:admin]).any?
  end

  def repo_names
    judges_repositories.map(&:name).join(",")
  end

  def repo_syncing?
    last_repo_sync_at.present? && (Time.now - last_repo_sync_at) < 3600
  end

  def gh_data_syncing?
    last_gh_data_sync_at.present? && (Time.now - last_gh_data_sync_at) < 3600
  end

  def self.encrypter
    @_encrypter ||= ActiveSupport::MessageEncryptor.new(Base64.decode64(ENV['ENC_KEY'])[0..31])
  end

  def redeemable_points
    transactions.redeemable.sum(:points)
  end

  def self.search(q)
    User.where(github_handle: /^#{q}/i).limit(8).pluck(:github_handle, :id, :avatar_url)
  end

  def able_to_redeem?
    (github_user_since <= Date.today - 6.months) && (created_at <= Date.today - 3.months)
  end

  def deleted?
    self.deleted_at.present? and !active
  end

  def append_twitter_prefix
    if self.twitter_handle.present?
      self.twitter_handle.strip!
      # Regex to match whether twitter handle provided by user contains @ sign at its
      # begining or not
      if !/^@/.match(self.twitter_handle)
        self.twitter_handle = '@' + self.twitter_handle
      end
    end
  end
end
