module JamRuby
  class JamTrack < ActiveRecord::Base
    include JamRuby::S3ManagerMixin

    TIME_SIGNATURES = %w{4/4 3/4 2/4 6/8 5/8'}
    STATUS = %w{Staging Production Retired}
    RECORDING_TYPE = %w{Cover Original}
    PRO = %w{ASCAP BMI SESAC}
    SALES_REGION = ['United States', 'Worldwide']

    PRODUCT_TYPE = 'JamTrack'

    @@log = Logging.logger[JamTrack]

    attr_accessor   :uploading_preview
    attr_accessible :name, :description, :bpm, :time_signature, :status, :recording_type,
                  :original_artist, :songwriter, :publisher, :licensor, :licensor_id, :pro, :genre, :genre_id, :sales_region, :price,
                  :reproduction_royalty, :public_performance_royalty, :reproduction_royalty_amount,
                  :licensor_royalty_amount, :pro_royalty_amount, :plan_code, :initial_play_silence, :jam_track_tracks_attributes,
                  :jam_track_tap_ins_attributes, :version, :jmep_json, :jmep_text, :pro_ascap, :pro_bmi, :pro_sesac, :duration,  as: :admin

    validates :name,            presence: true, uniqueness: true, length: {maximum: 200}
    validates :plan_code,       presence: true, uniqueness: true, length: {maximum: 50  }
    validates :description,     length: {maximum: 1000}
    validates :time_signature,  inclusion: {in: [nil] + [''] + TIME_SIGNATURES} # the empty string is needed because of activeadmin
    validates :status,          inclusion: {in: [nil] + STATUS}
    validates :recording_type,  inclusion: {in: [nil] + RECORDING_TYPE}
    validates :original_artist, length: {maximum: 200}
    validates :songwriter,      length: {maximum: 1000}
    validates :publisher,       length: {maximum: 1000}
    validates :sales_region,    inclusion: {in: [nil] + SALES_REGION}
    validates_format_of :price, with: /^\d+\.*\d{0,2}$/
    validates :version,         presence: true
    validates :pro_ascap,       inclusion: {in: [true, false]}
    validates :pro_bmi,         inclusion: {in: [true, false]}
    validates :pro_sesac,       inclusion: {in: [true, false]}
    validates :public_performance_royalty,            inclusion: {in: [nil, true, false]}
    validates :reproduction_royalty,                  inclusion: {in: [nil, true, false]}
    validates :public_performance_royalty,            inclusion: {in: [nil, true, false]}
    validates :duration,        numericality: {only_integer: true}, :allow_nil => true

    validates_format_of :reproduction_royalty_amount, with: /^\d+\.*\d{0,3}$/
    validates_format_of :licensor_royalty_amount,     with: /^\d+\.*\d{0,3}$/

    belongs_to :genre, class_name: "JamRuby::Genre"
    belongs_to :licensor , class_name: 'JamRuby::JamTrackLicensor', foreign_key: 'licensor_id'

    has_many :jam_track_tracks, :class_name => "JamRuby::JamTrackTrack", order: 'track_type ASC, position ASC, part ASC, instrument_id ASC'
    has_many :jam_track_tap_ins, :class_name => "JamRuby::JamTrackTapIn", order: 'offset_time ASC'

    has_many :jam_track_rights, :class_name => "JamRuby::JamTrackRight"  #, inverse_of: 'jam_track', :foreign_key => "jam_track_id"  # '

    has_many :owners, :through => :jam_track_rights, :class_name => "JamRuby::User", :source => :user

    has_many    :playing_sessions, :class_name => "JamRuby::ActiveMusicSession"

    has_many :recordings, :class_name => "JamRuby::Recording"

    # VRFS-2916 jam_tracks.id is varchar: REMOVE
    # has_many :plays, :class_name => "JamRuby::PlayablePlay", :foreign_key => :jam_track_id, :dependent => :destroy
    # VRFS-2916 jam_tracks.id is varchar: ADD
     has_many :plays, :class_name => "JamRuby::PlayablePlay", :as => :playable, :dependent => :destroy

    # when we know what JamTrack this refund is related to, these are associated
    belongs_to :recurly_transactions, class_name: 'JamRuby::RecurlyTransactionWebHook'

    accepts_nested_attributes_for :jam_track_tracks, allow_destroy: true
    accepts_nested_attributes_for :jam_track_tap_ins, allow_destroy: true

    def duplicate_positions?
      counter = {}
      jam_track_tracks.each do |track|
        count = counter[track.position]
        if count.nil?
          count = 0
        end
        counter[track.position]  = count + 1
      end

      duplicate = false
      counter.each do|position, count|
        if count > 1
          duplicate = true
          break
        end
      end
      duplicate
    end

    def missing_previews?
      missing_preview = false
      self.jam_track_tracks.each do |track|
        unless track.has_preview?
          missing_preview = true
          break
        end
      end
      missing_preview
    end

    def onboard_warnings
      warnings = []
      warnings << 'POSITIONS' if duplicate_positions?
      warnings << 'PREVIEWS'if missing_previews?
      warnings << 'DURATION' if duration.nil?
      warnings << 'JMEP' if jmep_json.blank?
      warnings.join(',')
    end

    def band_jam_track_count
      JamTrack.where(original_artist: original_artist).count
    end

    class << self 
      # @return array[artist_name(string)]
      def all_artists 
        JamTrack.select("original_artist").
                 group("original_artist").
                 order('original_artist').
                 collect{|jam_track|jam_track.original_artist}
      end

      # @return array[JamTrack] for given artist_name
      def tracks_for_artist(artist_name)
        JamTrack.where("original_artist=?", artist_name).all
      end

      def index(options, user)
        if options[:page]
          page = options[:page].to_i
          per_page = options[:per_page].to_i

          if per_page == 0
            # try and see if limit was specified
            limit = options[:limit]
            limit ||= 20
            limit = limit.to_i
          else
            limit = per_page
          end
 
          start = (page -1 )* per_page
          limit = per_page
        else
          limit = options[:limit]
          limit ||= 20
          limit = limit.to_i

          start = options[:start].presence
          start = start.to_i || 0

          page = 1 + start/limit
          per_page = limit
        end


        query = JamTrack.joins(:jam_track_tracks)
                    .paginate(page: page, per_page: per_page)

        if options[:show_purchased_only]
          query = query.joins(:jam_track_rights)
          query = query.where("jam_track_rights.user_id = ?", user.id)
        end

        if options[:artist].present?
          query = query.where("original_artist=?", options[:artist])
        end

        if options[:id].present?
          query = query.where("jam_tracks.id=?", options[:id])
        end

        if options[:group_artist]
          query = query.select("original_artist, array_agg(jam_tracks.id) AS id, MIN(name) AS name, MIN(description) AS description, MIN(recording_type) AS recording_type, MIN(original_artist) AS original_artist, MIN(songwriter) AS songwriter, MIN(publisher) AS publisher, MIN(sales_region) AS sales_region, MIN(price) AS price, MIN(version) AS version, MIN(genre_id) AS genre_id")
          query = query.group("original_artist")
          query = query.order('jam_tracks.original_artist')
        else
          query = query.group("jam_tracks.id")
          query = query.order('jam_tracks.original_artist, jam_tracks.name')
        end

        query = query.where("jam_tracks.status = ?", 'Production') unless user.admin
        query = query.where("jam_tracks.genre_id = '#{options[:genre]}'") unless options[:genre].blank?
        query = query.where("jam_track_tracks.instrument_id = '#{options[:instrument]}' and jam_track_tracks.track_type != 'Master'") unless options[:instrument].blank?
        query = query.where("jam_tracks.sales_region = '#{options[:availability]}'") unless options[:availability].blank?


        if query.length == 0
          [query, nil]
        elsif query.length < limit
          [query, nil]
        else
          [query, start + limit]
        end
      end


      # provides artist names and how many jamtracks are available for each
      def artist_index(options, user)
        if options[:page]
          page = options[:page].to_i
          per_page = options[:per_page].to_i

          if per_page == 0
            # try and see if limit was specified
            limit = options[:limit]
            limit ||= 100
            limit = limit.to_i
          else
            limit = per_page
          end

          start = (page -1 )* per_page
          limit = per_page
        else
          limit = options[:limit]
          limit ||= 100
          limit = limit.to_i

          start = options[:start].presence
          start = start.to_i || 0

          page = 1 + start/limit
          per_page = limit
        end


        query = JamTrack.paginate(page: page, per_page: per_page)
        query = query.select("original_artist, count(original_artist) AS song_count")
        query = query.group("original_artist")
        query = query.order('jam_tracks.original_artist')

        query = query.where("jam_tracks.status = ?", 'Production') unless user.admin
        query = query.where("jam_tracks.genre_id = '#{options[:genre]}'") unless options[:genre].blank?
        query = query.where("jam_track_tracks.instrument_id = '#{options[:instrument]}'") unless options[:instrument].blank?
        query = query.where("jam_tracks.sales_region = '#{options[:availability]}'") unless options[:availability].blank?


        if query.length == 0
          [query, nil]
        elsif query.length < limit
          [query, nil]
        else
          [query, start + limit]
        end
      end
    end


    def master_track
      JamTrackTrack.where(jam_track_id: self.id).where(track_type: 'Master').first
    end

    def stem_tracks
      JamTrackTrack.where(jam_track_id: self.id).where(track_type: 'Track')
    end

    def can_download?(user)
      owners.include?(user)
    end

    def right_for_user(user)
      jam_track_rights.where("user_id=?", user).first      
    end

    def short_plan_code
      prefix = 'jamtrack-'
      plan_code[prefix.length..-1]
    end

  end
end
