require 'aasm'

module JamRuby
  class Connection < ActiveRecord::Base

    SELECT_AT_LEAST_ONE = "Please select at least one track"
    FAN_CAN_NOT_JOIN_AS_MUSICIAN = "A fan can not join a music session as a musician"
    MUSIC_SESSION_MUST_BE_SPECIFIED = "A music session must be specified"
    INVITE_REQUIRED = "You must be invited to join this session"
    FANS_CAN_NOT_JOIN = "Fans can not join this session"

    attr_accessor :joining_session

    self.primary_key = 'id'

    belongs_to :user, :class_name => "JamRuby::User"
    belongs_to :music_session, :class_name => "JamRuby::MusicSession"
    has_many :tracks, :class_name => "JamRuby::Track", :inverse_of => :connection


    validates :as_musician, :inclusion => {:in => [true, false]}
    validate :can_join_music_session, :if => :joining_session?
    after_save :require_at_least_one_track_when_in_session, :if => :joining_session?

    include AASM
    IDLE_STATE = :idle
    CONNECT_STATE = :connected
    STALE_STATE = :stale
    EXPIRED_STATE = :expired

    aasm do
      state IDLE_STATE, :initial => true
      state CONNECT_STATE
      state STALE_STATE
      state EXPIRED_STATE

      event :connect do
        transitions :from => IDLE_STATE, :to => CONNECT_STATE
        transitions :from => STALE_STATE, :to => CONNECT_STATE
      end
      event :stale do
        transitions :from => CONNECT_STATE, :to => STALE_STATE
        transitions :from => IDLE_STATE, :to => STALE_STATE
      end
      event :expire, :after => :did_expire do
        transitions :from => CONNECT_STATE, :to => EXPIRED_STATE
        transitions :from => STALE_STATE, :to => EXPIRED_STATE
        transitions :from => IDLE_STATE, :to => EXPIRED_STATE
      end
    end

    def state_message
      case self.aasm_state.to_sym
        when CONNECT_STATE
        'Connected'
        when STALE_STATE 
        'Stale'
        else
        'Idle'
      end
    end

    def did_expire
      self.destroy
    end

    def joining_session?
      return joining_session
    end
    
    def can_join_music_session

      if music_session.nil?
        errors.add(:music_session, MUSIC_SESSION_MUST_BE_SPECIFIED)
        return false
      end

      if as_musician
        unless self.user.musician
          errors.add(:as_musician, FAN_CAN_NOT_JOIN_AS_MUSICIAN)
          return false
        end

        if music_session.musician_access
          if music_session.approval_required
            unless music_session.creator == user || music_session.invited_musicians.exists?(user)
              errors.add(:approval_required, INVITE_REQUIRED)
              return false
            end
          end
        else
          unless music_session.creator == user || music_session.invited_musicians.exists?(user)
            errors.add(:musician_access, INVITE_REQUIRED)
            return false
          end
        end
      else
        unless self.music_session.fan_access
          # it's someone joining as a fan, and the only way a fan can join is if fan_access is true
          errors.add(:fan_access, FANS_CAN_NOT_JOIN)
          return false
        end
      end

      return true
    end


    # decides if a given user can access this client with p2p messaging
    # the answer is yes if the user is in the same music session
    def access_p2p?(user)
      return self.music_session.users.exists?(user)
    end

    private
    def require_at_least_one_track_when_in_session
      if tracks.count == 0
        errors.add(:genres, SELECT_AT_LEAST_ONE)
      end
    end

  end
end
