class IncomingLink < ActiveRecord::Base
  belongs_to :topic
  belongs_to :user

  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).find_by(username_lower: request["u"].downcase)
      user_id = u.id if u
    end

    if request.referer.present?
      begin
        host = URI.parse(request.referer).host
        referer = request.referer[0..999]
      rescue URI::InvalidURIError
        # bad uri, skip
      end
    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?
      # We may get a junk URI, just deal with it
      self.domain = URI.parse(self.referer).host rescue nil
      self.referer = nil unless self.domain
    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
        # TODO achieve same thing with no exception
        params = Rails.application.routes.recognize_path(parsed.path)
        if self.topic_id = params[:topic_id]
          self.post_number = params[:post_number] || 1
        end
      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

# == Schema Information
#
# Table name: incoming_links
#
#  id              :integer          not null, primary key
#  url             :string(1000)     not null
#  referer         :string(1000)
#  domain          :string(100)
#  topic_id        :integer
#  post_number     :integer
#  created_at      :datetime
#  updated_at      :datetime
#  user_id         :integer
#  ip_address      :inet
#  current_user_id :integer
#
# Indexes
#
#  incoming_index                                  (topic_id,post_number)
#  index_incoming_links_on_created_at_and_domain   (created_at,domain)
#  index_incoming_links_on_created_at_and_user_id  (created_at,user_id)
#
