module JamRuby
  class   InvitedUser < ActiveRecord::Base
    include HtmlSanitize
    html_sanitize strict: [:note]

    VALID_EMAIL_REGEX = /\A[\w+\-.]+@[a-z\d\-.]+\.[a-z]+\z/i

    attr_accessible :email, :sender_id, :autofriend, :note, as: :admin

    attr_accessor :accepted_twice

    self.primary_key = 'id'

    ### Who sent this invitatio?
    # either admin_sender or user_sender is not null.  If an administrator sends the invitation, then
    belongs_to :sender , :inverse_of => :invited_users, :class_name => "JamRuby::User", :foreign_key => "sender_id"
    belongs_to :receiver, :inverse_of => :receiver_users, :class_name => "JamRuby::User", :foreign_key => "receiver_id"

    # who is the invitation sent to?
    validates :email, format: {with: VALID_EMAIL_REGEX}, :if => lambda { |iu| iu.email_required? }
    validates :autofriend, :inclusion => {:in => [nil, true, false]}
    validates :invitation_code, :presence => true
    validates :note, length: {maximum: 1000}, no_profanity: true # 1000 == arbitrary.

    validate :one_facebook_invite_per_user, :if => lambda { |iu| iu.facebook_invite? }
    validate :valid_personalized_invitation
    # validate :not_accepted_twice
    validate :not_accepted_twice, :if => lambda { |iu| iu.email_required? }
    validate :spammer
    validate :can_invite?

    after_save :track_user_progression

    # ensure invitation code is always created
    before_validation(:on => :create) do
      self.invitation_code = SecureRandom.urlsafe_base64 if self.invitation_code.nil?
      self.sender_id = nil if self.sender_id.blank? # this coercion was done just to make activeadmin work
      self.receiver = User.find_by_email(self.email) unless self.email.nil?
    end

    FB_MEDIUM = 'facebook'

    def self.facebook_invite(user)
      where(:sender_id => user.id, :invite_medium => FB_MEDIUM).limit(1).first
    end

    def track_user_progression
      self.sender.update_progression_field(:first_invited_at) unless self.sender.nil?
    end

    def self.index(user)
      return InvitedUser.where(:sender_id => user).order(:updated_at)
    end

    def sender_display_name
      return sender.name
    end

    def accept!
      if self.accepted
        accepted_twice = true
      end

      self.accepted = true
    end

    def invited_by_administrator?
      sender.nil? || sender.admin # a nil sender can only be created by someone using jam-admin
    end

    def generate_signup_url
      url = "#{APP_CONFIG.external_root_url}/signup?invitation_code=#{self.invitation_code}"
      if APP_CONFIG.external_hostname == 'localhost'
        # the feed widget in facebook will not accept localhost.  external_host name should be localhost only in dev environments
        url["localhost"] = "127.0.0.1"
      end
      url
    end

    def facebook_invite?
      FB_MEDIUM == self.invite_medium
    end

    def email_required?
      !self.facebook_invite?
    end

    def has_required_email?
      self.email.present? && self.email_required?
    end

    private

    def can_invite?
      errors.add(:sender, "can not invite others") if !invited_by_administrator? && !sender.can_invite?
    end

    def valid_personalized_invitation
      errors.add(:autofriend, "must be true if sender is specified") if autofriend && sender.nil?
    end

    def not_accepted_twice
      errors.add(:accepted, "you can only accept an invitation once") if accepted_twice
    end

    # the same account should not receive emails within the same day
    def spammer
      max_invites_ever_per_sender
      max_invites_per_day_per_sender
      max_invites_to_receiver_per_day
    end

    def max_invites_ever_per_sender
      if InvitedUser.where(:sender => self.sender).count > APP_CONFIG.max_invites_ever_per_sender
        errors.add(:base, "max invites sent by this account")
      end
    end

    def max_invites_per_day_per_sender
      if InvitedUser.where(:sender => self.sender).where("created_at > ?", Time.now - 1.days).count > APP_CONFIG.max_invites_per_day_per_sender
        errors.add(:base, "maximum number of invites sent in past 24 hours")
      end
    end

    def max_invites_to_receiver_per_day
      if  InvitedUser.where(:email => self.email).where("created_at > ?", Time.now - 1.days).count > APP_CONFIG.max_invites_to_receiver_per_day - 1
        errors.add(:base, "someone has already sent to #{self.email} in past 24 hours")
      end
    end

    def one_facebook_invite_per_user
      rel = InvitedUser.where(:invite_medium => FB_MEDIUM, :sender_id => self.sender_id)
      rel = rel.where(['id != ?',self.id]) if self.id
      errors.add(:invite_medium, "one facebook invite allowed per user") if 0 < rel.count
    end
    
  end
end
