class IncomingLink < ActiveRecord::Base
  belongs_to :topic

  validates :url, presence: true

  validate :referer_valid

  before_validation :extract_domain
  before_validation :extract_topic_and_post
  after_create :update_link_counts

  def self.add(request,current_user=nil)
    user_id, host, referer = nil

    if request['u']
      u = User.select(:id).where(username_lower: request['u'].downcase).first
      user_id = u.id if u
    end

    if request.referer.present?
      host = URI.parse(request.referer).host
      referer = request.referer[0..999]
    end

    if host != request.host && (user_id || referer)
      cid = current_user.id if current_user
      unless cid && cid == user_id
        IncomingLink.create(url: request.url,
                            referer: referer,
                            user_id: user_id,
                            current_user_id: cid,
                            ip_address: request.remote_ip)
      end
    end

  end


  # Internal: Extract the domain from link.
  def extract_domain
    if referer.present?
      self.domain = URI.parse(referer).host
    end
  end

  # Internal: If link is internal and points to topic/post, extract their IDs.
  def extract_topic_and_post
    if url.present?
      parsed = URI.parse(url)

      begin
        params = Rails.application.routes.recognize_path(parsed.path)
        self.topic_id = params[:topic_id]
        self.post_number = params[:post_number]
      rescue ActionController::RoutingError
        # If we can't route to the url, that's OK. Don't save those two fields.
      end
    end
  end

  # Internal: Update appropriate link counts.
  def update_link_counts
    if topic_id.present?
      exec_sql("UPDATE topics
                SET incoming_link_count = incoming_link_count + 1
                WHERE id = ?", topic_id)
      if post_number.present?
        exec_sql("UPDATE posts
                  SET incoming_link_count = incoming_link_count + 1
                  WHERE topic_id = ? and post_number = ?", topic_id, post_number)
      end
    end
  end

  protected

  def referer_valid
    return true unless referer
    if (referer.length < 3 || referer.length > 100) || (domain.length < 1 || domain.length > 100)
      # internal, no need to localize
      errors.add(:referer, 'referer is invalid')
      false
    else
      true
    end
  end
end
