module JamRuby
  class MusicSessionUserHistory < ActiveRecord::Base

    self.table_name = "music_sessions_user_history"

    self.primary_key = 'id'

    attr_accessible :max_concurrent_connections, :session_removed_at, :rating

    belongs_to(:user, 
               :class_name => "JamRuby::User", 
               :foreign_key => "user_id", 
               :inverse_of => :music_session_user_histories)

    validates_inclusion_of :rating, :in => 0..2, :allow_nil => true
    after_save :track_user_progression

    def music_session_history
      @msh ||= JamRuby::MusicSessionHistory.find_by_music_session_id(self.music_session_id)
    end

    def perf_data
      @perfdata ||= JamRuby::MusicSessionPerfData.find_by_client_id(self.client_id)
    end

    def self.save(music_session_id, user_id, client_id)
      session_user_history = MusicSessionUserHistory.new()
      session_user_history.music_session_id = music_session_id
      session_user_history.user_id = user_id
      session_user_history.client_id = client_id
      session_user_history.save
    end
    
    def user_email
      self.user ? self.user.email : '<user deleted>'
    end

    def duration_minutes
      end_time = self.session_removed_at || Time.now
      (end_time - self.created_at) / 60.0
    end

    def self.removed_music_session(user_id, session_id)
      hist = self
        .where(:user_id => user_id)
        .where(:music_session_id => session_id)
        .limit(1)
        .first
      hist.end_history if hist
    end

    def end_history
      self.session_removed_at = Time.now if self.session_removed_at.nil?

      self.update_attributes(:session_removed_at => self.session_removed_at, :max_concurrent_connections => determine_max_concurrent)
    end

    # figures out what the peak amount of other clients the user saw while playing at any given time.
    # we use the database to get all other connections that occurred while their this user was connected,
    # and then sort through them using custom logic to increase/decrease the count as people come and go
    def determine_max_concurrent
      overlapping_connections = MusicSessionUserHistory.where("music_session_id = ? AND
                                    ((created_at >= ? AND (session_removed_at is NULL OR session_removed_at <= ?)) OR
                                    (created_at <= ? AND (session_removed_at is NULL OR session_removed_at >= ?)))",
                                                              self.music_session_id, self.created_at, self.session_removed_at, self.created_at, self.created_at).select('id, created_at, session_removed_at').order(:created_at)
      in_out_times = []
      overlapping_connections.each do |connection|
        in_out_times.push([connection.created_at.nil? ? Time.at(0) : connection.created_at, true])
        in_out_times.push([connection.session_removed_at.nil? ? Time.new(3000) : connection.session_removed_at, false]) #helpful to get rid of nulls for sorting
      end

      count_concurrent(in_out_times)
    end

    def count_concurrent(in_out_times)
      in_out_times.sort!

      max_concurrent = 0
      concurrent = 0

      in_out_times.each do |hit|
        if hit[1]
          concurrent = concurrent + 1
        else
          concurrent = concurrent - 1
        end

        if concurrent > max_concurrent
          max_concurrent = concurrent
        end
      end
      max_concurrent
    end

    def perf_uri
      self.perf_data.try(:uri)
    end

    def track_user_progression
      if self.rating == 0
        user.update_progression_field(:first_good_music_session_at)
      end
    end
  end
end
