class User < ApplicationRecord
  include Watchable
  # Account statuses
  STATUS_ANONYMOUS  = 0
  STATUS_ACTIVE     = 1
  STATUS_REGISTERED = 2
  STATUS_LOCKED     = 3

  # tpi tpm权限控制
  EDU_ADMIN = 1       # 超级管理员
  EDU_BUSINESS = 2    # 运营人员
  EDU_SHIXUN_MANAGER = 3 # 实训管理员
  EDU_SHIXUN_MEMBER = 4  # 实训成员
  EDU_CERTIFICATION_TEACHER = 5 # 平台认证的老师
  EDU_GAME_MANAGER = 6     # TPI的创建者
  EDU_TEACHER = 7 # 平台老师,但是未认证
  EDU_NORMAL = 8  # 普通用户

  VALID_EMAIL_REGEX = /^[a-zA-Z0-9]+([.\-_\\]*[a-zA-Z0-9])*@([a-z0-9]+[-a-z0-9]*[a-z0-9]+.){1,63}[a-z0-9]+$/i
  VALID_PHONE_REGEX = /^1\d{10}$/

  LOGIN_LENGTH_LIMIT = 30
  MAIL_LENGTH_LMIT = 60

  MIX_PASSWORD_LIMIT = 8

  has_one :user_extension, dependent: :destroy
  accepts_nested_attributes_for :user_extension, update_only: true

  has_many :memos, foreign_key: 'author_id'
  has_many :shixun_members, :dependent => :destroy
  has_many :shixuns, :through => :shixun_members
  has_many :myshixuns, :dependent => :destroy
  has_many :study_shixuns, through: :myshixuns, source: :shixun   # 已学习的实训
  has_many :course_messages
  has_many :courses, dependent: :destroy

  #试卷
  has_many :exercise_banks, :dependent => :destroy
  has_many :exercise_users, :dependent => :destroy
  has_many :exercise_answers, :dependent => :destroy  #针对每个题目学生的答案
  has_many :exercise_shixun_answers, :dependent => :destroy  #针对每个实训题目学生的答案
  has_many :exercise_answer_comments, :dependent => :destroy
  has_many :exercises, :dependent => :destroy  #创建的试卷

  has_many :homework_banks, dependent: :destroy

  has_many :graduation_works, dependent: :destroy

  # 关注
  has_many :relationships, foreign_key: "follower_id", dependent: :destroy
  has_many :followed_users, through: :relationships, source: :followed
  # 粉丝
  has_many :reverse_relationships, foreign_key: "followed_id",
                                   class_name: "Relationship",
                                   dependent: :destroy
  has_many :followers, through: :reverse_relationships, source: :follower
  has_many :students_for_courses, foreign_key: :student_id, dependent: :destroy
  has_one :onclick_time, :dependent => :destroy

  # 新版私信
  has_many :private_messages, :dependent => :destroy
  has_many :tidings, :dependent => :destroy

  has_many :games, :dependent => :destroy
  has_many :subjects, :through => :subject_members
  has_many :subject_members, :dependent => :destroy
  has_many :grades, :dependent => :destroy
  has_many :experiences, :dependent => :destroy
  has_many :student_works, :dependent => :destroy
  has_many :student_works_scores
  has_many :student_works_evaluation_distributions

  # 毕业设计
  has_many :graduation_topics, :dependent => :destroy
  has_many :student_graduation_topics, :dependent => :destroy

  # 题库
  has_many :question_banks, :dependent => :destroy
  # 毕设任务题库
  has_many :gtask_banks, dependent: :destroy
  has_many :gtopic_banks, dependent: :destroy

  #问卷
  has_many :course_members, :dependent => :destroy
  has_many :poll_votes, :dependent => :destroy
  has_many :poll_users, :dependent => :destroy

  has_many :messages,foreign_key: 'author_id',:dependent => :destroy

  has_many :journals_for_messages, :as => :jour, :dependent => :destroy
  has_many :teacher_course_groups, :dependent => :destroy

  has_many :attachments,foreign_key: :author_id, :dependent => :destroy

  # 工程认证
  has_many :ec_school_users,:dependent => :destroy
  has_many :schools, :through => :ec_school_users

  has_many :ec_major_school_users, :dependent => :destroy
  has_many :ec_major_schools, :through => :ec_major_school_users

  has_many :ec_course_users

  has_many :department_members, dependent: :destroy #部门管理员

  # 课堂
  has_many :student_course_members, -> { course_students }, class_name: 'CourseMember'
  has_many :as_student_courses, through: :student_course_members, source: :course
  has_many :manage_course_members, -> { teachers_and_admin }, class_name: 'CourseMember'
  has_many :manage_courses, through: :manage_course_members, source: :course

  # 关注
  has_many :be_watchers, foreign_key: :user_id, dependent: :destroy # 我的关注
  has_many :be_watcher_users, through: :be_watchers, dependent: :destroy # 我关注的用户

  # 认证
  has_many :apply_user_authentication
  has_one :process_real_name_apply, -> { processing.real_name_auth.order(created_at: :desc) }, class_name: 'ApplyUserAuthentication'
  has_one :process_professional_apply, -> { processing.professional_auth.order(created_at: :desc) }, class_name: 'ApplyUserAuthentication'
  has_many :apply_actions, dependent: :destroy
  has_many :trail_auth_apply_actions, -> { where(container_type: 'TrialAuthorization') }, class_name: 'ApplyAction'

  has_many :attendances

  # Groups and active users
  scope :active, lambda { where(status: STATUS_ACTIVE) }

  attr_accessor :password, :password_confirmation

  before_save :update_hashed_password

  #
  # validations
  #
  validates_presence_of :login, :if => Proc.new { |user| !user.is_a?(AnonymousUser) }, case_sensitive: false
  validates_uniqueness_of :login, :if => Proc.new { |user| user.login_changed? && user.login.present? }, case_sensitive: false
  validates_uniqueness_of :mail, :if => Proc.new { |user| user.mail_changed? && user.mail.present? }, case_sensitive: false
  validates_uniqueness_of :phone, :if => Proc.new { |user| user.phone_changed? && user.phone.present? }, case_sensitive: false
  validates_length_of :login, maximum: LOGIN_LENGTH_LIMIT
  validates_length_of :mail, maximum: MAIL_LENGTH_LMIT
  # validates_format_of :mail, with: VALID_EMAIL_REGEX, multiline: true
  # validates_format_of :phone, with: VALID_PHONE_REGEX, multiline: true
  validate :validate_password_length

  # validates :nickname, presence: true, length: { maximum: 10 }
  # validates :lastname, presence: true

  # 删除自动登录的token,一旦退出下次会提示需要登录
  def delete_autologin_token(value)
    Token.where(:user_id => id, :action => 'autologin', :value => value).delete_all
  end

  def delete_session_token(value)
    Token.where(:user_id => id, :action => 'session', :value => value).delete_all
  end


  # 学号
  def student_id
    self.user_extension.try(:student_id)
  end

  # 关注总数
  def following?(other_user)
    relationships.find_by(followed_id: other_user)
  end

  # 关注
  def follow!(other_user)
    relationships.create!(followed_id: other_user)
  end

  # 取消关注
  def unfollow!(other_user)
    relationships.find_by(followed_id: other_user.id).destroy
  end

  # 判断当前用户是否为老师
  def is_teacher?
    self.user_extension.teacher?
  end

  # 平台认证的老师
  def is_certification_teacher
    self.user_extension.teacher? && self.professional_certification
  end

  def certification_teacher?
    professional_certification? && user_extension.teacher?
  end

  # 判断用户的身份
  def identity
    ue = self.user_extension
    unless ue.blank?
      if ue.teacher?
        ue.technical_title ? ue.technical_title : "老师"
      elsif ue.student?
        "学生"
      else
        ue.technical_title ? ue.technical_title : "专业人士"
      end
    end
  end

  # 判断当前用户是否通过职业认证
  def pro_certification?
    professional_certification
  end

  # 用户的学校名称
  def school_name
    user_extension&.school&.name || ''
  end

  def school_id
    user_extension&.school_id
  end

  # 课堂的老师(创建者、老师、助教)
  def teacher_of_course?(course)
    course.course_members.exists?(user_id: id, role: [1,2,3], is_active: 1) || admin?
  end

  # 课堂的老师(创建者、老师、助教),不用考虑当前身份
  def teacher_of_course_non_active?(course)
    course.course_members.exists?(user_id: id, role: [1,2,3]) || admin?
  end

  # 是否是教师,课堂管理员或者超级管理员
  def teacher_or_admin?(course)
    course.course_members.exists?(user_id: id, role: [1,2], is_active: 1) || admin?
  end

  # 课堂的创建者(考虑到多重身份的用户)
  def creator_of_course?(course)
    course.course_members.exists?(user_id: id, role: 1, is_active: 1) || admin?
  end

  # 课堂的学生
  def student_of_course?(course)
    course.course_members.exists?(user_id: id, role: %i[STUDENT])
  end

  # 课堂成员
  def member_of_course?(course)
    course.course_members.exists?(user_id: id)
  end

  # 实训路径管理员:创建者或admin
  def creator_of_subject?(subject)
    subject.user_id == id || admin?
  end

  # 实训路径:合作者、admin
  def manager_of_subject?(subject)
    subject.subject_members.exists?(user_id: id, role: [1,2]) || admin?
  end

  # 实训管理员:实训合作者、admin
  def manager_of_shixun?(shixun)
     shixun.shixun_members.exists?(role: [1,2], user_id: id) || admin?
  end

  # 实训管理员
  def creator_of_shixun?(shixun)
    id == shixun.user_id
  end

  # 实训的合作者
  def member_of_shixun?(shixun)
    #self.shixun_members.where(:role => 2, :shixun_id => shixun.id).present?
    shixun.shixun_members.exists?(role: 2, user_id: id)
  end

  # TPI的创建者
  def creator_of_game?(game)
    id == game.user_id
  end

  # 用户账号状态
  def active?
    status == STATUS_ACTIVE
  end

  def registered?
    status == STATUS_REGISTERED
  end

  def locked?
    status == STATUS_LOCKED
  end

  def activate
    self.status = STATUS_ACTIVE
  end

  def register
    self.status = STATUS_REGISTERED
  end

  def lock
    self.status = STATUS_LOCKED
  end

  def activate!
    update_attribute(:status, STATUS_ACTIVE)
  end

  def register!
    update_attribute(:status, STATUS_REGISTERED)
  end

  def lock!
    update_attribute(:status, STATUS_LOCKED)
  end

  # 课程用户身份
  def course_identity(course)
    if !logged?
      Course::Anonymous
    elsif admin?
      Course::ADMIN
    elsif business?
      Course::BUSINESS
    else
      role = course.course_members.find_by(user_id: id, is_active: 1)&.role
      case role
      when nil                   then Course::NORMAL
      when 'CREATOR'             then Course::CREATOR
      when 'PROFESSOR'           then Course::PROFESSOR
      when 'STUDENT'             then Course::STUDENT
      when 'ASSISTANT_PROFESSOR' then Course::ASSISTANT_PROFESSOR
      end
    end
  end

  # 实训用户身份
  def shixun_identity(shixun)
    @identity =
        if admin?
          User::EDU_ADMIN
        elsif business?
          User::EDU_BUSINESS
        elsif creator_of_shixun?(shixun)
          User::EDU_SHIXUN_MANAGER
        elsif member_of_shixun?(shixun)
          User::EDU_SHIXUN_MEMBER
        elsif is_certification_teacher
          User::EDU_CERTIFICATION_TEACHER
        elsif is_teacher?
          User::EDU_TEACHER
        else
          User::EDU_NORMAL
        end
    return @identity
  end

  # tpi的用户身份
  def game_identity(game)
    shixun = game.myshixun.shixun
    @identity =
        if admin?
          User::EDU_ADMIN
        elsif creator_of_shixun?(shixun)
          User::EDU_SHIXUN_MANAGER
        elsif member_of_shixun?(shixun)
          User::EDU_SHIXUN_MEMBER
        elsif is_certification_teacher
          User::EDU_CERTIFICATION_TEACHER
        elsif creator_of_game?(game)
          User::EDU_GAME_MANAGER
        elsif is_teacher?
          User::EDU_TEACHER
        else
          User::EDU_NORMAL
        end
    return @identity
  end

  # 我的实训
  def my_shixuns
    shixun_ids = shixun_members.pluck(:shixun_id) + myshixuns.pluck(:shixun_id)
    Shixun.where(:id => shixun_ids).visible
  end

  # 用户是否有权限查看实训
  def shixun_permission(shixun)
    # 性能优化:先处理不需要权限的实训(已发布并且没有单位权限限制的实训)
    return true if manager_of_shixun?(shixun) # 实训管理员
    return false if shixun.status != 2 || shixun.hidden # 隐藏或者未发布的实训:false
    return true if shixun.use_scope == 0 # 对所有学校公开
    return true if shixun.use_scope == 1 && shixun.shixun_schools.exists?(school_id: school_id) # 对部分高校公开
    return false
  end

  # 用户在平台名称的显示方式
  def full_name
    return '游客' unless logged?

    name = show_realname? ? lastname + firstname : nickname
    name.blank? ? (nickname.blank? ? login : nickname) : name
  end

  # 用户的真实姓名(不考虑用户是否隐藏了真实姓名,课堂模块都用真实姓名)
  def real_name
    return '游客' unless logged?

    name = lastname + firstname
    name.blank? ? (nickname.blank? ? login : nickname) : name
    name.gsub(/\s+/, '').strip    #6.11 -hs
  end

  # 用户是否选题毕设课题
  def selected_topic?(topic)
    student_graduation_topics.where(graduation_topic_id: topic.id).last.try(:status)
  end

  def click_time
    click_time = OnclickTime.find_by(user_id: id) || OnclickTime.create(user_id: id, onclick_time: created_on)
    click_time.onclick_time
  end

  def manager_of_memo?(memo)
    id == memo.author_id || admin?
  end

  # 是否是项目管理者
  def manager_of_project?(project)
    project.project_members.where(user_id: id).count > 0
  end

  def logged?
    true
  end

  def active?
    status == STATUS_ACTIVE
  end

  def locked?
    status == STATUS_LOCKED
  end

  def phone_binded?
    phone.present?
  end

  def self.current=(user)
    Thread.current[:current_user] = user
  end

  def self.current
    Thread.current[:current_user] ||= User.anonymous
  end

  def self.anonymous
    anonymous_user = AnonymousUser.unscoped.take
    if anonymous_user.nil?
      anonymous_user = AnonymousUser.unscoped.create(lastname: 'Anonymous', firstname: '', login: '',
                                                     mail: '358551897@qq.com', phone: '13333333333', status: 0)
      raise "Unable to create the anonymous user: error_info:#{anonymous_user.errors.messages}" if anonymous_user.new_record?
    end
    anonymous_user
  end

  # Returns the user who matches the given autologin +key+ or nil
  def self.try_to_autologin(key)
    user = Token.find_active_user('autologin', key)
    user.update(last_login_on: Time.now) if user
    user
  end

  def self.hash_password(clear_password)
    Digest::SHA1.hexdigest(clear_password || "")
  end

  def check_password?(clear_password)
    # Preventing Timing Attack
    ActiveSupport::SecurityUtils.secure_compare(
      User.hash_password("#{salt}#{User.hash_password clear_password}"),
      hashed_password
    )
  end

  # 登录,返回用户名与密码匹配的用户
  def self.try_to_login(login, password)
    login = login.to_s.strip
    password = password.to_s

    # Make sure no one can sign in with an empty login or password
    return nil if login.empty? || password.empty?
    if (login =~ VALID_EMAIL_REGEX)
      user = find_by_mail(login)
    elsif (login =~ VALID_PHONE_REGEX)
      user = find_by_phone(login)
    else
      user = find_by_login(login)
    end

    if user
      # user is already in local database
      raise("账号已被注销,请联系管理员") if user.locked?
      raise("密码错误") unless user.check_password?(password)
    else
      raise("账号未注册")
    end

    user
  rescue => text
    raise text
  end

  def show_real_name
    name = lastname + firstname
    if name.blank?
      nickname.blank? ? login : nickname
    else
      name
    end
  end

  def update_hashed_password
    if password
      salt_password(password)
    end
  end

  def salt_password(clear_password)
    self.salt = User.generate_salt
    self.hashed_password = User.hash_password("#{salt}#{User.hash_password clear_password}")
  end

  def self.generate_salt
    Educoder::Utils.random_hex(16)
  end

  protected
  def validate_password_length
    # 管理员的初始密码是5位
    if password.present? && password.size < MIX_PASSWORD_LIMIT && !User.current.admin?
      raise("密码长度不能低于#{MIX_PASSWORD_LIMIT}位")
    end
  end
end


class AnonymousUser < User
  validate :validate_anonymous_uniqueness, :on => :create

  def validate_anonymous_uniqueness
    # There should be only one AnonymousUser in the database
    errors.add :base, 'An anonymous user already exists.' if AnonymousUser.exists?
  end

  def available_custom_fields
    []
  end

  # Overrides a few properties
  def logged?; false end
  def admin; false end
  def name(*args); I18n.t(:label_user_anonymous) end
  # def mail=(*args); nil end
  # def mail; nil end
  def time_zone; nil end
  def rss_key; nil end


  def membership(*args)
    nil
  end

  def member_of?(*args)
    false
  end

  # Anonymous user can not be destroyed
  def destroy
    false
  end

  protected

  def instantiate_email_address
  end

end